allow selecting conflict resolutions for many conflicts
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>
Fri, 12 May 2023 11:17:38 +0000 (13:17 +0200)
committerMatthieu Gallien <matthieu_gallien@yahoo.fr>
Wed, 17 May 2023 06:43:54 +0000 (08:43 +0200)
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
src/gui/ConflictDelegate.qml
src/gui/ResolveConflictsDialog.qml
src/gui/syncconflictsmodel.cpp
src/gui/syncconflictsmodel.h

index a8cbe9dd5cbe43daa339b65fd3a15928d729aaf2..eeebc3f5011c7efd93ca27fbc48c4b3b12c88536 100644 (file)
@@ -32,6 +32,7 @@ Item {
     required property bool conflictSelected
     required property url existingPreviewUrl
     required property url conflictPreviewUrl
+    required property var model
 
     EnforcedPlainTextLabel {
         id: existingFileNameLabel
@@ -66,6 +67,10 @@ Item {
                 spacing: 0
 
                 checked: root.existingSelected
+
+                onToggled: function() {
+                    model.existingSelected = checked
+                }
             }
 
             Image {
@@ -139,6 +144,10 @@ Item {
                 spacing: 0
 
                 checked: root.conflictSelected
+
+                onToggled: function() {
+                    model.conflictSelected = checked
+                }
             }
 
             Image {
index 5e83d951a1fbccca159ae6353a055b747db17510..d94541601147faad1782d067c18f4af7525ff6cd 100644 (file)
@@ -80,6 +80,11 @@ QtWindow.Window {
                 implicitWidth: 100
 
                 font.pixelSize: 15
+
+                checked: realModel.allExistingsSelected
+                onToggled: function() {
+                    realModel.selectAllExisting(checked)
+                }
             }
 
             CheckBox {
@@ -93,6 +98,11 @@ QtWindow.Window {
                 implicitWidth: 100
 
                 font.pixelSize: 15
+
+                checked: realModel.allConflictingSelected
+                onToggled: function() {
+                    realModel.selectAllConflicting(checked)
+                }
             }
         }
 
index b03d35371970a2299cd50861e11cd3d43425f2c6..cc9f4302b325cd90eaa4491fb6bb8e1531df4a8e 100644 (file)
@@ -82,6 +82,50 @@ QVariant SyncConflictsModel::data(const QModelIndex &index, int role) const
     return result;
 }
 
+bool SyncConflictsModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+    auto result = false;
+
+    Q_ASSERT(checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid));
+
+    if (index.parent().isValid()) {
+        return result;
+    }
+
+    if (role >= static_cast<int>(SyncConflictRoles::ExistingFileName) && role <= static_cast<int>(SyncConflictRoles::ConflictPreviewUrl)) {
+        auto convertedRole = static_cast<SyncConflictRoles>(role);
+
+        switch(convertedRole) {
+        case SyncConflictRoles::ExistingFileName:
+            break;
+        case SyncConflictRoles::ExistingSize:
+            break;
+        case SyncConflictRoles::ConflictSize:
+            break;
+        case SyncConflictRoles::ExistingDate:
+            break;
+        case SyncConflictRoles::ConflictDate:
+            break;
+        case SyncConflictRoles::ExistingSelected:
+            setExistingSelected(value.toBool(), index, role);
+            result = true;
+            break;
+        case SyncConflictRoles::ConflictSelected:
+            setConflictingSelected(value.toBool(), index, role);
+            result = true;
+            break;
+        case SyncConflictRoles::ExistingPreviewUrl:
+            break;
+        case SyncConflictRoles::ConflictPreviewUrl:
+            break;
+        }
+
+        result = false;
+    }
+
+    return result;
+}
+
 QHash<int, QByteArray> SyncConflictsModel::roleNames() const
 {
     auto result = QAbstractListModel::roleNames();
@@ -99,11 +143,34 @@ QHash<int, QByteArray> SyncConflictsModel::roleNames() const
     return result;
 }
 
+Qt::ItemFlags SyncConflictsModel::flags(const QModelIndex &index) const
+{
+    auto result = Qt::ItemFlags{};
+
+    if (!index.parent().isValid()) {
+        result = QAbstractListModel::flags(index);
+        return result;
+    }
+
+    result = Qt::ItemIsSelectable | Qt::ItemIsEditable;
+    return result;
+}
+
 ActivityList SyncConflictsModel::conflictActivities() const
 {
     return mData;
 }
 
+bool SyncConflictsModel::allExistingsSelected() const
+{
+    return mAllExistingsSelected;
+}
+
+bool SyncConflictsModel::allConflictingSelected() const
+{
+    return mAllConflictingsSelected;
+}
+
 void SyncConflictsModel::setConflictActivities(ActivityList conflicts)
 {
     if (mData == conflicts) {
@@ -120,6 +187,40 @@ void SyncConflictsModel::setConflictActivities(ActivityList conflicts)
     endResetModel();
 }
 
+void SyncConflictsModel::selectAllExisting(bool selected)
+{
+    for (auto &singleConflict : mConflictData) {
+        singleConflict.mExistingSelected = selected;
+    }
+
+    Q_EMIT dataChanged(index(0), index(rowCount() - 1), {static_cast<int>(SyncConflictRoles::ExistingSelected)});
+
+    if (selected && !mAllExistingsSelected) {
+        mAllExistingsSelected = true;
+        Q_EMIT allExistingsSelectedChanged();
+    } else if (!selected && mAllExistingsSelected) {
+        mAllExistingsSelected = false;
+        Q_EMIT allExistingsSelectedChanged();
+    }
+}
+
+void SyncConflictsModel::selectAllConflicting(bool selected)
+{
+    for (auto &singleConflict : mConflictData) {
+        singleConflict.mConflictSelected = selected;
+    }
+
+    Q_EMIT dataChanged(index(0), index(rowCount() - 1), {static_cast<int>(SyncConflictRoles::ConflictSelected)});
+
+    if (selected && !mAllConflictingsSelected) {
+        mAllConflictingsSelected = true;
+        Q_EMIT allConflictingSelectedChanged();
+    } else if (!selected && mAllConflictingsSelected) {
+        mAllConflictingsSelected = false;
+        Q_EMIT allConflictingSelectedChanged();
+    }
+}
+
 void SyncConflictsModel::updateConflictsData()
 {
     mConflictData.clear();
@@ -165,4 +266,54 @@ void SyncConflictsModel::updateConflictsData()
     }
 }
 
+void SyncConflictsModel::setExistingSelected(bool value,
+                                             const QModelIndex &index,
+                                             int role)
+{
+    mConflictData[index.row()].mExistingSelected = value;
+    Q_EMIT dataChanged(index, index, {role});
+
+    if (!mConflictData[index.row()].mExistingSelected && mAllExistingsSelected) {
+        mAllExistingsSelected = false;
+        Q_EMIT allExistingsSelectedChanged();
+    } else if (mConflictData[index.row()].mExistingSelected && !mAllExistingsSelected) {
+        auto allSelected = true;
+        for (const auto &singleConflict : qAsConst(mConflictData)) {
+            if (!singleConflict.mExistingSelected) {
+                allSelected = false;
+                break;
+            }
+        }
+        if (allSelected) {
+            mAllExistingsSelected = true;
+            Q_EMIT allExistingsSelectedChanged();
+        }
+    }
+}
+
+void SyncConflictsModel::setConflictingSelected(bool value,
+                                                const QModelIndex &index,
+                                                int role)
+{
+    mConflictData[index.row()].mConflictSelected = value;
+    Q_EMIT dataChanged(index, index, {role});
+
+    if (!mConflictData[index.row()].mConflictSelected && mAllConflictingsSelected) {
+        mAllConflictingsSelected = false;
+        Q_EMIT allConflictingSelectedChanged();
+    } else if (mConflictData[index.row()].mConflictSelected && !mAllConflictingsSelected) {
+        auto allSelected = true;
+        for (const auto &singleConflict : qAsConst(mConflictData)) {
+            if (!singleConflict.mConflictSelected) {
+                allSelected = false;
+                break;
+            }
+        }
+        if (allSelected) {
+            mAllConflictingsSelected = true;
+            Q_EMIT allConflictingSelectedChanged();
+        }
+    }
+}
+
 }
index d7ca61961d97d7529285792ddfc84936ed48b14a..2586ab17b03f20842ca330b0a4492e9e6fe1af51 100644 (file)
@@ -29,6 +29,10 @@ class SyncConflictsModel : public QAbstractListModel
 
     Q_PROPERTY(OCC::ActivityList conflictActivities READ conflictActivities WRITE setConflictActivities NOTIFY conflictActivitiesChanged)
 
+    Q_PROPERTY(bool allExistingsSelected READ allExistingsSelected NOTIFY allExistingsSelectedChanged)
+
+    Q_PROPERTY(bool allConflictingSelected READ allConflictingSelected NOTIFY allConflictingSelectedChanged)
+
     struct ConflictInfo {
         QString mExistingFileName;
         QString mExistingSize;
@@ -62,19 +66,43 @@ public:
 
     [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
 
+    [[nodiscard]] bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+
     [[nodiscard]] QHash<int,QByteArray> roleNames() const override;
 
+    [[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
+
     [[nodiscard]] OCC::ActivityList conflictActivities() const;
 
+    [[nodiscard]] bool allExistingsSelected() const;
+
+    [[nodiscard]] bool allConflictingSelected() const;
+
 public slots:
     void setConflictActivities(OCC::ActivityList conflicts);
 
+    void selectAllExisting(bool selected);
+
+    void selectAllConflicting(bool selected);
+
 signals:
     void conflictActivitiesChanged();
 
+    void allExistingsSelectedChanged();
+
+    void allConflictingSelectedChanged();
+
 private:
     void updateConflictsData();
 
+    void setExistingSelected(bool value,
+                             const QModelIndex &index,
+                             int role);
+
+    void setConflictingSelected(bool value,
+                                const QModelIndex &index,
+                                int role);
+
     OCC::ActivityList mData;
 
     QVector<ConflictInfo> mConflictData;
@@ -82,6 +110,10 @@ private:
     QMimeDatabase mMimeDb;
 
     QLocale mLocale;
+
+    bool mAllExistingsSelected = false;
+
+    bool mAllConflictingsSelected = false;
 };
 
 }