From 970b13ab75bdd57631e282792c8a0765414071d0 Mon Sep 17 00:00:00 2001 From: Modspike Date: Tue, 12 May 2026 12:31:02 +0200 Subject: [PATCH 1/3] just added some placeholders for where this is going --- src/gui/CMakeLists.txt | 1 + src/gui/mainwindow/CMakeLists.txt | 7 +++++++ src/gui/mainwindow/mainwindow.cpp | 17 +++++++++++++++++ src/gui/mainwindow/mainwindow.h | 21 +++++++++++++++++++++ src/gui/mainwindow/mainwindowcontroller.cpp | 7 +++++++ src/gui/mainwindow/mainwindowcontroller.h | 12 ++++++++++++ 6 files changed, 65 insertions(+) create mode 100644 src/gui/mainwindow/CMakeLists.txt create mode 100644 src/gui/mainwindow/mainwindow.cpp create mode 100644 src/gui/mainwindow/mainwindow.h create mode 100644 src/gui/mainwindow/mainwindowcontroller.cpp create mode 100644 src/gui/mainwindow/mainwindowcontroller.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 77fb3c3129c..c63e7a250ce 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -118,6 +118,7 @@ add_subdirectory(newaccountwizard) add_subdirectory(socketapi) add_subdirectory(spaces) add_subdirectory(FoldersGui) +add_subdirectory(mainwindow) target_include_directories(owncloudGui PUBLIC ${CMAKE_SOURCE_DIR}/src/3rdparty/QProgressIndicator diff --git a/src/gui/mainwindow/CMakeLists.txt b/src/gui/mainwindow/CMakeLists.txt new file mode 100644 index 00000000000..013e4a2b7aa --- /dev/null +++ b/src/gui/mainwindow/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(owncloudGui PRIVATE + mainwindow.cpp + mainwindow.h + mainwindowcontroller.cpp + mainwindowcontroller.h +) + diff --git a/src/gui/mainwindow/mainwindow.cpp b/src/gui/mainwindow/mainwindow.cpp new file mode 100644 index 00000000000..fd4e912c8f8 --- /dev/null +++ b/src/gui/mainwindow/mainwindow.cpp @@ -0,0 +1,17 @@ +#include "mainwindow.h" + +namespace OCC { +MainWindow::MainWindow() + : QMainWindow{nullptr} +{ +} + +// envisioning: +// the actions for changing the current panel in the main window have a panel id as data +// so the main window controller just needs to find this id in the panel collection and show it. +// building the panel, its controller, and "installing" it on the main window with it's id should be up to +// an application (window) builder so the main window isn't responsible for knowing how many or which panels live in it. +// this is very powerful when it comes to adding or removing guis depending on....stuff. + + +} diff --git a/src/gui/mainwindow/mainwindow.h b/src/gui/mainwindow/mainwindow.h new file mode 100644 index 00000000000..4394670fc13 --- /dev/null +++ b/src/gui/mainwindow/mainwindow.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace OCC { +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit MainWindow(); + +private: + // hash of panel id's to panel widgets. the id is encapsulated in the main window's toolbar and menu actions + // when the window "hears" that an action was triggered, it should just show the widget associated with the + // action's id. + // this will need refinement for the elements that currently run in the "modal" impls - maybe those go away + // completely, no idea yet. but this is a good start so that the main window isn't controlling any of the activities related + // to the panels. they need to control themselves! + QHash _panelLookup; +}; +} diff --git a/src/gui/mainwindow/mainwindowcontroller.cpp b/src/gui/mainwindow/mainwindowcontroller.cpp new file mode 100644 index 00000000000..169bc884949 --- /dev/null +++ b/src/gui/mainwindow/mainwindowcontroller.cpp @@ -0,0 +1,7 @@ +#include "mainwindowcontroller.h" + + +MainWindowController::MainWindowController(QObject *parent) + : QObject{parent} +{ +} diff --git a/src/gui/mainwindow/mainwindowcontroller.h b/src/gui/mainwindow/mainwindowcontroller.h new file mode 100644 index 00000000000..235d9a35112 --- /dev/null +++ b/src/gui/mainwindow/mainwindowcontroller.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +class MainWindowController : public QObject +{ + Q_OBJECT +public: + explicit MainWindowController(QObject *parent = nullptr); + +signals: +}; From ddc3ccf8920ab0bc91bda42a924a85d4a883822e Mon Sep 17 00:00:00 2001 From: Modspike Date: Tue, 12 May 2026 18:29:57 +0200 Subject: [PATCH 2/3] added switch to show new main window new main win is currently empty. To show it uncomment #define USE_NEW_MAIN_WINDOW in owncloudgui.h --- src/gui/application.cpp | 12 ++++ src/gui/application.h | 8 +++ src/gui/folderman.h | 9 +-- src/gui/main.cpp | 3 + src/gui/mainwindow/mainwindow.cpp | 64 +++++++++++++++++++++ src/gui/mainwindow/mainwindow.h | 4 ++ src/gui/mainwindow/mainwindowcontroller.cpp | 2 + src/gui/mainwindow/mainwindowcontroller.h | 4 ++ src/gui/owncloudgui.cpp | 20 +++++-- src/gui/owncloudgui.h | 4 +- src/gui/settingsdialog.cpp | 2 + 11 files changed, 123 insertions(+), 9 deletions(-) diff --git a/src/gui/application.cpp b/src/gui/application.cpp index ebeb1fd290f..d9066728b09 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -24,6 +24,8 @@ #include "configfile.h" #include "folder.h" #include "folderman.h" +#include "mainwindow/mainwindow.h" +#include "mainwindow/mainwindowcontroller.h" #include "settingsdialog.h" #include "socketapi/socketapi.h" #include "theme.h" @@ -90,6 +92,11 @@ Application::Application(Platform *platform, const QString &displayLanguage, boo // setup that follows, like folder setup _gui = new ownCloudGui(this); +#ifdef USE_NEW_MAIN_WINDOW + _mainWin = new MainWindow(); + _mainController = new MainWindowController(this); +#endif + connect(AccountManager::instance(), &AccountManager::accountAdded, this, &Application::slotAccountStateAdded); connect(AccountManager::instance(), &AccountManager::lastAccountRemoved, this, &Application::lastAccountStateRemoved); for (const auto &ai : AccountManager::instance()->accounts()) { @@ -121,6 +128,11 @@ Application::~Application() // Make sure all folders are gone, otherwise removing the // accounts will remove the associated folders from the settings. FolderMan::instance()->unloadAndDeleteAllFolders(); + + if (_mainWin) { + _mainWin->disconnect(); + delete _mainWin; + } } void Application::lastAccountStateRemoved() const diff --git a/src/gui/application.h b/src/gui/application.h index 220038f57af..29772b6668d 100644 --- a/src/gui/application.h +++ b/src/gui/application.h @@ -36,6 +36,8 @@ Q_DECLARE_LOGGING_CATEGORY(lcApplication) class Theme; class Folder; +class MainWindow; +class MainWindowController; /** * @brief The Application class @@ -52,6 +54,9 @@ class OWNCLOUDGUI_EXPORT Application : public QObject ownCloudGui *gui() const; + // try to get rid of this before the end. currently needed to raise the main window via owncloudgui + MainWindow *mainWindow() { return _mainWin; } + QString displayLanguage() const; /** @@ -77,6 +82,9 @@ protected Q_SLOTS: QPointer _gui = {}; + MainWindow *_mainWin = nullptr; + MainWindowController *_mainController = nullptr; + const bool _debugMode = false; QString _displayLanguage; diff --git a/src/gui/folderman.h b/src/gui/folderman.h index d9d266fc135..2222e35c663 100644 --- a/src/gui/folderman.h +++ b/src/gui/folderman.h @@ -335,6 +335,11 @@ public Q_SLOTS: void removeFolderFromGui(Folder *f); void forceFolderSync(Folder *f); + // this was private which then required Application be a friend of FolderMan... + // I am not sure why the Application seems to be the "master" minder of account manager signals + // but I think this will soon change + void slotServerVersionChanged(Account *account); + private Q_SLOTS: void slotFolderSyncPauseChanged(Folder *, bool paused); @@ -344,8 +349,6 @@ private Q_SLOTS: void slotRemoveFoldersForAccount(AccountState *accountState); - void slotServerVersionChanged(Account *account); - // saves folder using an internally created QSettings instance. This is used for "one off" persistence operations // that should be synced immediately - eg when the user adds a new folder sync from the gui or as slot to eg persist a property // change @@ -510,8 +513,6 @@ private Q_SLOTS: // set when they are paused/resumed but aside from that we don't really do anything with it. QSet _disabledFolders; - friend class OCC::Application; - // the literal is needed to get the tests to build inline static const QString IgnoreHiddenFilesKey = QStringLiteral("ignoreHiddenFiles"); void scheduleFoldersForAccount(const QUuid &accountId); diff --git a/src/gui/main.cpp b/src/gui/main.cpp index b0c6ca1a754..f29925298eb 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -437,6 +437,9 @@ int main(int argc, char **argv) return -1; } + // I think this could/should just be a local instance that just naturally goes out of scope. this will take some time though, + // as it's a singleton :/ + // good news is that it's mostly used to handle the main window "modal" impls which will likely change or even go away soon-ish auto ocApp = Application::createInstance(platform.get(), displayLanguage, options.debugMode); ocApp->updateAutoRun(firstRun); diff --git a/src/gui/mainwindow/mainwindow.cpp b/src/gui/mainwindow/mainwindow.cpp index fd4e912c8f8..8eeafb59615 100644 --- a/src/gui/mainwindow/mainwindow.cpp +++ b/src/gui/mainwindow/mainwindow.cpp @@ -1,11 +1,75 @@ #include "mainwindow.h" +#include + +#include "configfile.h" +#include "theme.h" + +#ifdef Q_OS_MAC +#include "settingsdialog_mac.h" +void setActivationPolicy(ActivationPolicy policy); +#endif + namespace OCC { MainWindow::MainWindow() : QMainWindow{nullptr} { + // required as group for saveGeometry call. the original name is "Settings" so we should factor this in + // and make sure we either accept that previous geometry is lost between upgrade/downgrades OR put the name back to Settings + // which imo is a terrible name but we could save the rename til next major version. + // in reality the stored geometry is just the size afaik but will double check. If we had user editable docking positions, + // subwidgets that can run along side the main window, etc. the stored geometry would be more important for user happiness. + setObjectName(QStringLiteral("MainWindow")); + setWindowTitle(Theme::instance()->appNameGUI()); + + setMinimumSize(minimumSizeHint()); + + // People perceive this as a Window, so also make Ctrl+W work + addAction(tr("Hide"), Qt::CTRL | Qt::Key_W, this, &MainWindow::hide); + + ConfigFile().restoreGeometry(this); +#ifdef Q_OS_MAC + setActivationPolicy(ActivationPolicy::Accessory); +#endif } +QSize MainWindow::minimumSizeHint() const +{ + const QSize min{800, 700}; // When changing this, please check macOS: widgets there have larger insets, so they take up more space. + const auto screen = windowHandle() ? windowHandle()->screen() : QApplication::screenAt(QCursor::pos()); + if (screen) { + const auto availableSize = screen->availableSize(); + if (availableSize.isValid()) { + // Assume we can use at least 90% of the screen, if the screen is smaller than 800x700 pixels. + // + // Note: this means that the wizards have even less space: with the style we use, the + // wizard tries to fit inside the window. So, if this is a common case that users have + // such small screens, and the contents of the wizard screen are squashed together (or + // not shown due to lack of space), we should consider putting that content in a + // scroll-view. + return min.boundedTo(availableSize * 0.9); + } + } + return min; +} + +void MainWindow::setVisible(bool visible) +{ + if (!visible) { + ConfigFile cfg; + cfg.saveGeometry(this); + } + +#ifdef Q_OS_MAC + if (visible) { + setActivationPolicy(ActivationPolicy::Regular); + } else { + setActivationPolicy(ActivationPolicy::Accessory); + } +#endif + + QMainWindow::setVisible(visible); +} // envisioning: // the actions for changing the current panel in the main window have a panel id as data // so the main window controller just needs to find this id in the panel collection and show it. diff --git a/src/gui/mainwindow/mainwindow.h b/src/gui/mainwindow/mainwindow.h index 4394670fc13..fe02840d26c 100644 --- a/src/gui/mainwindow/mainwindow.h +++ b/src/gui/mainwindow/mainwindow.h @@ -9,6 +9,10 @@ class MainWindow : public QMainWindow public: explicit MainWindow(); + QSize minimumSizeHint() const override; + + void setVisible(bool visible) override; + private: // hash of panel id's to panel widgets. the id is encapsulated in the main window's toolbar and menu actions // when the window "hears" that an action was triggered, it should just show the widget associated with the diff --git a/src/gui/mainwindow/mainwindowcontroller.cpp b/src/gui/mainwindow/mainwindowcontroller.cpp index 169bc884949..dbc80ec12c5 100644 --- a/src/gui/mainwindow/mainwindowcontroller.cpp +++ b/src/gui/mainwindow/mainwindowcontroller.cpp @@ -1,7 +1,9 @@ #include "mainwindowcontroller.h" +namespace OCC { MainWindowController::MainWindowController(QObject *parent) : QObject{parent} { } +} diff --git a/src/gui/mainwindow/mainwindowcontroller.h b/src/gui/mainwindow/mainwindowcontroller.h index 235d9a35112..da38b715464 100644 --- a/src/gui/mainwindow/mainwindowcontroller.h +++ b/src/gui/mainwindow/mainwindowcontroller.h @@ -2,6 +2,8 @@ #include +namespace OCC { + class MainWindowController : public QObject { Q_OBJECT @@ -10,3 +12,5 @@ class MainWindowController : public QObject signals: }; + +} diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index dac2ad47fa3..48867572f91 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -26,6 +26,7 @@ #include "guiutility.h" #include "libsync/theme.h" #include "logbrowser.h" +#include "mainwindow/mainwindow.h" #include "progressdispatcher.h" #include "settingsdialog.h" @@ -65,11 +66,14 @@ SyncResult::Status trayOverallStatus() ownCloudGui::ownCloudGui(Application *parent) : QObject(parent) , _tray(new QSystemTrayIcon(this)) - , _settingsDialog(new SettingsDialog(this)) + // , _settingsDialog(new SettingsDialog(this)) , _app(parent) { - connect(_tray, &QSystemTrayIcon::activated, - this, &ownCloudGui::slotTrayClicked); +#ifndef USE_NEW_MAIN_WINDOW + _settingsDialog = new SettingsDialog(this); +#endif + + connect(_tray, &QSystemTrayIcon::activated, this, &ownCloudGui::slotTrayClicked); setupTrayContextMenu(); @@ -285,7 +289,15 @@ void ownCloudGui::slotHelp() void ownCloudGui::raise() { - auto window = ocApp()->gui()->settingsDialog(); + // auto window = ocApp()->gui()->settingsDialog(); + QMainWindow *window; +#ifdef USE_NEW_MAIN_WINDOW + window = ocApp()->mainWindow(); +#else + // no we can't just use the member because this function apparently "has" to be static? + // if this is the case it would make more sense to move it to Application since it should own the main window + window = ocApp()->gui()->settingsDialog(); +#endif window->show(); window->raise(); window->activateWindow(); diff --git a/src/gui/owncloudgui.h b/src/gui/owncloudgui.h index 4e257f3a5b8..4567f8f16b0 100644 --- a/src/gui/owncloudgui.h +++ b/src/gui/owncloudgui.h @@ -23,6 +23,8 @@ #include #include +// #define USE_NEW_MAIN_WINDOW + namespace OCC { namespace Wizard { @@ -93,7 +95,7 @@ public Q_SLOTS: QIcon getTrayStatusIcon(const SyncResult::Status &status) const; QSystemTrayIcon *_tray; - SettingsDialog *_settingsDialog; + SettingsDialog *_settingsDialog = nullptr; QPointer _shareDialog; Application *_app; diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index 645e09ed3c5..5617643d054 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -128,6 +128,8 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) setActivationPolicy(ActivationPolicy::Accessory); #endif + // todo + // I don't see the point here insofar as I can't find any panels that change the app title connect(_ui->dialogStack, &QStackedWidget::currentChanged, this, [this] { auto *w = _ui->dialogStack->currentWidget(); if (!w->windowTitle().isEmpty()) { From 54b78d110bf26d4454497fa435e8bdd4b42808e9 Mon Sep 17 00:00:00 2001 From: Modspike Date: Wed, 13 May 2026 18:37:03 +0200 Subject: [PATCH 3/3] started the more menu button impl fleshing out the new MainWindow and MainWindowController to replace old stuff --- src/gui/CMakeLists.txt | 4 +- src/gui/accountmodalwidget.h | 5 ++ src/gui/accountsgui/CMakeLists.txt | 7 +++ src/gui/accountsgui/accountsguicontroller.cpp | 10 ++++ src/gui/accountsgui/accountsguicontroller.h | 13 ++++ src/gui/{ => accountsgui}/accountview.cpp | 4 ++ src/gui/{ => accountsgui}/accountview.h | 0 src/gui/{ => accountsgui}/accountview.ui | 0 src/gui/application.cpp | 2 +- src/gui/creds/credentials.cpp | 5 ++ .../creds/requestauthenticationcontroller.cpp | 2 +- src/gui/mainwindow/mainwindow.cpp | 55 ++++++++++++++++- src/gui/mainwindow/mainwindow.h | 15 +++++ src/gui/mainwindow/mainwindowcontroller.cpp | 59 ++++++++++++++++++- src/gui/mainwindow/mainwindowcontroller.h | 15 ++++- src/gui/owncloudgui.cpp | 6 +- src/gui/owncloudgui.h | 2 +- src/gui/settingsdialog.cpp | 2 +- 18 files changed, 194 insertions(+), 12 deletions(-) create mode 100644 src/gui/accountsgui/CMakeLists.txt create mode 100644 src/gui/accountsgui/accountsguicontroller.cpp create mode 100644 src/gui/accountsgui/accountsguicontroller.h rename src/gui/{ => accountsgui}/accountview.cpp (97%) rename src/gui/{ => accountsgui}/accountview.h (100%) rename src/gui/{ => accountsgui}/accountview.ui (100%) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index c63e7a250ce..c2d3d35cc8c 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -12,13 +12,12 @@ set(client_UI_SRCS settingsdialog.ui tlserrordialog.ui logbrowser.ui - accountview.ui + accountsgui/accountview.ui ) set(client_SRCS aboutdialog.cpp accountmanager.cpp - accountview.cpp accountmodalwidget.cpp accountmodalwidget.ui @@ -119,6 +118,7 @@ add_subdirectory(socketapi) add_subdirectory(spaces) add_subdirectory(FoldersGui) add_subdirectory(mainwindow) +add_subdirectory(accountsgui) target_include_directories(owncloudGui PUBLIC ${CMAKE_SOURCE_DIR}/src/3rdparty/QProgressIndicator diff --git a/src/gui/accountmodalwidget.h b/src/gui/accountmodalwidget.h index ebd2fe59083..df48874f852 100644 --- a/src/gui/accountmodalwidget.h +++ b/src/gui/accountmodalwidget.h @@ -24,6 +24,11 @@ namespace Ui { class AccountModalWidget; } +// this class is basically a "wrapper" that hosts a widget/panel that we want to run in a modal concept. +// basically it adds a title to the given widget, and provides buttons (normally ok/cancel) that control the lifetime of +// the "modality" +// the class is used in the AccountView with account related stuff +// it's basically a reproduction of a modal dialog but it's embedded in the account view of the main window. class AccountModalWidget : public QWidget { Q_OBJECT diff --git a/src/gui/accountsgui/CMakeLists.txt b/src/gui/accountsgui/CMakeLists.txt new file mode 100644 index 00000000000..c913a149e90 --- /dev/null +++ b/src/gui/accountsgui/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(owncloudGui PRIVATE + accountsguicontroller.cpp + accountsguicontroller.h + accountview.cpp + accountview.h +) + diff --git a/src/gui/accountsgui/accountsguicontroller.cpp b/src/gui/accountsgui/accountsguicontroller.cpp new file mode 100644 index 00000000000..250277d5c21 --- /dev/null +++ b/src/gui/accountsgui/accountsguicontroller.cpp @@ -0,0 +1,10 @@ +#include "accountsguicontroller.h" + +namespace OCC { + +AccountsGuiController::AccountsGuiController(QObject *parent) + : QObject(parent) +{ +} + +} diff --git a/src/gui/accountsgui/accountsguicontroller.h b/src/gui/accountsgui/accountsguicontroller.h new file mode 100644 index 00000000000..2e659513898 --- /dev/null +++ b/src/gui/accountsgui/accountsguicontroller.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace OCC { +class AccountsGuiController : public QObject +{ + Q_OBJECT + +public: + AccountsGuiController(QObject *parent); +}; +} diff --git a/src/gui/accountview.cpp b/src/gui/accountsgui/accountview.cpp similarity index 97% rename from src/gui/accountview.cpp rename to src/gui/accountsgui/accountview.cpp index 4cd2a1785da..bdad0bee3d2 100644 --- a/src/gui/accountview.cpp +++ b/src/gui/accountsgui/accountview.cpp @@ -349,6 +349,10 @@ void AccountView::onRequestAccountModalWidget(OCC::AccountModalWidget *widget) addModalAccountWidget(widget); } +// notes to self: the "modal" stuff is in this direction: the accountView sometimes wants to show something in a manner +// that users should finish the activity. The accountview shows the gui the user should interact with, but it has to ask the +// main window layer to block other user activity in the meantime. I think conceptually it's ok but the impl needs to be +// simplified, especially to get rid of the legacy vs non legacy impls void AccountView::addModalAccountWidget(AccountModalWidget *widget) { if (!_accountState || !_accountState->account()) { diff --git a/src/gui/accountview.h b/src/gui/accountsgui/accountview.h similarity index 100% rename from src/gui/accountview.h rename to src/gui/accountsgui/accountview.h diff --git a/src/gui/accountview.ui b/src/gui/accountsgui/accountview.ui similarity index 100% rename from src/gui/accountview.ui rename to src/gui/accountsgui/accountview.ui diff --git a/src/gui/application.cpp b/src/gui/application.cpp index d9066728b09..141ea1dcb6a 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -94,7 +94,7 @@ Application::Application(Platform *platform, const QString &displayLanguage, boo #ifdef USE_NEW_MAIN_WINDOW _mainWin = new MainWindow(); - _mainController = new MainWindowController(this); + _mainController = new MainWindowController(_mainWin, this); #endif connect(AccountManager::instance(), &AccountManager::accountAdded, this, &Application::slotAccountStateAdded); diff --git a/src/gui/creds/credentials.cpp b/src/gui/creds/credentials.cpp index fc130016cef..fa1940705bd 100644 --- a/src/gui/creds/credentials.cpp +++ b/src/gui/creds/credentials.cpp @@ -309,6 +309,11 @@ void Credentials::askFromUser() // the widget is parented to the AccountModalWidget when it's installed in the main window. // it will be cleaned up there - this is not a leak + // todo dc-300 : this needs to be handled as a "request" to show the gui. The creds are known to the Account + // the account view (or accountsguicontroller, more likely) should be able to connect auth request related signals + // between the account gui and the creds. + // essential to remember though, is that this auth widget is essentially a credentials editor. + // put a pin in it RequestAuthenticationWidget *widget = new RequestAuthenticationWidget(); _requestAuth = new RequestAuthenticationController(widget, this); // we should not connect to the failed signal as we are forcing the user to make the decision using the gui. diff --git a/src/gui/creds/requestauthenticationcontroller.cpp b/src/gui/creds/requestauthenticationcontroller.cpp index 6e9fdca8863..1c039ada16e 100644 --- a/src/gui/creds/requestauthenticationcontroller.cpp +++ b/src/gui/creds/requestauthenticationcontroller.cpp @@ -13,7 +13,7 @@ */ #include "requestauthenticationcontroller.h" -#include "accountview.h" +#include "accountsgui/accountview.h" #include "application.h" #include "requestauthenticationwidget.h" diff --git a/src/gui/mainwindow/mainwindow.cpp b/src/gui/mainwindow/mainwindow.cpp index 8eeafb59615..b1412d6ca66 100644 --- a/src/gui/mainwindow/mainwindow.cpp +++ b/src/gui/mainwindow/mainwindow.cpp @@ -1,6 +1,9 @@ #include "mainwindow.h" #include +#include +#include +#include #include "configfile.h" #include "theme.h" @@ -22,8 +25,6 @@ MainWindow::MainWindow() setObjectName(QStringLiteral("MainWindow")); setWindowTitle(Theme::instance()->appNameGUI()); - setMinimumSize(minimumSizeHint()); - // People perceive this as a Window, so also make Ctrl+W work addAction(tr("Hide"), Qt::CTRL | Qt::Key_W, this, &MainWindow::hide); @@ -31,6 +32,56 @@ MainWindow::MainWindow() #ifdef Q_OS_MAC setActivationPolicy(ActivationPolicy::Accessory); #endif + + buildWindow(); +} + +void MainWindow::buildWindow() +{ + // clang is complaining that call to minimumSizeHint bypasses virtual dispatch, but I'm not seeing any problem. + // the link to docs for that warning = 404 :D + // regardless, the evaluation is misleading as according to c++ standard, calling a virtual function in a ctr is guaranteed to + // call the override for the class being constructed. There is no problem here. + // this is part of the reason we have tidy turned off - it's a bit too touchy. + // question is, why is tidy butting in if we have it turned off? Figure this out later. + setMinimumSize(minimumSizeHint()); + + _toolbar = new QToolBar(this); + _toolbar->setObjectName("mainWindowToolbar"); + _toolbar->setMovable(false); + _toolbar->setAccessibleDescription(tr("Main toolbar for the application")); + _toolbar->setAccessibleName(tr("Main toolbar")); + addToolBar(_toolbar); + + QWidget *toolbarStretch = new QWidget(this); + // who knows, maybe someday we use the toolbar vertically + toolbarStretch->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _toolbar->addWidget(toolbarStretch); + + _toolbar->addSeparator(); + + _moreButton = new QToolButton(this); + _moreButton->setText("⋯"); + // _moreButton->setToolButtonStyle(Qt::ToolButtonTextOnly); + _moreButton->setPopupMode(QToolButton::InstantPopup); + _toolbar->addWidget(_moreButton); + + _widgetStack = new QStackedWidget(this); + setCentralWidget(_widgetStack); +} + +void MainWindow::setMoreMenuActions(const QList &actions) +{ + _moreButton->addActions(actions); +} + +void MainWindow::showModalWidget(QWidget *w) +{ + // ownCloudGui::raise(); + if (_widgetStack->indexOf(w) == -1) { + _widgetStack->addWidget(w); + _widgetStack->setCurrentWidget(w); + } } QSize MainWindow::minimumSizeHint() const diff --git a/src/gui/mainwindow/mainwindow.h b/src/gui/mainwindow/mainwindow.h index fe02840d26c..8dc4a575d1c 100644 --- a/src/gui/mainwindow/mainwindow.h +++ b/src/gui/mainwindow/mainwindow.h @@ -2,6 +2,10 @@ #include +class QToolBar; +class QToolButton; +class QStackedWidget; + namespace OCC { class MainWindow : public QMainWindow { @@ -13,7 +17,18 @@ class MainWindow : public QMainWindow void setVisible(bool visible) override; + void setMoreMenuActions(const QList &actions); + + void showModalWidget(QWidget *w); + private: + void buildWindow(); + + QToolBar *_toolbar = nullptr; + QStackedWidget *_widgetStack = nullptr; + + QToolButton *_moreButton = nullptr; + // hash of panel id's to panel widgets. the id is encapsulated in the main window's toolbar and menu actions // when the window "hears" that an action was triggered, it should just show the widget associated with the // action's id. diff --git a/src/gui/mainwindow/mainwindowcontroller.cpp b/src/gui/mainwindow/mainwindowcontroller.cpp index dbc80ec12c5..2457fe5911e 100644 --- a/src/gui/mainwindow/mainwindowcontroller.cpp +++ b/src/gui/mainwindow/mainwindowcontroller.cpp @@ -1,9 +1,66 @@ #include "mainwindowcontroller.h" +#include "aboutdialog.h" +#include "mainwindow.h" +#include "theme.h" + +#include +#include +#include + namespace OCC { -MainWindowController::MainWindowController(QObject *parent) +MainWindowController::MainWindowController(MainWindow *window, QObject *parent) : QObject{parent} + , _window(window) +{ + setup(); +} + +void MainWindowController::setup() +{ + buildMenuActions(); +} + +void MainWindowController::buildMenuActions() +{ + QList menuActions; + + QAction *aboutAction = new QAction(tr("About..."), this); + aboutAction->setObjectName("aboutAction"); + connect(aboutAction, &QAction::triggered, this, &MainWindowController::onAbout); + menuActions.push_back(aboutAction); + + QAction *separator = new QAction(this); + separator->setObjectName("sparatorAction"); + separator->setSeparator(true); + menuActions.push_back(separator); + + QAction *quitAction = new QAction(tr("Quit"), this); + quitAction->setObjectName("quitAction"); + connect(quitAction, &QAction::triggered, this, &MainWindowController::onQuit); + menuActions.push_back(quitAction); + _window->setMoreMenuActions(menuActions); +} + +void MainWindowController::onAbout() +{ + AboutDialog *aboutDialog = new AboutDialog(_window); + aboutDialog->setAttribute(Qt::WA_DeleteOnClose); + _window->showModalWidget(aboutDialog); +} + +void MainWindowController::onQuit() { + // this is just copied/pasted from the original - most likely will change this to a simple dialog exec, then we + // don't need any delayed handling of the actual call to app quit + auto box = new QMessageBox(QMessageBox::Question, tr("Quit %1").arg(Theme::instance()->appNameGUI()), + tr("Are you sure you want to quit %1?").arg(Theme::instance()->appNameGUI()), QMessageBox::Yes | QMessageBox::No, _window); + box->setAttribute(Qt::WA_DeleteOnClose); + connect(box, &QMessageBox::accepted, this, [] { + // delay quit to prevent a Qt 6.6 crash in the destructor of the dialog + QTimer::singleShot(0, qApp, &QCoreApplication::quit); + }); + box->open(); } } diff --git a/src/gui/mainwindow/mainwindowcontroller.h b/src/gui/mainwindow/mainwindowcontroller.h index da38b715464..15861531ecf 100644 --- a/src/gui/mainwindow/mainwindowcontroller.h +++ b/src/gui/mainwindow/mainwindowcontroller.h @@ -4,13 +4,24 @@ namespace OCC { +class MainWindow; + class MainWindowController : public QObject { Q_OBJECT public: - explicit MainWindowController(QObject *parent = nullptr); + explicit MainWindowController(MainWindow *window, QObject *parent = nullptr); + + // public for now + void setup(); + +private: + void buildMenuActions(); + + void onAbout(); + void onQuit(); -signals: + MainWindow *_window = nullptr; }; } diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index 48867572f91..3875e2d9839 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -267,11 +267,15 @@ void ownCloudGui::slotShowSettings() void ownCloudGui::slotShutdown() { + // with the new mainWindow the geometry is autosaved without this shutdown routine + // todo: dc-300 or soon after, get rid of this whole function + // explicitly close windows. This is somewhat of a hack to ensure // that saving the geometries happens ASAP during an OS shutdown // those do delete on close - _settingsDialog->close(); + if (_settingsDialog) + _settingsDialog->close(); } void ownCloudGui::slotToggleLogBrowser() diff --git a/src/gui/owncloudgui.h b/src/gui/owncloudgui.h index 4567f8f16b0..9ab74354138 100644 --- a/src/gui/owncloudgui.h +++ b/src/gui/owncloudgui.h @@ -23,7 +23,7 @@ #include #include -// #define USE_NEW_MAIN_WINDOW +#define USE_NEW_MAIN_WINDOW namespace OCC { diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index 5617643d054..c94f87d2211 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -16,7 +16,7 @@ #include "ui_settingsdialog.h" #include "accountmanager.h" -#include "accountview.h" +#include "accountsgui/accountview.h" #include "activitysettings.h" #include "application.h" #include "configfile.h"