diff --git a/CMakeLists.txt b/CMakeLists.txt index c6b9825..34ba82b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,8 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED DocTools ) +find_package(PolkitQt5-1 REQUIRED) + # use sane compile flags add_definitions( -DQT_USE_QSTRINGBUILDER diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ef4502..0e6151a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,6 +38,7 @@ target_link_libraries(partitionmanager ${BLKID_LIBRARIES} KF5::KIOWidgets KF5::WidgetsAddons KF5::XmlGui + PolkitQt5-1::Core ) target_compile_definitions(partitionmanager PRIVATE -DCMAKE_INSTALL_FULL_LIBEXECDIR_KF5=\"${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}\") diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 97357d8..987c99c 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -54,6 +54,8 @@ #include #include +#include + #include #include #include @@ -70,6 +72,9 @@ #include #include +#include +#include + #include #include #include @@ -126,10 +131,67 @@ void MainWindow::init() loadConfig(); + // this is done in order to hide the title bar of MessageWidget dock + findChild(QStringLiteral("MessageWidgetDock"))->setTitleBarWidget(new QWidget()); + + MessageWidget().hide(); + MessageWidget().setText( + i18nc("@info", "Partition Manager requires privileges in order to work. Please refresh the devices and authenticate when prompted.")); + show(); pmWidget().init(&operationStack()); - scanDevices(); + scanProgressDialog().cancel(); + setEnabled(false); + guiFactory()->container(QStringLiteral("selectedDevice"), this)->setEnabled(false); + + askForPermissions(); + + if (m_permissionGranted) { + FileSystemFactory::init(); + scanDevices(); + } else + Q_EMIT showMessageWidget(); + + setEnabled(true); +} + +void MainWindow::askForPermissions() +{ + PolkitQt1::UnixProcessSubject subject(QApplication::applicationPid()); + PolkitQt1::Authority *authority = PolkitQt1::Authority::instance(); + + PolkitQt1::Authority::Result result; + QEventLoop e; + connect(authority, &PolkitQt1::Authority::checkAuthorizationFinished, &e, + [&e, &result](PolkitQt1::Authority::Result _result) { + result = _result; + e.quit(); + }); + + authority->checkAuthorization(QStringLiteral("org.kde.kpmcore.externalcommand.init"), subject, PolkitQt1::Authority::AllowUserInteraction); + e.exec(); + + if (authority->hasError()) { + qDebug() << "Encountered error while checking authorization, error code:" + << authority->lastError() << authority->errorDetails(); + authority->clearError(); + } + + m_permissionGranted = result == PolkitQt1::Authority::Yes; +} + +QMenu *MainWindow::createPopupMenu() +{ + auto menu = QMainWindow::createPopupMenu(); + auto actions = menu->actions(); + QAction *toRemove = + *std::find_if(actions.begin(), actions.end(), + [](QAction *x) { return x->text().isEmpty(); }); + // this is done in order to hide the entry for the MessageWidget dock + menu->removeAction(toRemove); + + return menu; } void MainWindow::closeEvent(QCloseEvent* event) @@ -409,6 +471,7 @@ void MainWindow::setupActions() refreshDevices->setStatusTip(xi18nc("@info:status", "Renew the devices list.")); actionCollection()->setDefaultShortcut(refreshDevices, Qt::Key_F5); refreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); + MessageWidget().addAction(refreshDevices); // Settings Actions actionCollection()->addAction(QStringLiteral("toggleDockDevices"), dockDevices().toggleViewAction()); @@ -459,6 +522,11 @@ void MainWindow::setupConnections() connect(GlobalLog::instance(), &GlobalLog::newMessage, &treeLog(), &TreeLog::onNewLogMessage); + + connect(this, &MainWindow::showMessageWidget, &MessageWidget(), + &KMessageWidget::animatedShow); + connect(this, &MainWindow::hideMessageWidget, &MessageWidget(), + &KMessageWidget::animatedHide); } void MainWindow::setupStatusBar() @@ -741,7 +809,13 @@ void MainWindow::on_m_DeviceScanner_finished() scanProgressDialog().setProgress(100); - if (!operationStack().previewDevices().isEmpty()) + bool foundDevices = !operationStack().previewDevices().isEmpty(); + + guiFactory() + ->container(QStringLiteral("selectedDevice"), this) + ->setEnabled(foundDevices); + + if (foundDevices) pmWidget().setSelectedDevice(operationStack().previewDevices()[0]); pmWidget().updatePartitions(); @@ -751,7 +825,7 @@ void MainWindow::on_m_DeviceScanner_finished() // try to set the seleted device, either from the saved one or just select the // first device - if (!listDevices().setSelectedDevice(savedSelectedDeviceNode()) && !operationStack().previewDevices().isEmpty()) + if (!listDevices().setSelectedDevice(savedSelectedDeviceNode()) && foundDevices) listDevices().setSelectedDevice(operationStack().previewDevices()[0]->deviceNode()); updateSeletedDeviceMenu(); @@ -815,7 +889,17 @@ void MainWindow::onRefreshDevices() xi18nc("@title:window", "Really Rescan the Devices?"), KGuiItem(xi18nc("@action:button", "Rescan Devices"), QStringLiteral("arrow-right")), KStandardGuiItem::cancel(), QStringLiteral("reallyRescanDevices")) == KMessageBox::Continue) { - scanDevices(); + + if (m_permissionGranted) { + scanDevices(); + } else { + askForPermissions(); + if (m_permissionGranted) { + Q_EMIT hideMessageWidget(); + FileSystemFactory::init(); + scanDevices(); + } + } } } diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index a1954e0..df43bed 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -17,6 +17,7 @@ #include "ui_mainwindowbase.h" +#include #include class ApplyProgressDialog; @@ -206,6 +207,15 @@ protected: return *m_ScanProgressDialog; } + KMessageWidget &MessageWidget() { + Q_ASSERT(m_MessageWidget); + return *m_MessageWidget; + } + const KMessageWidget &MessageWidget() const { + Q_ASSERT(m_MessageWidget); + return *m_MessageWidget; + } + void onSelectedDeviceMenuTriggered(bool); protected Q_SLOTS: @@ -255,6 +265,15 @@ protected: void onSmartStatusDevice(); void onPropertiesDevice(const QString& deviceNode = {}); +private: + QMenu* createPopupMenu() override; + + void askForPermissions(); + +Q_SIGNALS: + void showMessageWidget(); + void hideMessageWidget(); + private: OperationStack* m_OperationStack; OperationRunner* m_OperationRunner; @@ -263,6 +282,8 @@ private: ScanProgressDialog* m_ScanProgressDialog; QLabel* m_StatusText; QString m_SavedSelectedDeviceNode; + + bool m_permissionGranted; }; #endif diff --git a/src/gui/mainwindowbase.ui b/src/gui/mainwindowbase.ui index a5cf231..74b77e9 100644 --- a/src/gui/mainwindowbase.ui +++ b/src/gui/mainwindowbase.ui @@ -17,8 +17,7 @@ SPDX-License-Identifier: GPL-3.0-or-later KDE Partition Manager - - + Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea @@ -29,8 +28,7 @@ SPDX-License-Identifier: GPL-3.0-or-later 1 - - + @@ -42,8 +40,7 @@ SPDX-License-Identifier: GPL-3.0-or-later 8 - - + @@ -52,8 +49,7 @@ SPDX-License-Identifier: GPL-3.0-or-later 1 - - + @@ -65,11 +61,34 @@ SPDX-License-Identifier: GPL-3.0-or-later 8 - + + + + + + 0 + 0 + + + + QDockWidget::NoDockWidgetFeatures + + + 4 + + + + KMessageWidget::Warning + + + KMessageWidget + QFrame +
kmessagewidget.h
+
PartitionManagerWidget QWidget diff --git a/src/gui/partitionmanagerwidget.cpp b/src/gui/partitionmanagerwidget.cpp index d7a0c1e..a2a8ae0 100644 --- a/src/gui/partitionmanagerwidget.cpp +++ b/src/gui/partitionmanagerwidget.cpp @@ -94,9 +94,6 @@ void PartitionManagerWidget::init(OperationStack* ostack) { m_OperationStack = ostack; - // TODO: shouldn't this also go to the main window class? - FileSystemFactory::init(); - loadConfig(); setupConnections(); }