X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fuisupport%2Fbufferviewfilter.cpp;h=780d0bf6ec6cb6e3014f9fb56850bef2c019d8ff;hp=c829267a7bc9e822097dfdeae4e47b02395dae72;hb=52209badc8e769e50aa3019b63689dda0e79e9d0;hpb=df48c9a36377de3c9e9deeaf539e1446ef7bd49b diff --git a/src/uisupport/bufferviewfilter.cpp b/src/uisupport/bufferviewfilter.cpp index c829267a..780d0bf6 100644 --- a/src/uisupport/bufferviewfilter.cpp +++ b/src/uisupport/bufferviewfilter.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2015 by the Quassel Project * + * Copyright (C) 2005-2019 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -21,8 +21,8 @@ #include "bufferviewfilter.h" #include -#include #include +#include #include "bufferinfo.h" #include "buffermodel.h" @@ -32,51 +32,42 @@ #include "graphicalui.h" #include "networkmodel.h" #include "uistyle.h" - -class CheckRemovalEvent : public QEvent -{ -public: - CheckRemovalEvent(const QModelIndex &source_index) : QEvent(QEvent::User), index(source_index) {}; - QPersistentModelIndex index; -}; - +#include "util.h" /***************************************** -* The Filter for the Tree View -*****************************************/ -BufferViewFilter::BufferViewFilter(QAbstractItemModel *model, BufferViewConfig *config) - : QSortFilterProxyModel(model), - _config(0), - _sortOrder(Qt::AscendingOrder), - _showServerQueries(false), - _editMode(false), - _enableEditMode(tr("Show / Hide Chats"), this) + * The Filter for the Tree View + *****************************************/ +BufferViewFilter::BufferViewFilter(QAbstractItemModel* model, BufferViewConfig* config) + : QSortFilterProxyModel(model) + , _config(nullptr) + , _sortOrder(Qt::AscendingOrder) + , _showServerQueries(false) + , _editMode(false) + , _enableEditMode(tr("Show / Hide Chats"), this) { setConfig(config); setSourceModel(model); setDynamicSortFilter(true); - - connect(this, SIGNAL(_dataChanged(const QModelIndex &, const QModelIndex &)), - this, SLOT(_q_sourceDataChanged(QModelIndex, QModelIndex))); + // Sort case-insensitively (primarily for network names; channels/nicks handled elsewhere) + setSortCaseSensitivity(Qt::CaseInsensitive); _enableEditMode.setCheckable(true); _enableEditMode.setChecked(_editMode); - connect(&_enableEditMode, SIGNAL(toggled(bool)), this, SLOT(enableEditMode(bool))); + connect(&_enableEditMode, &QAction::toggled, this, &BufferViewFilter::enableEditMode); BufferSettings defaultSettings; - defaultSettings.notify("ServerNoticesTarget", this, SLOT(showServerQueriesChanged())); + defaultSettings.notify("ServerNoticesTarget", this, &BufferViewFilter::showServerQueriesChanged); showServerQueriesChanged(); } - -void BufferViewFilter::setConfig(BufferViewConfig *config) +void BufferViewFilter::setConfig(BufferViewConfig* config) { if (_config == config) return; if (_config) { - disconnect(_config, 0, this, 0); + disconnect(_config, nullptr, this, nullptr); } _config = config; @@ -93,32 +84,19 @@ void BufferViewFilter::setConfig(BufferViewConfig *config) else { // we use a queued connection here since manipulating the connection list of a sending object // doesn't seem to be such a good idea while executing a connected slots. - connect(config, SIGNAL(initDone()), this, SLOT(configInitialized()), Qt::QueuedConnection); + connect(config, &SyncableObject::initDone, this, &BufferViewFilter::configInitialized, Qt::QueuedConnection); invalidate(); } } - void BufferViewFilter::configInitialized() { if (!config()) return; -// connect(config(), SIGNAL(bufferViewNameSet(const QString &)), this, SLOT(invalidate())); - connect(config(), SIGNAL(configChanged()), this, SLOT(invalidate())); -// connect(config(), SIGNAL(networkIdSet(const NetworkId &)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(addNewBuffersAutomaticallySet(bool)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(sortAlphabeticallySet(bool)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(hideInactiveBuffersSet(bool)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(allowedBufferTypesSet(int)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(minimumActivitySet(int)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(bufferListSet()), this, SLOT(invalidate())); -// connect(config(), SIGNAL(bufferAdded(const BufferId &, int)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(bufferMoved(const BufferId &, int)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(bufferRemoved(const BufferId &)), this, SLOT(invalidate())); -// connect(config(), SIGNAL(bufferPermanentlyRemoved(const BufferId &)), this, SLOT(invalidate())); - - disconnect(config(), SIGNAL(initDone()), this, SLOT(configInitialized())); + connect(config(), &BufferViewConfig::configChanged, this, &QSortFilterProxyModel::invalidate); + + disconnect(config(), &SyncableObject::initDone, this, &BufferViewFilter::configInitialized); setObjectName(config()->bufferViewName()); @@ -126,7 +104,6 @@ void BufferViewFilter::configInitialized() emit configChanged(); } - void BufferViewFilter::showServerQueriesChanged() { BufferSettings bufferSettings; @@ -138,15 +115,21 @@ void BufferViewFilter::showServerQueriesChanged() } } - -QList BufferViewFilter::actions(const QModelIndex &index) +QList BufferViewFilter::actions(const QModelIndex& index) { Q_UNUSED(index) - QList actionList; + QList actionList; actionList << &_enableEditMode; return actionList; } +void BufferViewFilter::setFilterString(const QString string) +{ + beginResetModel(); + _filterString = string; + endResetModel(); + enableEditMode(!string.isEmpty()); +} void BufferViewFilter::enableEditMode(bool enable) { @@ -159,7 +142,7 @@ void BufferViewFilter::enableEditMode(bool enable) return; if (enable == false) { - addBuffers(QList::fromSet(_toAdd)); + addBuffers(_toAdd.values()); QSet::const_iterator iter; for (iter = _toTempRemove.constBegin(); iter != _toTempRemove.constEnd(); ++iter) { if (config()->temporarilyRemovedBuffers().contains(*iter)) @@ -179,35 +162,33 @@ void BufferViewFilter::enableEditMode(bool enable) invalidate(); } - -Qt::ItemFlags BufferViewFilter::flags(const QModelIndex &index) const +Qt::ItemFlags BufferViewFilter::flags(const QModelIndex& index) const { QModelIndex source_index = mapToSource(index); Qt::ItemFlags flags = sourceModel()->flags(source_index); if (config()) { - NetworkModel::ItemType itemType = (NetworkModel::ItemType)sourceModel()->data(source_index, NetworkModel::ItemTypeRole).toInt(); BufferInfo::Type bufferType = (BufferInfo::Type)sourceModel()->data(source_index, NetworkModel::BufferTypeRole).toInt(); - if (source_index == QModelIndex() || itemType == NetworkModel::NetworkItemType) { - flags |= Qt::ItemIsDropEnabled; - } - else if (_editMode) { - flags |= Qt::ItemIsUserCheckable | Qt::ItemIsTristate; - } - // prohibit dragging of most items. and most drop places - // only query to query is allowed for merging - if (bufferType != BufferInfo::QueryBuffer) { - ClientBufferViewConfig *clientConf = qobject_cast(config()); - if (clientConf && clientConf->isLocked()) { - flags &= ~(Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled); + // We need Status Buffers to be a drop target, to allow for rearranging buffers. + // The Status Buffer "owns" the space between Channel/Query buffers in the tree. + // This DOES mean that it looks like you can merge a buffer into the Status buffer, but that is restricted in BufferView::dropEvent(). + if (bufferType == BufferInfo::StatusBuffer) { + // But only if the layout isn't locked! + auto* clientConf = qobject_cast(config()); + if (clientConf && !clientConf->isLocked()) { + flags |= Qt::ItemIsDropEnabled; } } + + // If we're in Edit Mode, everything except Status Buffers should be hideable. + if (_editMode && bufferType != BufferInfo::StatusBuffer) { + flags |= Qt::ItemIsUserCheckable | Qt::ItemIsTristate; + } } return flags; } - -bool BufferViewFilter::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) +bool BufferViewFilter::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) { if (!config() || !NetworkModel::mimeContainsBufferList(data)) return QSortFilterProxyModel::dropMimeData(data, action, row, column, parent); @@ -217,7 +198,7 @@ bool BufferViewFilter::dropMimeData(const QMimeData *data, Qt::DropAction action if (sourceModel()->data(source_parent, NetworkModel::ItemTypeRole) == NetworkModel::NetworkItemType) droppedNetworkId = sourceModel()->data(source_parent, NetworkModel::NetworkIdRole).value(); - QList > bufferList = NetworkModel::mimeDataToBufferList(data); + QList> bufferList = NetworkModel::mimeDataToBufferList(data); BufferId bufferId; NetworkId networkId; int pos; @@ -245,7 +226,7 @@ bool BufferViewFilter::dropMimeData(const QMimeData *data, Qt::DropAction action if (config()->bufferList().contains(bufferId) && !config()->sortAlphabetically()) { if (config()->bufferList().indexOf(bufferId) < pos) pos--; - ClientBufferViewConfig *clientConf = qobject_cast(config()); + auto* clientConf = qobject_cast(config()); if (!clientConf || !clientConf->isLocked()) config()->requestMoveBuffer(bufferId, pos); } @@ -260,15 +241,13 @@ bool BufferViewFilter::dropMimeData(const QMimeData *data, Qt::DropAction action return true; } - void BufferViewFilter::sort(int column, Qt::SortOrder order) { _sortOrder = order; QSortFilterProxyModel::sort(column, order); } - -void BufferViewFilter::addBuffer(const BufferId &bufferId) const +void BufferViewFilter::addBuffer(const BufferId& bufferId) const { if (!config() || config()->bufferList().contains(bufferId)) return; @@ -289,14 +268,13 @@ void BufferViewFilter::addBuffer(const BufferId &bufferId) const config()->requestAddBuffer(bufferId, pos); } - -void BufferViewFilter::addBuffers(const QList &bufferIds) const +void BufferViewFilter::addBuffers(const QList& bufferIds) const { if (!config()) return; QList bufferList = config()->bufferList(); - foreach(BufferId bufferId, bufferIds) { + foreach (BufferId bufferId, bufferIds) { if (bufferList.contains(bufferId)) continue; @@ -318,8 +296,7 @@ void BufferViewFilter::addBuffers(const QList &bufferIds) const } } - -bool BufferViewFilter::filterAcceptBuffer(const QModelIndex &source_bufferIndex) const +bool BufferViewFilter::filterAcceptBuffer(const QModelIndex& source_bufferIndex) const { // no config -> "all buffers" -> accept everything if (!config()) @@ -332,17 +309,19 @@ bool BufferViewFilter::filterAcceptBuffer(const QModelIndex &source_bufferIndex) if (!config()->bufferList().contains(bufferId) && !_editMode) { // add the buffer if... - if (config()->isInitialized() - && !config()->removedBuffers().contains(bufferId) // it hasn't been manually removed and either - && ((config()->addNewBuffersAutomatically() && !config()->temporarilyRemovedBuffers().contains(bufferId)) // is totally unknown to us (a new buffer)... - || (config()->temporarilyRemovedBuffers().contains(bufferId) && activityLevel > BufferInfo::OtherActivity))) { // or was just temporarily hidden and has a new message waiting for us. + if (config()->isInitialized() && !config()->removedBuffers().contains(bufferId) // it hasn't been manually removed and either + && ((config()->addNewBuffersAutomatically() + && !config()->temporarilyRemovedBuffers().contains(bufferId)) // is totally unknown to us (a new buffer)... + || (config()->temporarilyRemovedBuffers().contains(bufferId) + && activityLevel > BufferInfo::OtherActivity))) { // or was just temporarily hidden and has a new message waiting for us. addBuffer(bufferId); } // note: adding the buffer to the valid list does not temper with the following filters ("show only channels" and stuff) return false; } - if (config()->networkId().isValid() && config()->networkId() != sourceModel()->data(source_bufferIndex, NetworkModel::NetworkIdRole).value()) + if (config()->networkId().isValid() + && config()->networkId() != sourceModel()->data(source_bufferIndex, NetworkModel::NetworkIdRole).value()) return false; int allowedBufferTypes = config()->allowedBufferTypes(); @@ -352,16 +331,29 @@ bool BufferViewFilter::filterAcceptBuffer(const QModelIndex &source_bufferIndex) if (!(allowedBufferTypes & bufferType)) return false; - if (bufferType & BufferInfo::QueryBuffer && !_showServerQueries && sourceModel()->data(source_bufferIndex, Qt::DisplayRole).toString().contains('.')) { + if (bufferType & BufferInfo::QueryBuffer && !_showServerQueries + && sourceModel()->data(source_bufferIndex, Qt::DisplayRole).toString().contains('.')) { return false; } + if (!_filterString.isEmpty()) { + const BufferInfo info = qvariant_cast(Client::bufferModel()->data(source_bufferIndex, NetworkModel::BufferInfoRole)); + QString name = info.bufferName(); + if (name.contains(_filterString, Qt::CaseInsensitive)) { + return true; + } + else { + return false; + } + } + // the following dynamic filters may not trigger if the buffer is currently selected. QModelIndex currentIndex = Client::bufferModel()->standardSelectionModel()->currentIndex(); if (bufferId == Client::bufferModel()->data(currentIndex, NetworkModel::BufferIdRole).value()) return true; - if (config()->hideInactiveBuffers() && !sourceModel()->data(source_bufferIndex, NetworkModel::ItemActiveRole).toBool() && activityLevel <= BufferInfo::OtherActivity) + if (config()->hideInactiveBuffers() && !sourceModel()->data(source_bufferIndex, NetworkModel::ItemActiveRole).toBool() + && activityLevel <= BufferInfo::OtherActivity) return false; if (config()->minimumActivity() > activityLevel) @@ -370,8 +362,7 @@ bool BufferViewFilter::filterAcceptBuffer(const QModelIndex &source_bufferIndex) return true; } - -bool BufferViewFilter::filterAcceptNetwork(const QModelIndex &source_index) const +bool BufferViewFilter::filterAcceptNetwork(const QModelIndex& source_index) const { if (!config()) return true; @@ -388,8 +379,7 @@ bool BufferViewFilter::filterAcceptNetwork(const QModelIndex &source_index) cons } } - -bool BufferViewFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +bool BufferViewFilter::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { QModelIndex child = sourceModel()->index(source_row, 0, source_parent); @@ -409,8 +399,7 @@ bool BufferViewFilter::filterAcceptsRow(int source_row, const QModelIndex &sourc } } - -bool BufferViewFilter::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const +bool BufferViewFilter::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const { int leftItemType = sourceModel()->data(source_left, NetworkModel::ItemTypeRole).toInt(); int rightItemType = sourceModel()->data(source_right, NetworkModel::ItemTypeRole).toInt(); @@ -425,11 +414,32 @@ bool BufferViewFilter::lessThan(const QModelIndex &source_left, const QModelInde } } - -bool BufferViewFilter::bufferLessThan(const QModelIndex &source_left, const QModelIndex &source_right) const +bool BufferViewFilter::bufferLessThan(const QModelIndex& source_left, const QModelIndex& source_right) const { BufferId leftBufferId = sourceModel()->data(source_left, NetworkModel::BufferIdRole).value(); BufferId rightBufferId = sourceModel()->data(source_right, NetworkModel::BufferIdRole).value(); + // If filtering, prioritize relevant items first + if (!_filterString.isEmpty()) { + // Get names of the buffers + QString leftBufferName = sourceModel()->data(source_left, NetworkModel::BufferInfoRole).value().bufferName(); + QString rightBufferName = sourceModel()->data(source_right, NetworkModel::BufferInfoRole).value().bufferName(); + // Check if there's any differences across types, most important first + if ((QString::compare(leftBufferName, _filterString, Qt::CaseInsensitive) == 0) + != (QString::compare(rightBufferName, _filterString, Qt::CaseInsensitive) == 0)) { + // One of these buffers is an exact match with the filter string, while the other isn't + // Prioritize whichever one is the exact match + // (If left buffer is exact, return true to set it as less than right) + return (QString::compare(leftBufferName, _filterString, Qt::CaseInsensitive) == 0); + } + else if (leftBufferName.startsWith(_filterString, Qt::CaseInsensitive) + != rightBufferName.startsWith(_filterString, Qt::CaseInsensitive)) { + // One of these buffers starts with the filter string, while the other doesn't + // Prioritize whichever one starts with the filter string + // (If left buffer starts with, return true to set it as less than right) + return leftBufferName.startsWith(_filterString, Qt::CaseInsensitive); + } + // Otherwise, do the normal sorting (sorting happens within each priority bracket) + } if (config()) { int leftPos = config()->bufferList().indexOf(leftBufferId); int rightPos = config()->bufferList().indexOf(rightBufferId); @@ -443,8 +453,7 @@ bool BufferViewFilter::bufferLessThan(const QModelIndex &source_left, const QMod return bufferIdLessThan(leftBufferId, rightBufferId); } - -bool BufferViewFilter::networkLessThan(const QModelIndex &source_left, const QModelIndex &source_right) const +bool BufferViewFilter::networkLessThan(const QModelIndex& source_left, const QModelIndex& source_right) const { // NetworkId leftNetworkId = sourceModel()->data(source_left, NetworkModel::NetworkIdRole).value(); // NetworkId rightNetworkId = sourceModel()->data(source_right, NetworkModel::NetworkIdRole).value(); @@ -452,8 +461,7 @@ bool BufferViewFilter::networkLessThan(const QModelIndex &source_left, const QMo return QSortFilterProxyModel::lessThan(source_left, source_right); } - -QVariant BufferViewFilter::data(const QModelIndex &index, int role) const +QVariant BufferViewFilter::data(const QModelIndex& index, int role) const { switch (role) { case Qt::FontRole: @@ -470,8 +478,7 @@ QVariant BufferViewFilter::data(const QModelIndex &index, int role) const } } - -QVariant BufferViewFilter::checkedState(const QModelIndex &index) const +QVariant BufferViewFilter::checkedState(const QModelIndex& index) const { if (!_editMode || !config()) return QVariant(); @@ -499,8 +506,7 @@ QVariant BufferViewFilter::checkedState(const QModelIndex &index) const return Qt::Unchecked; } - -bool BufferViewFilter::setData(const QModelIndex &index, const QVariant &value, int role) +bool BufferViewFilter::setData(const QModelIndex& index, const QVariant& value, int role) { switch (role) { case Qt::CheckStateRole: @@ -510,8 +516,7 @@ bool BufferViewFilter::setData(const QModelIndex &index, const QVariant &value, } } - -bool BufferViewFilter::setCheckedState(const QModelIndex &index, Qt::CheckState state) +bool BufferViewFilter::setCheckedState(const QModelIndex& index, Qt::CheckState state) { QModelIndex source_index = mapToSource(index); BufferId bufferId = sourceModel()->data(source_index, NetworkModel::BufferIdRole).value(); @@ -541,36 +546,7 @@ bool BufferViewFilter::setCheckedState(const QModelIndex &index, Qt::CheckState return true; } - -void BufferViewFilter::checkPreviousCurrentForRemoval(const QModelIndex ¤t, const QModelIndex &previous) -{ - Q_UNUSED(current); - if (previous.isValid()) - QCoreApplication::postEvent(this, new CheckRemovalEvent(previous)); -} - - -void BufferViewFilter::customEvent(QEvent *event) -{ - if (event->type() != QEvent::User) - return; - - CheckRemovalEvent *removalEvent = static_cast(event); - checkItemForRemoval(removalEvent->index); - - event->accept(); -} - - -void BufferViewFilter::checkItemsForRemoval(const QModelIndex &topLeft, const QModelIndex &bottomRight) -{ - QModelIndex source_topLeft = mapToSource(topLeft); - QModelIndex source_bottomRight = mapToSource(bottomRight); - emit _dataChanged(source_topLeft, source_bottomRight); -} - - -bool BufferViewFilter::bufferIdLessThan(const BufferId &left, const BufferId &right) +bool BufferViewFilter::bufferIdLessThan(const BufferId& left, const BufferId& right) { Q_CHECK_PTR(Client::networkModel()); if (!Client::networkModel()) @@ -585,5 +561,8 @@ bool BufferViewFilter::bufferIdLessThan(const BufferId &left, const BufferId &ri if (leftType != rightType) return leftType < rightType; else - return QString::compare(Client::networkModel()->data(leftIndex, Qt::DisplayRole).toString(), Client::networkModel()->data(rightIndex, Qt::DisplayRole).toString(), Qt::CaseInsensitive) < 0; + return QString::compare(Client::networkModel()->data(leftIndex, Qt::DisplayRole).toString(), + Client::networkModel()->data(rightIndex, Qt::DisplayRole).toString(), + Qt::CaseInsensitive) + < 0; }