Sort directories by name/ID

* Use the name as sorting criteria and fall back to the ID if there's no
  name
* Use new SyncthingSortFilterDirectoryModel also for Plasmoid's filtering
* See https://github.com/Martchus/syncthingtray/issues/75
This commit is contained in:
Martchus 2020-10-18 15:48:02 +02:00
parent d0f27bf327
commit 3e1beaa11d
15 changed files with 132 additions and 20 deletions

View File

@ -245,7 +245,7 @@ To build the plugin for Dolphin integration KIO is also requried. Additionally,
building the plugin, add `-DNO_FILE_ITEM_ACTION_PLUGIN:BOOL=ON` to the CMake arguments.
To build the Plasmoid for the Plasma 5 desktop, the Qt module QML and the KF5 module
Plasma are required as well. Additionally, the Plasmoid requires Qt 5.8 or newer. To skip
Plasma are required as well. Additionally, the Plasmoid requires Qt 5.12 or newer. To skip
building the Plasmoid, add `-DNO_PLASMOID:BOOL=ON` to the CMake arguments.
It is also possible to build only the CLI (syncthingctl) by adding `-DNO_MODEL:BOOL=ON` and

View File

@ -15,6 +15,7 @@ set(HEADER_FILES
syncthingdevicemodel.h
syncthingdownloadmodel.h
syncthingrecentchangesmodel.h
syncthingsortfilterdirectorymodel.h
syncthingstatusselectionmodel.h
syncthingicons.h
colors.h)
@ -24,6 +25,7 @@ set(SRC_FILES
syncthingdevicemodel.cpp
syncthingdownloadmodel.cpp
syncthingrecentchangesmodel.cpp
syncthingsortfilterdirectorymodel.cpp
syncthingstatusselectionmodel.cpp
syncthingicons.cpp)
set(RES_FILES resources/${META_PROJECT_NAME}icons.qrc)

View File

@ -0,0 +1,27 @@
#include "./syncthingsortfilterdirectorymodel.h"
#include <QSortFilterProxyModel>
namespace Data {
bool SyncthingSortFilterDirectoryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
// show all nested structures
if (sourceParent.isValid()) {
return true;
}
// use default filtering for top-level
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
}
bool SyncthingSortFilterDirectoryModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
// keep order within nested structures
if (m_behavior == SyncthingDirectorySortBehavior::KeepRawOrder || left.parent().isValid() || right.parent().isValid()) {
return left.row() < right.row();
}
// use the default sorting for the top-level
return QSortFilterProxyModel::lessThan(left, right);
}
} // namespace Data

View File

@ -0,0 +1,55 @@
#ifndef DATA_SYNCTHINGSORTFILTERDIRECTORYMODEL_H
#define DATA_SYNCTHINGSORTFILTERDIRECTORYMODEL_H
#include "./global.h"
#include <QSortFilterProxyModel>
namespace Data {
enum class SyncthingDirectorySortBehavior {
KeepRawOrder,
Alphabetically,
};
class LIB_SYNCTHING_MODEL_EXPORT SyncthingSortFilterDirectoryModel : public QSortFilterProxyModel {
Q_OBJECT
public:
explicit SyncthingSortFilterDirectoryModel(QAbstractItemModel *sourceModel = nullptr, QObject *parent = nullptr);
SyncthingDirectorySortBehavior behavior() const;
void setBehavior(SyncthingDirectorySortBehavior behavior);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
private:
SyncthingDirectorySortBehavior m_behavior;
};
inline SyncthingSortFilterDirectoryModel::SyncthingSortFilterDirectoryModel(QAbstractItemModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
, m_behavior(SyncthingDirectorySortBehavior::Alphabetically)
{
setSortCaseSensitivity(Qt::CaseInsensitive);
setFilterCaseSensitivity(Qt::CaseInsensitive);
setSourceModel(sourceModel);
}
inline SyncthingDirectorySortBehavior SyncthingSortFilterDirectoryModel::behavior() const
{
return m_behavior;
}
inline void SyncthingSortFilterDirectoryModel::setBehavior(SyncthingDirectorySortBehavior behavior)
{
if (behavior != m_behavior) {
m_behavior = behavior;
invalidate();
}
}
} // namespace Data
#endif // DATA_SYNCTHINGSORTFILTERDIRECTORYMODEL_H

View File

@ -53,6 +53,7 @@ SyncthingApplet::SyncthingApplet(QObject *parent, const QVariantList &data)
, m_connection()
, m_notifier(m_connection)
, m_dirModel(m_connection)
, m_sortFilterDirModel(&m_dirModel)
, m_devModel(m_connection)
, m_downloadModel(m_connection)
, m_recentChangesModel(m_connection)
@ -66,6 +67,7 @@ SyncthingApplet::SyncthingApplet(QObject *parent, const QVariantList &data)
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
m_notifier.setService(&m_service);
#endif
m_sortFilterDirModel.sort(0, Qt::AscendingOrder);
qmlRegisterUncreatableMetaObject(Data::staticMetaObject, "martchus.syncthingplasmoid", 0, 6, "Data", QStringLiteral("only enums"));
}

View File

@ -9,6 +9,7 @@
#include "../../model/syncthingdirectorymodel.h"
#include "../../model/syncthingdownloadmodel.h"
#include "../../model/syncthingrecentchangesmodel.h"
#include "../../model/syncthingsortfilterdirectorymodel.h"
#include "../../model/syncthingstatusselectionmodel.h"
#include "../../connector/syncthingconnection.h"
@ -38,6 +39,7 @@ class SyncthingApplet : public Plasma::Applet {
Q_OBJECT
Q_PROPERTY(Data::SyncthingConnection *connection READ connection NOTIFY connectionChanged)
Q_PROPERTY(Data::SyncthingDirectoryModel *dirModel READ dirModel NOTIFY dirModelChanged)
Q_PROPERTY(Data::SyncthingSortFilterDirectoryModel *sortFilterDirModel READ sortFilterDirModel NOTIFY dirModelChanged)
Q_PROPERTY(Data::SyncthingDeviceModel *devModel READ devModel NOTIFY devModelChanged)
Q_PROPERTY(Data::SyncthingDownloadModel *downloadModel READ downloadModel NOTIFY downloadModelChanged)
Q_PROPERTY(Data::SyncthingRecentChangesModel *recentChangesModel READ recentChangesModel NOTIFY recentChangesModelChanged)
@ -71,6 +73,7 @@ public:
public:
Data::SyncthingConnection *connection() const;
Data::SyncthingDirectoryModel *dirModel() const;
Data::SyncthingSortFilterDirectoryModel *sortFilterDirModel() const;
Data::SyncthingDeviceModel *devModel() const;
Data::SyncthingDownloadModel *downloadModel() const;
Data::SyncthingRecentChangesModel *recentChangesModel() const;
@ -171,6 +174,7 @@ private:
#endif
QtGui::StatusInfo m_statusInfo;
Data::SyncthingDirectoryModel m_dirModel;
Data::SyncthingSortFilterDirectoryModel m_sortFilterDirModel;
Data::SyncthingDeviceModel m_devModel;
Data::SyncthingDownloadModel m_downloadModel;
Data::SyncthingRecentChangesModel m_recentChangesModel;
@ -196,6 +200,11 @@ inline Data::SyncthingDirectoryModel *SyncthingApplet::dirModel() const
return const_cast<Data::SyncthingDirectoryModel *>(&m_dirModel);
}
inline Data::SyncthingSortFilterDirectoryModel *SyncthingApplet::sortFilterDirModel() const
{
return const_cast<Data::SyncthingSortFilterDirectoryModel *>(&m_sortFilterDirModel);
}
inline Data::SyncthingDeviceModel *SyncthingApplet::devModel() const
{
return const_cast<Data::SyncthingDeviceModel *>(&m_devModel);

View File

@ -20,13 +20,7 @@ ColumnLayout {
TopLevelView {
id: directoryView
width: parent.width
model: PlasmaCore.SortFilterModel {
id: directoryFilterModel
sourceModel: plasmoid.nativeInterface.dirModel
filterRole: "name"
filterRegExp: filter.text
}
model: plasmoid.nativeInterface.sortFilterDirModel
delegate: TopLevelItem {
id: item
@ -37,8 +31,6 @@ ColumnLayout {
property alias rescanButton: rescanButton
property alias resumePauseButton: resumePauseButton
property alias openButton: openButton
property int sourceIndex: directoryFilterModel.mapRowToSource(
index)
ColumnLayout {
width: parent.width
@ -122,7 +114,7 @@ ColumnLayout {
model: DelegateModel {
model: plasmoid.nativeInterface.dirModel
rootIndex: detailsView.model.modelIndex(sourceIndex)
rootIndex: directoryView.model.mapToSource(directoryView.model.index(index, 0))
delegate: DetailItem {
width: detailsView.width
}
@ -185,5 +177,6 @@ ColumnLayout {
clearButtonShown: true
Layout.fillWidth: true
visible: explicitelyShown || text !== ""
onTextChanged: directoryView.model.filterRegularExpression = new RegExp(text)
}
}

View File

@ -14,6 +14,7 @@ class DevView : public QTreeView {
Q_OBJECT
public:
using ModelType = Data::SyncthingDeviceModel;
using SortFilterModelType = void;
DevView(QWidget *parent = nullptr);

View File

@ -4,6 +4,7 @@
#include "../../connector/syncthingconnection.h"
#include "../../model/syncthingdirectorymodel.h"
#include "../../model/syncthingsortfilterdirectorymodel.h"
#include "../../widgets/misc/direrrorsdialog.h"
#include <QClipboard>
@ -30,13 +31,15 @@ void DirView::mouseReleaseEvent(QMouseEvent *event)
{
QTreeView::mouseReleaseEvent(event);
// get SyncthingDir object
auto *const dirModel = qobject_cast<SyncthingDirectoryModel *>(model());
// get SyncthingDir object for clicked index
auto *const sortDirModel = qobject_cast<SortFilterModelType *>(model());
auto *const dirModel = qobject_cast<ModelType *>(sortDirModel ? sortDirModel->sourceModel() : model());
if (!dirModel) {
return;
}
const QPoint pos(event->pos());
const QModelIndex clickedIndex(indexAt(event->pos()));
const auto pos = event->pos();
const auto clickedProxyIndex = indexAt(event->pos());
const auto clickedIndex = sortDirModel ? sortDirModel->mapToSource(clickedProxyIndex) : clickedProxyIndex;
if (!clickedIndex.isValid() || clickedIndex.column() != 1) {
return;
}
@ -47,7 +50,7 @@ void DirView::mouseReleaseEvent(QMouseEvent *event)
if (!clickedIndex.parent().isValid()) {
// open/scan dir buttons
const QRect itemRect(visualRect(clickedIndex));
const QRect itemRect = visualRect(clickedProxyIndex);
if (pos.x() <= itemRect.right() - 58) {
return;
}

View File

@ -6,6 +6,7 @@
namespace Data {
struct SyncthingDir;
class SyncthingDirectoryModel;
class SyncthingSortFilterDirectoryModel;
} // namespace Data
namespace QtGui {
@ -14,6 +15,7 @@ class DirView : public QTreeView {
Q_OBJECT
public:
using ModelType = Data::SyncthingDirectoryModel;
using SortFilterModelType = Data::SyncthingSortFilterDirectoryModel;
DirView(QWidget *parent = nullptr);

View File

@ -15,6 +15,7 @@ class DownloadView : public QTreeView {
Q_OBJECT
public:
using ModelType = Data::SyncthingDownloadModel;
using SortFilterModelType = void;
DownloadView(QWidget *parent = nullptr);

View File

@ -9,6 +9,7 @@
#include <QTreeView>
#include <functional>
#include <type_traits>
QT_FORWARD_DECLARE_CLASS(QPoint)
QT_FORWARD_DECLARE_CLASS(QMenu)
@ -42,7 +43,15 @@ template <typename ViewType> SelectedRow<ViewType>::SelectedRow(ViewType *view)
return;
}
index = selectedRows.at(0);
model = qobject_cast<typename ViewType::ModelType *>(view->model());
if constexpr (std::is_void_v<typename ViewType::SortFilterModelType>) {
model = qobject_cast<typename ViewType::ModelType *>(view->model());
} else {
const auto *const sortFilterModel = qobject_cast<typename ViewType::SortFilterModelType *>(view->model());
if (sortFilterModel) {
index = sortFilterModel->mapToSource(index);
model = qobject_cast<typename ViewType::ModelType *>(sortFilterModel->sourceModel());
}
}
if (model) {
data = model->info(index);
}

View File

@ -76,6 +76,7 @@ TrayWidget::TrayWidget(TrayMenu *parent)
#endif
, m_notifier(m_connection)
, m_dirModel(m_connection)
, m_sortFilterDirModel(&m_dirModel)
, m_devModel(m_connection)
, m_dlModel(m_connection)
, m_recentChangesModel(m_connection)
@ -86,8 +87,9 @@ TrayWidget::TrayWidget(TrayMenu *parent)
m_ui->setupUi(this);
// setup model and view
m_ui->dirsTreeView->setModel(&m_dirModel);
// setup models and views
m_ui->dirsTreeView->header()->setSortIndicator(0, Qt::AscendingOrder);
m_ui->dirsTreeView->setModel(&m_sortFilterDirModel);
m_ui->devsTreeView->setModel(&m_devModel);
m_ui->downloadsTreeView->setModel(&m_dlModel);
m_ui->recentChangesTreeView->setModel(&m_recentChangesModel);

View File

@ -8,6 +8,7 @@
#include "../../model/syncthingdirectorymodel.h"
#include "../../model/syncthingdownloadmodel.h"
#include "../../model/syncthingrecentchangesmodel.h"
#include "../../model/syncthingsortfilterdirectorymodel.h"
#include "../../connector/syncthingconnection.h"
#include "../../connector/syncthingnotifier.h"
@ -118,6 +119,7 @@ private:
Data::SyncthingConnection m_connection;
Data::SyncthingNotifier m_notifier;
Data::SyncthingDirectoryModel m_dirModel;
Data::SyncthingSortFilterDirectoryModel m_sortFilterDirModel;
Data::SyncthingDeviceModel m_devModel;
Data::SyncthingDownloadModel m_dlModel;
Data::SyncthingRecentChangesModel m_recentChangesModel;

View File

@ -403,7 +403,11 @@ For &lt;i&gt;all&lt;/i&gt; notifications, checkout the log</string>
<number>0</number>
</property>
<item>
<widget class="QtGui::DirView" name="dirsTreeView"/>
<widget class="QtGui::DirView" name="dirsTreeView">
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>