Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/owncloud/client.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHannah von Reth <hannah.vonreth@owncloud.com>2022-02-24 16:51:15 +0300
committerFabian Müller <80399010+fmoc@users.noreply.github.com>2022-04-13 17:21:25 +0300
commit6c2a0ea867f75dc36a997b829bdf2424bcb101d5 (patch)
tree372aa7b7f20d483759f2e370b89df22d57a2690a /src
parent4033411ffadb7d9491fafe89a2dc72f47173897e (diff)
Allow to add Folder sync pairs based on spaces
Diffstat (limited to 'src')
-rw-r--r--src/gui/CMakeLists.txt6
-rw-r--r--src/gui/accountsettings.cpp7
-rw-r--r--src/gui/folderstatusdelegate.cpp10
-rw-r--r--src/gui/folderstatusdelegate.h6
-rw-r--r--src/gui/folderstatusmodel.cpp6
-rw-r--r--src/gui/folderwizard/CMakeLists.txt3
-rw-r--r--src/gui/folderwizard/folderwizard.cpp51
-rw-r--r--src/gui/folderwizard/folderwizard.h13
-rw-r--r--src/gui/folderwizard/spacespage.cpp45
-rw-r--r--src/gui/folderwizard/spacespage.h45
-rw-r--r--src/gui/folderwizard/spacespage.ui32
-rw-r--r--src/gui/models/expandingheaderview.cpp4
-rw-r--r--src/gui/spaces/CMakeLists.txt14
-rw-r--r--src/gui/spaces/spacesbrowser.cpp78
-rw-r--r--src/gui/spaces/spacesbrowser.h49
-rw-r--r--src/gui/spaces/spacesbrowser.ui52
-rw-r--r--src/gui/spaces/spacesmodel.cpp147
-rw-r--r--src/gui/spaces/spacesmodel.h55
18 files changed, 597 insertions, 26 deletions
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index c84d7864e..c337c6e36 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -118,7 +118,7 @@ add_subdirectory(folderwizard)
add_library(owncloudCore STATIC ${final_src})
set_target_properties(owncloudCore PROPERTIES AUTOUIC ON AUTORCC ON)
target_link_libraries(owncloudCore PUBLIC Qt5::Widgets Qt5::Network Qt5::Xml
- libsync newwizard folderwizard)
+ libsync newwizard folderwizard spaces)
target_compile_definitions(owncloudCore
PUBLIC QT_USE_QSTRINGBUILDER
QT_MESSAGELOGCONTEXT # enable function name and line number in debug output
@@ -126,6 +126,10 @@ target_compile_definitions(owncloudCore
QT_NO_FOREACH
)
+
+add_subdirectory(spaces)
+
+
add_subdirectory(socketapi)
target_include_directories(owncloudCore PUBLIC
diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp
index 520a8dc5a..c4f111bac 100644
--- a/src/gui/accountsettings.cpp
+++ b/src/gui/accountsettings.cpp
@@ -412,12 +412,14 @@ void AccountSettings::slotAddFolder()
FolderMan *folderMan = FolderMan::instance();
folderMan->setSyncEnabled(false); // do not start more syncs.
- FolderWizard *folderWizard = new FolderWizard(_accountState->account(), this);
+ FolderWizard *folderWizard = new FolderWizard(_accountState->account(), ocApp()->gui()->settingsDialog());
folderWizard->setAttribute(Qt::WA_DeleteOnClose);
+ folderWizard->resize(ocApp()->gui()->settingsDialog()->sizeHintForChild());
connect(folderWizard, &QDialog::accepted, this, &AccountSettings::slotFolderWizardAccepted);
connect(folderWizard, &QDialog::rejected, this, &AccountSettings::slotFolderWizardRejected);
folderWizard->open();
+ ocApp()->gui()->raiseDialog(folderWizard);
}
@@ -428,8 +430,7 @@ void AccountSettings::slotFolderWizardAccepted()
qCInfo(lcAccountSettings) << "Folder wizard completed";
- // TODO: spaces
- auto definition = FolderDefinition::createNewFolderDefinition(_accountState->account()->davUrl());
+ auto definition = FolderDefinition::createNewFolderDefinition(folderWizard->davUrl());
definition.setLocalPath(folderWizard->field(QLatin1String("sourceFolder")).toString());
definition.setTargetPath(folderWizard->property("targetPath").toString());
diff --git a/src/gui/folderstatusdelegate.cpp b/src/gui/folderstatusdelegate.cpp
index a970c4f25..2a8ccf53f 100644
--- a/src/gui/folderstatusdelegate.cpp
+++ b/src/gui/folderstatusdelegate.cpp
@@ -41,9 +41,9 @@ FolderStatusDelegate::FolderStatusDelegate()
{
}
-QString FolderStatusDelegate::addFolderText()
+QString FolderStatusDelegate::addFolderText(bool useSpaces)
{
- return tr("Add Folder Sync Connection");
+ return !useSpaces ? tr("Add Folder Sync Connection") : tr("Add a space");
}
// allocate each item size in listview.
@@ -62,7 +62,7 @@ QSize FolderStatusDelegate::sizeHint(const QStyleOptionViewItem &option,
QFontMetrics fm(qApp->font("QPushButton"));
QStyleOptionButton opt;
static_cast<QStyleOption &>(opt) = option;
- opt.text = addFolderText();
+ opt.text = addFolderText(index.data(FolderStatusDelegate::IsUsingSpaces).toBool());
return QApplication::style()->sizeFromContents(
QStyle::CT_PushButton, &opt, fm.size(Qt::TextSingleLine, opt.text))
.expandedTo(QApplication::globalStrut())
@@ -109,6 +109,8 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
{
QStyledItemDelegate::paint(painter, option, index);
+ const bool useSpaces = index.data(FolderStatusDelegate::IsUsingSpaces).toBool();
+
auto textAlign = Qt::AlignLeft;
QFont aliasFont = makeAliasFont(option.font);
@@ -131,7 +133,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
static_cast<QStyleOption &>(opt) = option;
opt.state &= ~QStyle::State_Selected;
opt.state |= QStyle::State_Raised;
- opt.text = addFolderText();
+ opt.text = addFolderText(useSpaces);
opt.rect.setWidth(qMin(opt.rect.width(), hint.width()));
opt.rect.adjust(0, aliasMargin, 0, -aliasMargin);
opt.rect = QStyle::visualRect(option.direction, option.rect, opt.rect);
diff --git a/src/gui/folderstatusdelegate.h b/src/gui/folderstatusdelegate.h
index 63dc22132..0532974e7 100644
--- a/src/gui/folderstatusdelegate.h
+++ b/src/gui/folderstatusdelegate.h
@@ -47,8 +47,8 @@ public:
AddButton, // 1 = enabled; 2 = disabled
FolderSyncText,
-
- IsReady // boolean
+ IsReady, // boolean
+ IsUsingSpaces // boolean
};
void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override;
QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override;
@@ -62,7 +62,7 @@ public:
static int rootFolderHeightWithoutErrors(const QFontMetrics &fm, const QFontMetrics &aliasFm);
private:
- static QString addFolderText();
+ static QString addFolderText(bool useSapces);
};
} // namespace OCC
diff --git a/src/gui/folderstatusmodel.cpp b/src/gui/folderstatusmodel.cpp
index c7d12e807..788e07bd0 100644
--- a/src/gui/folderstatusmodel.cpp
+++ b/src/gui/folderstatusmodel.cpp
@@ -142,6 +142,10 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
if (role == Qt::EditRole)
return QVariant();
+ // independent of the index
+ if (role == FolderStatusDelegate::IsUsingSpaces) {
+ return _accountState->account()->capabilities().spacesSupport().enabled;
+ }
switch (classify(index)) {
case AddButton: {
if (role == FolderStatusDelegate::AddButton) {
@@ -150,7 +154,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
if (!_accountState->isConnected()) {
return tr("You need to be connected to add a folder");
}
- return tr("Click this button to add a folder to synchronize.");
+ return _accountState->account()->capabilities().spacesSupport().enabled ? tr("Click this button to add a space.") : tr("Click this button to add a folder to synchronize.");
}
return QVariant();
}
diff --git a/src/gui/folderwizard/CMakeLists.txt b/src/gui/folderwizard/CMakeLists.txt
index 8785b39e9..d3089fe66 100644
--- a/src/gui/folderwizard/CMakeLists.txt
+++ b/src/gui/folderwizard/CMakeLists.txt
@@ -2,6 +2,9 @@ add_library(folderwizard OBJECT
folderwizard.cpp
folderwizardsourcepage.ui
folderwizardtargetpage.ui
+
+ spacespage.cpp
+ spacespage.ui
)
target_link_libraries(folderwizard PUBLIC Qt5::Widgets libsync)
diff --git a/src/gui/folderwizard/folderwizard.cpp b/src/gui/folderwizard/folderwizard.cpp
index 160c91e27..b515b0a6b 100644
--- a/src/gui/folderwizard/folderwizard.cpp
+++ b/src/gui/folderwizard/folderwizard.cpp
@@ -17,6 +17,8 @@
#include "ui_folderwizardsourcepage.h"
#include "ui_folderwizardtargetpage.h"
+#include "spacespage.h"
+
#include "account.h"
#include "common/asserts.h"
#include "configfile.h"
@@ -28,6 +30,7 @@
#include "gui/accountstate.h"
#include "gui/folderman.h"
#include "gui/selectivesyncdialog.h"
+#include "gui/spaces/spacesmodel.h"
#include <QCheckBox>
#include <QDesktopServices>
@@ -81,9 +84,6 @@ FolderWizardLocalPath::FolderWizardLocalPath(const AccountPtr &account, QWidget
connect(_ui->localFolderChooseBtn, &QAbstractButton::clicked, this, &FolderWizardLocalPath::slotChooseLocalFolder);
_ui->localFolderChooseBtn->setToolTip(tr("Click to select a local folder to sync."));
- QString defaultPath = QDir::homePath() + QLatin1Char('/') + Theme::instance()->appName();
- defaultPath = FolderMan::instance()->findGoodPathForNewSyncFolder(defaultPath);
- _ui->localFolderLineEdit->setText(QDir::toNativeSeparators(defaultPath));
_ui->localFolderLineEdit->setToolTip(tr("Enter the path to the local folder."));
_ui->warnLabel->setTextFormat(Qt::RichText);
@@ -98,6 +98,7 @@ FolderWizardLocalPath::~FolderWizardLocalPath()
void FolderWizardLocalPath::initializePage()
{
_ui->warnLabel->hide();
+ _ui->localFolderLineEdit->setText(QDir::toNativeSeparators(static_cast<FolderWizard *>(wizard())->destination()));
}
void FolderWizardLocalPath::cleanupPage()
@@ -212,7 +213,7 @@ void FolderWizardRemotePath::slotCreateRemoteFolder(const QString &folder)
fullPath += QLatin1Char('/') + folder;
// TODO: legacy
- MkColJob *job = new MkColJob(_account, _account->davUrl(), fullPath, {}, this);
+ MkColJob *job = new MkColJob(_account, static_cast<FolderWizard *>(wizard())->davUrl(), fullPath, {}, this);
/* check the owncloud configuration file and query the ownCloud */
connect(job, &MkColJob::finishedWithoutError,
this, &FolderWizardRemotePath::slotCreateRemoteFolderFinished);
@@ -327,7 +328,7 @@ bool FolderWizardRemotePath::selectByPath(QString path)
void FolderWizardRemotePath::slotUpdateDirectories(const QStringList &list)
{
- QString webdavFolder = QUrl(_account->davUrl()).path();
+ QString webdavFolder = static_cast<FolderWizard *>(wizard())->davUrl().path();
QTreeWidgetItem *root = _ui->folderTreeWidget->topLevelItem(0);
if (!root) {
@@ -411,8 +412,7 @@ void FolderWizardRemotePath::slotTypedPathFound(const QStringList &subpaths)
LsColJob *FolderWizardRemotePath::runLsColJob(const QString &path)
{
- // TODO: legacy
- LsColJob *job = new LsColJob(_account, _account->davUrl(), path, this);
+ LsColJob *job = new LsColJob(_account, static_cast<FolderWizard *>(wizard())->davUrl(), path, this);
job->setProperties(QList<QByteArray>() << "resourcetype");
connect(job, &LsColJob::directoryListingSubfolders,
this, &FolderWizardRemotePath::slotUpdateDirectories);
@@ -585,19 +585,28 @@ void FolderWizardSelectiveSync::virtualFilesCheckboxClicked()
FolderWizard::FolderWizard(AccountPtr account, QWidget *parent, Qt::WindowFlags flags)
: QWizard(parent, flags)
+ , _account(account)
, _folderWizardSourcePage(new FolderWizardLocalPath(account))
- , _folderWizardTargetPage(nullptr)
, _folderWizardSelectiveSyncPage(new FolderWizardSelectiveSync(account))
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ if (account->capabilities().spacesSupport().enabled) {
+ _spacesPage = new SpacesPage(account, this);
+ setPage(Page_Space, _spacesPage);
+ _spacesPage->installEventFilter(this);
+ }
setPage(Page_Source, _folderWizardSourcePage);
_folderWizardSourcePage->installEventFilter(this);
- if (!Theme::instance()->singleSyncFolder()) {
+ // for now spaces are meant to be synced as a whole
+ if (!account->capabilities().spacesSupport().enabled && !Theme::instance()->singleSyncFolder()) {
_folderWizardTargetPage = new FolderWizardRemotePath(account);
setPage(Page_Target, _folderWizardTargetPage);
_folderWizardTargetPage->installEventFilter(this);
}
- setPage(Page_SelectiveSync, _folderWizardSelectiveSyncPage);
+ if (!account->capabilities().spacesSupport().enabled) {
+ // TODO: add spaces support to selective sync
+ setPage(Page_SelectiveSync, _folderWizardSelectiveSyncPage);
+ }
setWindowTitle(tr("Add Folder Sync Connection"));
setOptions(QWizard::CancelButtonOnLeft);
@@ -609,6 +618,28 @@ FolderWizard::~FolderWizard()
{
}
+QUrl FolderWizard::davUrl() const
+{
+ if (_account->capabilities().spacesSupport().enabled) {
+ auto url = _spacesPage->selectedSpace(Spaces::SpacesModel::Columns::WebDavUrl).toUrl();
+ if (!url.path().endsWith(QLatin1Char('/'))) {
+ url.setPath(url.path() + QLatin1Char('/'));
+ }
+ return url;
+ }
+ return _account->davUrl();
+}
+
+QString FolderWizard::destination() const
+{
+ QString defaultPath = QDir::homePath() + QLatin1Char('/') + Theme::instance()->appName();
+ if (_account->capabilities().spacesSupport().enabled) {
+ // TODO: account whide home
+ defaultPath = QDir::homePath() + QLatin1Char('/') + _spacesPage->selectedSpace(Spaces::SpacesModel::Columns::Name).toString();
+ };
+ return FolderMan::instance()->findGoodPathForNewSyncFolder(defaultPath);
+}
+
bool FolderWizard::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::LayoutRequest) {
diff --git a/src/gui/folderwizard/folderwizard.h b/src/gui/folderwizard/folderwizard.h
index 1cf591ace..c1a9f9485 100644
--- a/src/gui/folderwizard/folderwizard.h
+++ b/src/gui/folderwizard/folderwizard.h
@@ -146,6 +146,7 @@ class FolderWizard : public QWizard
Q_OBJECT
public:
enum {
+ Page_Space,
Page_Source,
Page_Target,
Page_SelectiveSync
@@ -154,13 +155,19 @@ public:
explicit FolderWizard(AccountPtr account, QWidget *parent = nullptr, Qt::WindowFlags flags = {});
~FolderWizard() override;
+ QUrl davUrl() const;
+
+ QString destination() const;
+
bool eventFilter(QObject *watched, QEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
- FolderWizardLocalPath *_folderWizardSourcePage;
- FolderWizardRemotePath *_folderWizardTargetPage;
- FolderWizardSelectiveSync *_folderWizardSelectiveSyncPage;
+ AccountPtr _account;
+ class SpacesPage *_spacesPage;
+ FolderWizardLocalPath *_folderWizardSourcePage = nullptr;
+ FolderWizardRemotePath *_folderWizardTargetPage = nullptr;
+ FolderWizardSelectiveSync *_folderWizardSelectiveSyncPage = nullptr;
};
diff --git a/src/gui/folderwizard/spacespage.cpp b/src/gui/folderwizard/spacespage.cpp
new file mode 100644
index 000000000..e9af3dc39
--- /dev/null
+++ b/src/gui/folderwizard/spacespage.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.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 "spacespage.h"
+#include "ui_spacespage.h"
+
+#include <QModelIndex>
+
+using namespace OCC;
+
+SpacesPage::SpacesPage(AccountPtr acc, QWidget *parent)
+ : QWizardPage(parent)
+ , ui(new Ui::SpacesPage)
+{
+ ui->setupUi(this);
+
+ ui->widget->setAccount(acc);
+
+ connect(ui->widget, &Spaces::SpacesBrowser::selectionChanged, this, &QWizardPage::completeChanged);
+}
+
+SpacesPage::~SpacesPage()
+{
+ delete ui;
+}
+
+bool OCC::SpacesPage::isComplete() const
+{
+ return ui->widget->currentSpace().isValid();
+}
+
+QVariant OCC::SpacesPage::selectedSpace(Spaces::SpacesModel::Columns column) const
+{
+ return ui->widget->currentSpace().siblingAtColumn(static_cast<int>(column)).data();
+}
diff --git a/src/gui/folderwizard/spacespage.h b/src/gui/folderwizard/spacespage.h
new file mode 100644
index 000000000..850c86608
--- /dev/null
+++ b/src/gui/folderwizard/spacespage.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.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 "gui/spaces/spacesmodel.h"
+
+#include "accountfwd.h"
+
+#include <QWizardPage>
+
+
+namespace Ui {
+class SpacesPage;
+}
+
+namespace OCC {
+class SpacesPage : public QWizardPage
+{
+ Q_OBJECT
+
+public:
+ explicit SpacesPage(AccountPtr acc, QWidget *parent = nullptr);
+ ~SpacesPage();
+
+ bool isComplete() const override;
+
+
+ QVariant selectedSpace(Spaces::SpacesModel::Columns column) const;
+
+private:
+ Ui::SpacesPage *ui;
+};
+
+} \ No newline at end of file
diff --git a/src/gui/folderwizard/spacespage.ui b/src/gui/folderwizard/spacespage.ui
new file mode 100644
index 000000000..2a0b44154
--- /dev/null
+++ b/src/gui/folderwizard/spacespage.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SpacesPage</class>
+ <widget class="QWizardPage" name="SpacesPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>362</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>WizardPage</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="OCC::Spaces::SpacesBrowser" name="widget" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>OCC::Spaces::SpacesBrowser</class>
+ <extends>QWidget</extends>
+ <header>gui/spaces/spacesbrowser.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/gui/models/expandingheaderview.cpp b/src/gui/models/expandingheaderview.cpp
index 3457d3f63..7bc5e3fd1 100644
--- a/src/gui/models/expandingheaderview.cpp
+++ b/src/gui/models/expandingheaderview.cpp
@@ -75,5 +75,7 @@ void ExpandingHeaderView::resizeColumns(bool reset)
void ExpandingHeaderView::addResetActionToMenu(QMenu *menu)
{
- menu->addAction(tr("Reset column sizes"), this, [this] { resizeColumns(true); });
+ menu->addAction(tr("Reset column sizes"), this, [this] {
+ resizeColumns(true);
+ });
}
diff --git a/src/gui/spaces/CMakeLists.txt b/src/gui/spaces/CMakeLists.txt
new file mode 100644
index 000000000..8485e7816
--- /dev/null
+++ b/src/gui/spaces/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_library(spaces OBJECT
+ spacesmodel.cpp spacesbrowser.cpp spacesbrowser.ui)
+target_link_libraries(spaces PUBLIC Qt5::Widgets libsync)
+set_target_properties(spaces PROPERTIES AUTOUIC ON AUTORCC ON)
+target_compile_definitions(spaces
+ PRIVATE QT_NO_CAST_TO_ASCII
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_URL_CAST_FROM_STRING
+ QT_NO_CAST_FROM_BYTEARRAY
+ QT_USE_QSTRINGBUILDER
+ QT_MESSAGELOGCONTEXT # enable function name and line number in debug output
+ QT_DEPRECATED_WARNINGS
+ QT_NO_FOREACH
+)
diff --git a/src/gui/spaces/spacesbrowser.cpp b/src/gui/spaces/spacesbrowser.cpp
new file mode 100644
index 000000000..a237bed68
--- /dev/null
+++ b/src/gui/spaces/spacesbrowser.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.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 "spacesbrowser.h"
+#include "ui_spacesbrowser.h"
+
+#include "spacesmodel.h"
+
+#include "graphapi/drives.h"
+
+#include "gui/models/expandingheaderview.h"
+
+#include <QCursor>
+#include <QMenu>
+
+using namespace OCC::Spaces;
+
+SpacesBrowser::SpacesBrowser(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::SpacesBrowser)
+{
+ ui->setupUi(this);
+ _model = new SpacesModel(this);
+ ui->tableView->setModel(_model);
+
+ connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SpacesBrowser::selectionChanged);
+
+ ui->tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ auto header = new OCC::ExpandingHeaderView(QStringLiteral("SpacesBrowserHeader"), ui->tableView);
+ ui->tableView->setHorizontalHeader(header);
+ header->setExpandingColumn(static_cast<int>(SpacesModel::Columns::Name));
+ header->hideSection(static_cast<int>(SpacesModel::Columns::WebDavUrl));
+ // not used yet
+ header->hideSection(static_cast<int>(SpacesModel::Columns::WebUrl));
+ header->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(header, &QHeaderView::customContextMenuRequested, header, [header, this] {
+ auto menu = new QMenu(this);
+ menu->setAttribute(Qt::WA_DeleteOnClose);
+ header->addResetActionToMenu(menu);
+ menu->popup(QCursor::pos());
+ });
+}
+
+SpacesBrowser::~SpacesBrowser()
+{
+ delete ui;
+}
+
+void SpacesBrowser::setAccount(OCC::AccountPtr acc)
+{
+ _acc = acc;
+ if (acc) {
+ QTimer::singleShot(0, this, [this] {
+ auto drive = new OCC::GraphApi::Drives(_acc);
+ connect(drive, &OCC::GraphApi::Drives::finishedSignal, [drive, this] {
+ _model->setData(_acc, drive->drives());
+ show();
+ });
+ drive->start();
+ });
+ }
+}
+
+QModelIndex SpacesBrowser::currentSpace()
+{
+ const auto spaces = ui->tableView->selectionModel()->selectedRows();
+ return spaces.isEmpty() ? QModelIndex {} : spaces.first();
+}
diff --git a/src/gui/spaces/spacesbrowser.h b/src/gui/spaces/spacesbrowser.h
new file mode 100644
index 000000000..12c950339
--- /dev/null
+++ b/src/gui/spaces/spacesbrowser.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.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 "account.h"
+
+#include <QWidget>
+
+namespace Ui {
+class SpacesBrowser;
+}
+
+namespace OCC::Spaces {
+class SpacesModel;
+
+class SpacesBrowser : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit SpacesBrowser(QWidget *parent = nullptr);
+ ~SpacesBrowser();
+
+ void setAccount(OCC::AccountPtr acc);
+
+ QModelIndex currentSpace();
+
+Q_SIGNALS:
+ void selectionChanged();
+
+private:
+ Ui::SpacesBrowser *ui;
+
+ OCC::AccountPtr _acc;
+ SpacesModel *_model;
+};
+
+} \ No newline at end of file
diff --git a/src/gui/spaces/spacesbrowser.ui b/src/gui/spaces/spacesbrowser.ui
new file mode 100644
index 000000000..b4c6fe224
--- /dev/null
+++ b/src/gui/spaces/spacesbrowser.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SpacesBrowser</class>
+ <widget class="QWidget" name="SpacesBrowser">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTableView" name="tableView">
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <attribute name="horizontalHeaderVisible">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/gui/spaces/spacesmodel.cpp b/src/gui/spaces/spacesmodel.cpp
new file mode 100644
index 000000000..924d84384
--- /dev/null
+++ b/src/gui/spaces/spacesmodel.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.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 "spacesmodel.h"
+
+#include "networkjobs.h"
+
+#include <QPixmap>
+
+namespace {
+constexpr QSize ImageSizeC(128, 128);
+}
+
+using namespace OCC::Spaces;
+
+SpacesModel::SpacesModel(QObject *parent)
+ : QAbstractTableModel(parent)
+{
+}
+
+QVariant SpacesModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal) {
+ const auto actionRole = static_cast<Columns>(section);
+ switch (role) {
+ case Qt::DisplayRole:
+ switch (actionRole) {
+ case Columns::Name:
+ return tr("Name");
+ case Columns::Description:
+ return tr("Description");
+ case Columns::WebUrl:
+ return tr("Web URL");
+ case Columns::WebDavUrl:
+ return tr("Web Dav URL");
+ case Columns::Image:
+ return tr("Image");
+ case Columns::ColumnCount:
+ Q_UNREACHABLE();
+ break;
+ }
+ }
+ }
+ return QAbstractTableModel::headerData(section, orientation, role);
+}
+
+int SpacesModel::rowCount(const QModelIndex &parent) const
+{
+ Q_ASSERT(checkIndex(parent));
+ if (parent.isValid())
+ return 0;
+ return static_cast<int>(_data.size());
+}
+
+int SpacesModel::columnCount(const QModelIndex &parent) const
+{
+ Q_ASSERT(checkIndex(parent));
+ if (parent.isValid()) {
+ return 0;
+ }
+ return static_cast<int>(Columns::ColumnCount);
+}
+
+QVariant SpacesModel::data(const QModelIndex &index, int role) const
+{
+ Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid));
+
+ const auto column = static_cast<Columns>(index.column());
+ const auto &item = _data.at(index.row());
+ switch (role) {
+ case Qt::DisplayRole:
+ switch (column) {
+ case Columns::Name:
+ return item.getName();
+ case Columns::Description:
+ return item.getDescription();
+ case Columns::WebUrl:
+ return item.getWebUrl();
+ case Columns::WebDavUrl:
+ return item.getRoot().getWebDavUrl();
+ case Columns::Image: {
+ const auto &special = item.getSpecial();
+ const auto img = std::find_if(special.cbegin(), special.cend(), [](OpenAPI::OAIDriveItem it) {
+ return it.getSpecialFolder().getName() == QLatin1String("image");
+ });
+ return img == special.cend() ? QString() : img->getWebDavUrl();
+ }
+ case Columns::ColumnCount:
+ Q_UNREACHABLE();
+ break;
+ }
+ break;
+ case Qt::DecorationRole:
+ switch (column) {
+ case Columns::Image: {
+ auto it = _images.find(item.getId());
+ if (it != _images.cend()) {
+ return QVariant::fromValue(*it);
+ }
+ const auto imgUrl = data(index, Qt::DisplayRole);
+ if (!imgUrl.isValid()) {
+ return {};
+ }
+ // TODO: placeholder
+ _images[item.getId()] = QPixmap();
+ auto davUrl = QUrl(item.getRoot().getWebDavUrl());
+ auto path = imgUrl.toString().remove(item.getRoot().getWebDavUrl());
+ auto job = new OCC::SimpleNetworkJob(_acc, davUrl, path, "GET", {}, {}, nullptr);
+ connect(job, &OCC::SimpleNetworkJob::finishedSignal, this, [job, id = item.getId(), index, this] {
+ QPixmap img;
+ qDebug() << img.loadFromData(job->reply()->readAll());
+ img = img.scaled(ImageSizeC, Qt::KeepAspectRatio);
+ _images[id] = img;
+ Q_EMIT const_cast<SpacesModel *>(this)->dataChanged(index, index, { Qt::DecorationRole });
+ });
+ job->start();
+ return _images[item.getId()];
+ } break;
+ }
+ case Qt::SizeHintRole: {
+ switch (column) {
+ case Columns::Image: {
+ return ImageSizeC;
+ }
+ }
+ }
+ }
+ return {};
+}
+
+void SpacesModel::setData(OCC::AccountPtr acc, const QList<OpenAPI::OAIDrive> &data)
+{
+ beginResetModel();
+ _acc = acc;
+ _data = data;
+ endResetModel();
+}
diff --git a/src/gui/spaces/spacesmodel.h b/src/gui/spaces/spacesmodel.h
new file mode 100644
index 000000000..8f40cd9e7
--- /dev/null
+++ b/src/gui/spaces/spacesmodel.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.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 "accountfwd.h"
+
+#include <graphapi/drives.h>
+
+#include <QAbstractItemModel>
+
+namespace OCC::Spaces {
+class SpacesModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ enum class Columns {
+ Image,
+ Name,
+ Description,
+ WebUrl,
+ WebDavUrl,
+
+ ColumnCount
+ };
+ Q_ENUM(Columns)
+ explicit SpacesModel(QObject *parent = nullptr);
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+ void setData(OCC::AccountPtr acc, const QList<OpenAPI::OAIDrive> &data);
+
+private:
+ QList<OpenAPI::OAIDrive> _data;
+
+ mutable QMap<QString, QPixmap> _images;
+ OCC::AccountPtr _acc;
+};
+} \ No newline at end of file