From: allexzander Date: Fri, 29 Jan 2021 18:00:21 +0000 (+0200) Subject: Allow creation of new folders from the Settings Dialog. X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~377^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=81a090b362f10df8d208924c97148b0bcff135ad;p=nextcloud-desktop.git Allow creation of new folders from the Settings Dialog. Signed-off-by: allexzander --- diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 0107a9d6c..346114074 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -23,6 +23,7 @@ endif() set(client_UI_SRCS accountsettings.ui conflictdialog.ui + foldercreationdialog.ui folderwizardsourcepage.ui folderwizardtargetpage.ui generalsettings.ui @@ -60,6 +61,7 @@ set(client_SRCS conflictsolver.cpp connectionvalidator.cpp folder.cpp + foldercreationdialog.cpp folderman.cpp folderstatusmodel.cpp folderstatusdelegate.cpp diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index ec6254b91..5b340de40 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -17,6 +17,7 @@ #include "ui_accountsettings.h" #include "theme.h" +#include "foldercreationdialog.h" #include "folderman.h" #include "folderwizard.h" #include "folderstatusmodel.h" @@ -333,6 +334,46 @@ void AccountSettings::slotEditCurrentIgnoredFiles() openIgnoredFilesDialog(f->path()); } +void AccountSettings::slotOpenMakeFolderDialog() +{ + const auto &selected = _ui->_folderList->selectionModel()->currentIndex(); + + if (!selected.isValid()) { + qCWarning(lcAccountSettings) << "Selection model current folder index is not valid."; + return; + } + + const auto &classification = _model->classify(selected); + + if (classification != FolderStatusModel::SubFolder && classification != FolderStatusModel::RootFolder) { + return; + } + + const QString fileName = [this, &selected, &classification] { + QString result; + if (classification == FolderStatusModel::RootFolder) { + const auto alias = _model->data(selected, FolderStatusDelegate::FolderAliasRole).toString(); + if (const auto folder = FolderMan::instance()->folder(alias)) { + result = folder->path(); + } + } else { + result = _model->data(selected, FolderStatusDelegate::FolderPathRole).toString(); + } + + if (result.endsWith('/')) { + result.chop(1); + } + + return result; + }(); + + if (!fileName.isEmpty()) { + const auto folderCreationDialog = new FolderCreationDialog(fileName, this); + folderCreationDialog->setAttribute(Qt::WA_DeleteOnClose); + folderCreationDialog->open(); + } +} + void AccountSettings::slotEditCurrentLocalIgnoredFiles() { QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex(); @@ -403,6 +444,10 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index ac = menu.addAction(tr("Edit Ignored Files")); connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentLocalIgnoredFiles); + ac = menu.addAction(tr("Create new folder")); + connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenMakeFolderDialog); + ac->setEnabled(QFile::exists(fileName)); + const auto folder = info->_folder; if (folder && folder->virtualFilesEnabled()) { auto availabilityMenu = menu.addMenu(tr("Availability")); @@ -475,6 +520,10 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos) ac = menu->addAction(tr("Edit Ignored Files")); connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentIgnoredFiles); + ac = menu->addAction(tr("Create new folder")); + connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenMakeFolderDialog); + ac->setEnabled(QFile::exists(folder->path())); + if (!_ui->_folderList->isExpanded(index) && folder->supportsSelectiveSync()) { ac = menu->addAction(tr("Choose what to sync")); ac->setEnabled(folderConnected); diff --git a/src/gui/accountsettings.h b/src/gui/accountsettings.h index ccb986e74..17e839839 100644 --- a/src/gui/accountsettings.h +++ b/src/gui/accountsettings.h @@ -85,6 +85,7 @@ protected slots: void slotOpenCurrentFolder(); // sync folder void slotOpenCurrentLocalSubFolder(); // selected subfolder in sync folder void slotEditCurrentIgnoredFiles(); + void slotOpenMakeFolderDialog(); void slotEditCurrentLocalIgnoredFiles(); void slotEnableVfsCurrentFolder(); void slotDisableVfsCurrentFolder(); diff --git a/src/gui/foldercreationdialog.cpp b/src/gui/foldercreationdialog.cpp new file mode 100644 index 000000000..3ee046d38 --- /dev/null +++ b/src/gui/foldercreationdialog.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) by Oleksandr Zolotov + * + * 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 "foldercreationdialog.h" +#include "ui_foldercreationdialog.h" + +#include + +#include +#include + +FolderCreationDialog::FolderCreationDialog(const QString &destination, QWidget *parent) + : QDialog(parent) + , ui(new Ui::FolderCreationDialog) + , _destination(destination) +{ + ui->setupUi(this); + + ui->labelErrorMessage->setVisible(false); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + connect(ui->newFolderNameEdit, &QLineEdit::textChanged, this, &FolderCreationDialog::slotNewFolderNameEditTextEdited); + + const QString suggestedFolderNamePrefix = QObject::tr("New folder"); + + const auto newFolderFullPath = _destination + "/" + suggestedFolderNamePrefix; + if (!QDir(newFolderFullPath).exists()) { + ui->newFolderNameEdit->setText(suggestedFolderNamePrefix); + } else { + for (unsigned int i = 2; i < std::numeric_limits::max(); ++i) { + const QString suggestedPostfix = QString(" (%1)").arg(i); + + if (!QDir(newFolderFullPath + suggestedPostfix).exists()) { + ui->newFolderNameEdit->setText(suggestedFolderNamePrefix + suggestedPostfix); + break; + } + } + } + + ui->newFolderNameEdit->setFocus(); + ui->newFolderNameEdit->selectAll(); +} + +FolderCreationDialog::~FolderCreationDialog() +{ + delete ui; +} + +void FolderCreationDialog::accept() +{ + Q_ASSERT(!_destination.endsWith('/')); + + if (QDir(_destination + "/" + ui->newFolderNameEdit->text()).exists()) { + ui->labelErrorMessage->setVisible(true); + return; + } + + if (!QDir(_destination).mkdir(ui->newFolderNameEdit->text())) { + QMessageBox::critical(this, tr("Error"), tr("Could not create a folder! Check your write permissions.")); + } + + QDialog::accept(); +} + +void FolderCreationDialog::slotNewFolderNameEditTextEdited() +{ + if (!ui->newFolderNameEdit->text().isEmpty() && QDir(_destination + "/" + ui->newFolderNameEdit->text()).exists()) { + ui->labelErrorMessage->setVisible(true); + } else { + ui->labelErrorMessage->setVisible(false); + } +} diff --git a/src/gui/foldercreationdialog.h b/src/gui/foldercreationdialog.h new file mode 100644 index 000000000..c3d219f9a --- /dev/null +++ b/src/gui/foldercreationdialog.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) by Oleksandr Zolotov + * + * 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. + */ + +#ifndef FOLDERCREATIONDIALOG_H +#define FOLDERCREATIONDIALOG_H + +#include + +namespace Ui { +class FolderCreationDialog; +} + +class FolderCreationDialog : public QDialog +{ + Q_OBJECT + +public: + explicit FolderCreationDialog(const QString &destination, QWidget *parent = nullptr); + ~FolderCreationDialog(); + +private slots: + void accept() override; + + void slotNewFolderNameEditTextEdited(); + +private: + Ui::FolderCreationDialog *ui; + + QString _destination; +}; + +#endif // FOLDERCREATIONDIALOG_H diff --git a/src/gui/foldercreationdialog.ui b/src/gui/foldercreationdialog.ui new file mode 100644 index 000000000..87c7a87d0 --- /dev/null +++ b/src/gui/foldercreationdialog.ui @@ -0,0 +1,100 @@ + + + FolderCreationDialog + + + + 0 + 0 + 355 + 138 + + + + Create new folder + + + + + 0 + 90 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 20 + 30 + 321 + 22 + + + + Enter folder name + + + + + true + + + + 20 + 60 + 321 + 16 + + + + color: rgb(255, 0, 0) + + + Folder already exists + + + + + + + buttonBox + accepted() + FolderCreationDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FolderCreationDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/gui/folderstatusmodel.cpp b/src/gui/folderstatusmodel.cpp index d2e906c0e..d66378a16 100644 --- a/src/gui/folderstatusmodel.cpp +++ b/src/gui/folderstatusmodel.cpp @@ -595,8 +595,12 @@ void FolderStatusModel::fetchMore(const QModelIndex &parent) return; info->resetSubs(this, parent); QString path = info->_folder->remotePathTrailingSlash(); - if (info->_path != QLatin1String("/")) { - path += info->_path; + + // info->_path always contains non-mangled name, so we need to use mangled when requesting nested folders for encrypted subfolders as required by LsColJob + const QString infoPath = (info->_isEncrypted && !info->_e2eMangledName.isEmpty()) ? info->_e2eMangledName : info->_path; + + if (infoPath != QLatin1String("/")) { + path += infoPath; } auto *job = new LsColJob(_accountState->account(), path, this); @@ -742,6 +746,15 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list) parentInfo->_folder->journalDb()->getFileRecordByE2eMangledName(removeTrailingSlash(relativePath), &rec); if (rec.isValid()) { newInfo._name = removeTrailingSlash(rec._path).split('/').last(); + if (rec._isE2eEncrypted && !rec._e2eMangledName.isEmpty()) { + // we must use local path for Settings Dialog's filesystem tree, otherwise open and create new folder actions won't work + // hence, we are storing _e2eMangledName separately so it can be use later for LsColJob + newInfo._e2eMangledName = relativePath; + newInfo._path = rec._path; + } + if (!newInfo._path.endsWith('/')) { + newInfo._path += '/'; + } } else { newInfo._name = removeTrailingSlash(relativePath).split('/').last(); } diff --git a/src/gui/folderstatusmodel.h b/src/gui/folderstatusmodel.h index 194e8edf9..39d937f09 100644 --- a/src/gui/folderstatusmodel.h +++ b/src/gui/folderstatusmodel.h @@ -60,8 +60,9 @@ public: struct SubFolderInfo { Folder *_folder = nullptr; - QString _name; - QString _path; + QString _name; // Folder name to be displayed in the UI + QString _path; // Sub-folder path that should always point to a local filesystem's folder + QString _e2eMangledName; // Mangled name that needs to be used when making fetch requests and should not be used for displaying in the UI QVector _pathIdx; QVector _subs; qint64 _size = 0;