modernize: Replace most remaining old-style connects by PMF ones
[quassel.git] / src / uisupport / bufferviewfilter.cpp
index c829267..059e47e 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   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),
@@ -56,13 +49,12 @@ BufferViewFilter::BufferViewFilter(QAbstractItemModel *model, BufferViewConfig *
     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()));
@@ -76,7 +68,7 @@ void BufferViewFilter::setConfig(BufferViewConfig *config)
         return;
 
     if (_config) {
-        disconnect(_config, 0, this, 0);
+        disconnect(_config, nullptr, this, nullptr);
     }
 
     _config = config;
@@ -93,7 +85,7 @@ 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();
     }
 }
@@ -104,21 +96,9 @@ 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());
 
@@ -147,6 +127,14 @@ QList<QAction *> BufferViewFilter::actions(const QModelIndex &index)
     return actionList;
 }
 
+void BufferViewFilter::setFilterString(const QString string)
+{
+    beginResetModel();
+    _filterString = string;
+    endResetModel();
+    enableEditMode(!string.isEmpty());
+}
+
 
 void BufferViewFilter::enableEditMode(bool enable)
 {
@@ -185,23 +173,23 @@ 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<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;
 }
@@ -245,7 +233,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<ClientBufferViewConfig *>(config());
+                auto *clientConf = qobject_cast<ClientBufferViewConfig *>(config());
                 if (!clientConf || !clientConf->isLocked())
                     config()->requestMoveBuffer(bufferId, pos);
             }
@@ -356,6 +344,16 @@ bool BufferViewFilter::filterAcceptBuffer(const QModelIndex &source_bufferIndex)
         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>())
@@ -430,6 +428,30 @@ bool BufferViewFilter::bufferLessThan(const QModelIndex &source_left, const QMod
 {
     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);
@@ -542,34 +564,6 @@ bool BufferViewFilter::setCheckedState(const QModelIndex &index, Qt::CheckState
 }
 
 
-void BufferViewFilter::checkPreviousCurrentForRemoval(const QModelIndex &current, 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());