[Pkg-owncloud-commits] [owncloud-client] 06/115: Selective sync: Add UI to select paths

Sandro Knauß hefee-guest at moszumanska.debian.org
Fri Aug 29 22:03:53 UTC 2014


This is an automated email from the git hooks/post-receive script.

hefee-guest pushed a commit to branch master
in repository owncloud-client.

commit aa85e875bd2aa3d80c61e371f7a52e2c915420fe
Author: Olivier Goffart <ogoffart at woboq.com>
Date:   Mon Aug 11 15:09:17 2014 +0200

    Selective sync:  Add UI to select paths
---
 src/CMakeLists.txt                 |   1 +
 src/mirall/accountsettings.cpp     |  18 +++
 src/mirall/accountsettings.h       |   1 +
 src/mirall/accountsettings.ui      |   7 +
 src/mirall/folder.h                |   5 +
 src/mirall/folderman.cpp           |  10 +-
 src/mirall/folderman.h             |   7 +-
 src/mirall/logger.cpp              |   2 +-
 src/mirall/selectivesyncdialog.cpp | 256 +++++++++++++++++++++++++++++++++++++
 src/mirall/selectivesyncdialog.h   |  47 +++++++
 10 files changed, 346 insertions(+), 8 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ec15a25..9d4e66b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -267,6 +267,7 @@ set(mirall_SRCS
     mirall/socketapi.cpp
     mirall/sslbutton.cpp
     mirall/syncrunfilelog.cpp
+    mirall/selectivesyncdialog.cpp
 )
 
 
diff --git a/src/mirall/accountsettings.cpp b/src/mirall/accountsettings.cpp
index 6259d44..4db0c28 100644
--- a/src/mirall/accountsettings.cpp
+++ b/src/mirall/accountsettings.cpp
@@ -26,6 +26,7 @@
 #include "mirall/ignorelisteditor.h"
 #include "mirall/account.h"
 #include "mirall/quotainfo.h"
+#include "selectivesyncdialog.h"
 #include "creds/abstractcredentials.h"
 
 #include <math.h>
@@ -77,6 +78,7 @@ AccountSettings::AccountSettings(QWidget *parent) :
 
     ui->_buttonRemove->setEnabled(false);
     ui->_buttonEnable->setEnabled(false);
+    ui->_buttonSelectiveSync->setEnabled(false);
     ui->_buttonAdd->setEnabled(true);
 
     QAction *resetFolderAction = new QAction(this);
@@ -92,6 +94,7 @@ AccountSettings::AccountSettings(QWidget *parent) :
     connect(ui->_buttonRemove, SIGNAL(clicked()), this, SLOT(slotRemoveCurrentFolder()));
     connect(ui->_buttonEnable, SIGNAL(clicked()), this, SLOT(slotEnableCurrentFolder()));
     connect(ui->_buttonAdd,    SIGNAL(clicked()), this, SLOT(slotAddFolder()));
+    connect(ui->_buttonSelectiveSync, SIGNAL(clicked()), this, SLOT(slotSelectiveSync()));
     connect(ui->modifyAccountButton, SIGNAL(clicked()), SLOT(slotOpenAccountWizard()));
     connect(ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));;
 
@@ -152,6 +155,7 @@ void AccountSettings::slotFolderActivated( const QModelIndex& indx )
   }
   ui->_buttonAdd->setEnabled(_account && _account->state() == Account::Connected);
   ui->_buttonEnable->setEnabled( isValid );
+  ui->_buttonSelectiveSync->setEnabled( isValid );
 
   if ( isValid ) {
     bool folderEnabled = _model->data( indx, FolderStatusDelegate::FolderSyncEnabled).toBool();
@@ -369,6 +373,20 @@ void AccountSettings::slotResetCurrentFolder()
     }
 }
 
+void AccountSettings::slotSelectiveSync()
+{
+    QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
+    if( selected.isValid() ) {
+        QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
+        FolderMan *folderMan = FolderMan::instance();
+        Folder *f = folderMan->folder(alias);
+        if (f) {
+            (new SelectiveSyncDialog(f, this))->show();
+        }
+    }
+
+}
+
 void AccountSettings::slotDoubleClicked( const QModelIndex& indx )
 {
     if( ! indx.isValid() ) return;
diff --git a/src/mirall/accountsettings.h b/src/mirall/accountsettings.h
index 4e64ea2..53c6ad8 100644
--- a/src/mirall/accountsettings.h
+++ b/src/mirall/accountsettings.h
@@ -81,6 +81,7 @@ protected slots:
     void slotFolderWizardRejected();
     void slotOpenAccountWizard();
     void slotHideProgress();
+    void slotSelectiveSync();
 
 private:
     QString shortenFilename( const QString& folder, const QString& file ) const;
diff --git a/src/mirall/accountsettings.ui b/src/mirall/accountsettings.ui
index 133dfaa..e62916d 100644
--- a/src/mirall/accountsettings.ui
+++ b/src/mirall/accountsettings.ui
@@ -71,6 +71,13 @@
          </widget>
         </item>
         <item>
+         <widget class="QPushButton" name="_buttonSelectiveSync">
+          <property name="text">
+           <string>Selective Sync...</string>
+          </property>
+         </widget>
+        </item>
+        <item>
          <spacer name="verticalSpacer_3">
           <property name="orientation">
            <enum>Qt::Vertical</enum>
diff --git a/src/mirall/folder.h b/src/mirall/folder.h
index 8a9d554..52304c8 100644
--- a/src/mirall/folder.h
+++ b/src/mirall/folder.h
@@ -121,6 +121,10 @@ public:
      SyncJournalDb *journalDb() { return &_journal; }
      CSYNC *csyncContext() { return _csync_ctx; }
 
+     QStringList selectiveSyncList() { return _selectiveSyncWhiteList; }
+     void setSelectiveSyncList(const QStringList &whiteList)
+     { _selectiveSyncWhiteList = whiteList; }
+
 
 signals:
     void syncStateChange();
@@ -188,6 +192,7 @@ private:
     SyncResult _syncResult;
     QScopedPointer<SyncEngine> _engine;
     QStringList  _errors;
+    QStringList _selectiveSyncWhiteList;
     bool         _csyncError;
     bool         _csyncUnavail;
     bool         _wipeDb;
diff --git a/src/mirall/folderman.cpp b/src/mirall/folderman.cpp
index 5729c4d..554ea34 100644
--- a/src/mirall/folderman.cpp
+++ b/src/mirall/folderman.cpp
@@ -234,7 +234,7 @@ void FolderMan::terminateCurrentSync()
 #define PAR_O_TAG   QLatin1String("__PAR_OPEN__")
 #define PAR_C_TAG   QLatin1String("__PAR_CLOSE__")
 
-QString FolderMan::escapeAlias( const QString& alias ) const
+QString FolderMan::escapeAlias( const QString& alias )
 {
     QString a(alias);
 
@@ -312,6 +312,7 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
     QString backend = settings.value(QLatin1String("backend")).toString();
     QString targetPath = settings.value( QLatin1String("targetPath")).toString();
     bool paused = settings.value( QLatin1String("paused"), false).toBool();
+    QStringList whiteList = settings.value( QLatin1String("whiteList")).toStringList();
     // QString connection = settings.value( QLatin1String("connection") ).toString();
     QString alias = unescapeAlias( escapedAlias );
 
@@ -326,7 +327,8 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
     }
 
     folder = new Folder( alias, path, targetPath, this );
-    folder->setConfigFile(file);
+    folder->setConfigFile(cfgFile.absoluteFilePath());
+    folder->setSelectiveSyncList(whiteList);
     qDebug() << "Adding folder to Folder Map " << folder;
     _folderMap[alias] = folder;
     if (paused) {
@@ -359,7 +361,7 @@ void FolderMan::slotEnableFolder( const QString& alias, bool enable )
         slotScheduleSync(alias);
 
         // FIXME: Use MirallConfigFile
-        QSettings settings(_folderConfigPath + QLatin1Char('/') + f->configFile(), QSettings::IniFormat);
+        QSettings settings(f->configFile(), QSettings::IniFormat);
         settings.beginGroup(escapeAlias(f->alias()));
         if (enable) {
             settings.remove("paused");
@@ -588,7 +590,7 @@ void FolderMan::removeFolder( const QString& alias )
         f->setSyncEnabled(false);
 
         // remove the folder configuration
-        QFile file( _folderConfigPath + QLatin1Char('/') + f->configFile() );
+        QFile file(f->configFile() );
         if( file.exists() ) {
             qDebug() << "Remove folder config file " << file.fileName();
             file.remove();
diff --git a/src/mirall/folderman.h b/src/mirall/folderman.h
index c3a8d00..abfaf12 100644
--- a/src/mirall/folderman.h
+++ b/src/mirall/folderman.h
@@ -84,6 +84,10 @@ public:
     void removeMonitorPath( const QString& alias, const QString& path );
     void addMonitorPath( const QString& alias, const QString& path );
 
+    // Escaping of the alias which is used in QSettings AND the file
+    // system, thus need to be escaped.
+    static QString escapeAlias( const QString& );
+
 signals:
     /**
       * signal to indicate a folder named by alias has changed its sync state.
@@ -131,9 +135,6 @@ private:
     QString getBackupName( const QString& ) const;
     void registerFolderMonitor( Folder *folder );
 
-    // Escaping of the alias which is used in QSettings AND the file
-    // system, thus need to be escaped.
-    QString escapeAlias( const QString& ) const;
     QString unescapeAlias( const QString& ) const;
 
     void removeFolder( const QString& );
diff --git a/src/mirall/logger.cpp b/src/mirall/logger.cpp
index 0bc8d1c..4ab9232 100644
--- a/src/mirall/logger.cpp
+++ b/src/mirall/logger.cpp
@@ -50,7 +50,7 @@ Logger *Logger::instance()
 Logger::Logger( QObject* parent) : QObject(parent),
   _showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0)
 {
-    qInstallMessageHandler(mirallLogCatcher);
+//    qInstallMessageHandler(mirallLogCatcher);
 }
 
 Logger::~Logger() {
diff --git a/src/mirall/selectivesyncdialog.cpp b/src/mirall/selectivesyncdialog.cpp
new file mode 100644
index 0000000..56d3999
--- /dev/null
+++ b/src/mirall/selectivesyncdialog.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) by Olivier Goffart <ogoffart at woboq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include "selectivesyncdialog.h"
+#include "folder.h"
+#include "account.h"
+#include "networkjobs.h"
+#include "theme.h"
+#include "folderman.h"
+#include <QDialogButtonBox>
+#include <QVBoxLayout>
+#include <QTreeWidget>
+#include <qpushbutton.h>
+#include <QFileIconProvider>
+#include <QDebug>
+#include <QSettings>
+#include <QScopedValueRollback>
+
+namespace Mirall {
+
+SelectiveSyncDialog::SelectiveSyncDialog(Folder* folder, QWidget* parent, Qt::WindowFlags f)
+    :   QDialog(parent, f), _folder(folder)
+{
+    QVBoxLayout *layout = new QVBoxLayout(this);
+    _treeView = new QTreeWidget;
+    connect(_treeView, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*)));
+    connect(_treeView, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
+    layout->addWidget(_treeView);
+    QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
+    QPushButton *button;
+    button = buttonBox->addButton(QDialogButtonBox::Ok);
+    connect(button, SIGNAL(clicked()), this, SLOT(accept()));
+    button = buttonBox->addButton(QDialogButtonBox::Cancel);
+    connect(button, SIGNAL(clicked()), this, SLOT(reject()));
+    layout->addWidget(buttonBox);
+
+    // Make sure we don't get crashes if the folder is destroyed while we are still open
+    connect(_folder, SIGNAL(destroyed(QObject*)), this, SLOT(deleteLater()));
+
+    refreshFolders();
+}
+
+void SelectiveSyncDialog::refreshFolders()
+{
+    LsColJob *job = new LsColJob(AccountManager::instance()->account(), _folder->remotePath(), this);
+    connect(job, SIGNAL(directoryListing(QStringList)),
+            this, SLOT(slotUpdateDirectories(QStringList)));
+    job->start();
+    _treeView->clear();
+
+}
+
+static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& text)
+{
+    for (int i = 0; i < parent->childCount(); ++i) {
+        QTreeWidgetItem *child = parent->child(i);
+        if (child->text(0) == text) {
+            return child;
+        }
+    }
+    return 0;
+}
+
+void SelectiveSyncDialog::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail,
+                                                  QString path)
+{
+    QFileIconProvider prov;
+    QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
+    if (pathTrail.size() == 0) {
+        if (path.endsWith('/')) {
+            path.chop(1);
+        }
+        parent->setToolTip(0, path);
+        parent->setData(0, Qt::UserRole, path);
+    } else {
+        QTreeWidgetItem *item = findFirstChild(parent, pathTrail.first());
+        if (!item) {
+            item = new QTreeWidgetItem(parent);
+            if (parent->checkState(0) == Qt::Checked) {
+                item->setCheckState(0, Qt::Checked);
+            } else if (parent->checkState(0) == Qt::Unchecked) {
+                item->setCheckState(0, Qt::Unchecked);
+            } else {
+                item->setCheckState(0, Qt::Unchecked);
+                foreach(const QString &str , _folder->selectiveSyncList()) {
+                    if (str + "/" == path) {
+                        item->setCheckState(0, Qt::Checked);
+                        break;
+                    } else if (str.startsWith(path)) {
+                        item->setCheckState(0, Qt::PartiallyChecked);
+                    }
+                }
+            }
+            item->setIcon(0, folderIcon);
+            item->setText(0, pathTrail.first());
+//            item->setData(0, Qt::UserRole, pathTrail.first());
+            item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
+        }
+
+        pathTrail.removeFirst();
+        recursiveInsert(item, pathTrail, path);
+    }
+}
+
+void SelectiveSyncDialog::slotUpdateDirectories(const QStringList &list)
+{
+    QScopedValueRollback<bool> isInserting(_inserting);
+    _inserting = true;
+
+    QTreeWidgetItem *root = _treeView->topLevelItem(0);
+    if (!root) {
+        root = new QTreeWidgetItem(_treeView);
+        root->setText(0, _folder->alias());
+        root->setIcon(0, Theme::instance()->applicationIcon());
+        root->setData(0, Qt::UserRole, _folder->remotePath());
+        if (_folder->selectiveSyncList().isEmpty() || _folder->selectiveSyncList().contains(QString())) {
+            root->setCheckState(0, Qt::Checked);
+        } else {
+            root->setCheckState(0, Qt::PartiallyChecked);
+        }
+    }
+    const QString folderPath = _folder->remoteUrl().path();
+    foreach (QString path, list) {
+        path.remove(folderPath);
+        QStringList paths = path.split('/');
+        if (paths.last().isEmpty()) paths.removeLast();
+        recursiveInsert(root, paths, path);
+    }
+    root->setExpanded(true);
+}
+
+void SelectiveSyncDialog::slotItemExpanded(QTreeWidgetItem *item)
+{
+    QString dir = item->data(0, Qt::UserRole).toString();
+    LsColJob *job = new LsColJob(AccountManager::instance()->account(), dir, this);
+    connect(job, SIGNAL(directoryListing(QStringList)),
+            SLOT(slotUpdateDirectories(QStringList)));
+    job->start();
+}
+
+void SelectiveSyncDialog::slotItemChanged(QTreeWidgetItem *item, int col)
+{
+    if (col != 0 || _inserting)
+        return;
+
+    if (item->checkState(0) == Qt::Checked) {
+        // If we are checked, check that we may need to check the parent as well if
+        // all the sibilings are also checked
+        QTreeWidgetItem *parent = item->parent();
+        if (parent && parent->checkState(0) != Qt::Checked) {
+            bool hasUnchecked = false;
+            for (int i = 0; i < parent->childCount(); ++i) {
+                if (parent->child(i)->checkState(0) != Qt::Checked) {
+                    hasUnchecked = true;
+                    break;
+                }
+            }
+            if (!hasUnchecked) {
+                parent->setCheckState(0, Qt::Checked);
+            } else if (parent->checkState(0) == Qt::Unchecked) {
+                parent->setCheckState(0, Qt::PartiallyChecked);
+            }
+        }
+        // also check all the childs
+        for (int i = 0; i < item->childCount(); ++i) {
+            if (item->child(i)->checkState(0) != Qt::Checked) {
+                item->child(i)->setCheckState(0, Qt::Checked);
+            }
+        }
+    }
+
+    if (item->checkState(0) == Qt::Unchecked) {
+        QTreeWidgetItem *parent = item->parent();
+        if (parent && parent->checkState(0) != Qt::Unchecked) {
+            bool hasChecked = false;
+            for (int i = 0; i < parent->childCount(); ++i) {
+                if (parent->child(i)->checkState(0) != Qt::Unchecked) {
+                    hasChecked = true;
+                    break;
+                }
+            }
+            if (!hasChecked) {
+                parent->setCheckState(0, Qt::Unchecked);
+            } else if (parent->checkState(0) == Qt::Checked) {
+                parent->setCheckState(0, Qt::PartiallyChecked);
+            }
+        }
+
+        // Uncheck all the childs
+        for (int i = 0; i < item->childCount(); ++i) {
+            if (item->child(i)->checkState(0) != Qt::Unchecked) {
+                item->child(i)->setCheckState(0, Qt::Unchecked);
+            }
+        }
+    }
+
+    if (item->checkState(0) == Qt::PartiallyChecked) {
+        QTreeWidgetItem *parent = item->parent();
+        if (parent && parent->checkState(0) != Qt::PartiallyChecked) {
+            parent->setCheckState(0, Qt::PartiallyChecked);
+        }
+    }
+}
+
+QStringList SelectiveSyncDialog::createWhiteList(QTreeWidgetItem* root) const
+{
+    if (!root) {
+        root = _treeView->topLevelItem(0);
+    }
+    if (!root) return {};
+
+    switch(root->checkState(0)) {
+    case  Qt::Checked:
+        return { root->data(0, Qt::UserRole).toString() };
+    case Qt::Unchecked:
+        return {};
+    case Qt::PartiallyChecked:
+        break;
+    }
+
+    QStringList result;
+    for (int i = 0; i < root->childCount(); ++i) {
+        result += createWhiteList(root->child(i));
+    }
+    return result;
+}
+
+void SelectiveSyncDialog::accept()
+{
+    QStringList whiteList = createWhiteList();
+    _folder->setSelectiveSyncList(whiteList);
+
+    // FIXME: Use MirallConfigFile
+    QSettings settings(_folder->configFile(), QSettings::IniFormat);
+    settings.beginGroup(FolderMan::escapeAlias(_folder->alias()));
+    settings.setValue("whiteList", whiteList);
+
+    QDialog::accept();
+}
+
+
+
+}
+
+
+
diff --git a/src/mirall/selectivesyncdialog.h b/src/mirall/selectivesyncdialog.h
new file mode 100644
index 0000000..a74a7aa
--- /dev/null
+++ b/src/mirall/selectivesyncdialog.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) by Olivier Goffart <ogoffart at woboq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#pragma once
+#include <QDialog>
+
+class QTreeWidgetItem;
+class QTreeWidget;
+namespace Mirall {
+
+class Folder;
+
+class SelectiveSyncDialog : public QDialog {
+    Q_OBJECT
+public:
+    explicit SelectiveSyncDialog(Folder *folder, QWidget* parent = 0, Qt::WindowFlags f = 0);
+
+    virtual void accept() Q_DECL_OVERRIDE;
+    QStringList createWhiteList(QTreeWidgetItem* root = 0) const;
+
+private slots:
+    void refreshFolders();
+    void slotUpdateDirectories(const QStringList &);
+    void slotItemExpanded(QTreeWidgetItem *);
+    void slotItemChanged(QTreeWidgetItem*,int);
+
+private:
+    void recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path);
+
+    Folder *_folder;
+    QTreeWidget *_treeView;
+    bool _inserting = false; // set to true when we are inserting new items on the list
+};
+
+
+}
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud-client.git



More information about the Pkg-owncloud-commits mailing list