/***************************************************************************
- * Copyright (C) 2005-2015 by the Quassel Project *
+ * Copyright (C) 2005-2018 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#include "networkmodel.h"
#include "uistyle.h"
-class CheckRemovalEvent : public QEvent
-{
-public:
- CheckRemovalEvent(const QModelIndex &source_index) : QEvent(QEvent::User), index(source_index) {};
- QPersistentModelIndex index;
-};
-
/*****************************************
* The Filter for the Tree View
*****************************************/
BufferViewFilter::BufferViewFilter(QAbstractItemModel *model, BufferViewConfig *config)
: QSortFilterProxyModel(model),
- _config(0),
+ _config(nullptr),
_sortOrder(Qt::AscendingOrder),
_showServerQueries(false),
_editMode(false),
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()));
return;
if (_config) {
- disconnect(_config, 0, this, 0);
+ disconnect(_config, nullptr, this, nullptr);
}
_config = 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();
}
}
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());
return actionList;
}
+void BufferViewFilter::setFilterString(const QString string)
+{
+ beginResetModel();
+ _filterString = string;
+ endResetModel();
+ enableEditMode(!string.isEmpty());
+}
+
void BufferViewFilter::enableEditMode(bool enable)
{
if (enable == false) {
addBuffers(QList<BufferId>::fromSet(_toAdd));
QSet<BufferId>::const_iterator iter;
- for (iter = _toTempRemove.constBegin(); iter != _toTempRemove.constEnd(); iter++) {
+ for (iter = _toTempRemove.constBegin(); iter != _toTempRemove.constEnd(); ++iter) {
if (config()->temporarilyRemovedBuffers().contains(*iter))
continue;
config()->requestRemoveBuffer(*iter);
}
- for (iter = _toRemove.constBegin(); iter != _toRemove.constEnd(); iter++) {
+ for (iter = _toRemove.constBegin(); iter != _toRemove.constEnd(); ++iter) {
if (config()->removedBuffers().contains(*iter))
continue;
config()->requestRemoveBufferPermanently(*iter);
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<ClientBufferViewConfig *>(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<ClientBufferViewConfig *>(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;
}
if (config()->bufferList().contains(bufferId) && !config()->sortAlphabetically()) {
if (config()->bufferList().indexOf(bufferId) < pos)
pos--;
- ClientBufferViewConfig *clientConf = qobject_cast<ClientBufferViewConfig *>(config());
+ auto *clientConf = qobject_cast<ClientBufferViewConfig *>(config());
if (!clientConf || !clientConf->isLocked())
config()->requestMoveBuffer(bufferId, pos);
}
return false;
}
+ if (!_filterString.isEmpty()) {
+ const BufferInfo info = qvariant_cast<BufferInfo>(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<BufferId>())
{
BufferId leftBufferId = sourceModel()->data(source_left, NetworkModel::BufferIdRole).value<BufferId>();
BufferId rightBufferId = sourceModel()->data(source_right, NetworkModel::BufferIdRole).value<BufferId>();
+ // If filtering, prioritize relevant items first
+ if (!_filterString.isEmpty()) {
+ // Get names of the buffers
+ QString leftBufferName = sourceModel()->data(source_left, NetworkModel::BufferInfoRole)
+ .value<BufferInfo>().bufferName();
+ QString rightBufferName = sourceModel()->data(source_right, NetworkModel::BufferInfoRole)
+ .value<BufferInfo>().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);
}
-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<CheckRemovalEvent *>(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)
{
Q_CHECK_PTR(Client::networkModel());