diff --git a/classic/ClassicMode.cpp b/classic/ClassicMode.cpp index dcc956fb..f24d4c39 100644 --- a/classic/ClassicMode.cpp +++ b/classic/ClassicMode.cpp @@ -1,275 +1,275 @@ /************************************************************************** * Copyright (C) 2009 Ben Cooksley * * Copyright (C) 2008 Mathias Soeken * * * * 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. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301, USA. * ***************************************************************************/ #include "ClassicMode.h" #include "ui_configClassic.h" #include #include #include #include #include #include #include #include #include #include "MenuItem.h" #include "MenuModel.h" #include "ModuleView.h" #include "CategoryList.h" #include "MenuProxyModel.h" K_PLUGIN_FACTORY(ClassicModeFactory, registerPlugin();) class ClassicMode::Private { public: Private() {} virtual ~Private() { delete aboutClassic; } QSplitter * classicWidget = nullptr; QTreeView * classicTree = nullptr; Ui::ConfigClassic classicConfig; CategoryList * classicCategory = nullptr; QStackedWidget * stackedWidget = nullptr; ModuleView * moduleView = nullptr; QModelIndex currentItem; MenuProxyModel * proxyModel = nullptr; MenuModel * model = nullptr; KAboutData * aboutClassic = nullptr; }; ClassicMode::ClassicMode( QObject * parent, const QVariantList& ) : BaseMode( parent ), d( new Private() ) { d->aboutClassic = new KAboutData(QStringLiteral("TreeView"), i18n("Tree View"), QStringLiteral("1.0"), i18n("Provides a classic tree-based view of control modules."), KAboutLicense::GPL, i18n("(c) 2009, Ben Cooksley")); d->aboutClassic->addAuthor(i18n("Ben Cooksley"), i18n("Author"), QStringLiteral("bcooksley@kde.org")); d->aboutClassic->addAuthor(i18n("Mathias Soeken"), i18n("Developer"), QStringLiteral("msoeken@informatik.uni-bremen.de")); } ClassicMode::~ClassicMode() { if( !d->classicTree ) { delete d->classicWidget; } delete d; } void ClassicMode::initEvent() { // Create the model d->model = new MenuModel( rootItem(), this ); // Move items that are the sole child of a category up.... moveUp( rootItem() ); // Create the proxy model d->proxyModel = new MenuProxyModel( this ); d->proxyModel->setSourceModel( d->model ); d->proxyModel->sort( 0 ); d->classicWidget = new QSplitter( Qt::Horizontal, nullptr ); d->classicWidget->setChildrenCollapsible( false ); d->moduleView = new ModuleView( d->classicWidget ); d->classicTree = nullptr; } QWidget * ClassicMode::mainWidget() { if( !d->classicTree ) { initWidget(); } return d->classicWidget; } KAboutData * ClassicMode::aboutData() { return d->aboutClassic; } ModuleView * ClassicMode::moduleView() const { return d->moduleView; } QList ClassicMode::views() const { QList theViews; theViews << d->classicTree; return theViews; } void ClassicMode::saveState() { config().writeEntry( "viewLayout", d->classicWidget->sizes() ); config().sync(); } void ClassicMode::expandColumns() { d->classicTree->resizeColumnToContents(0); } void ClassicMode::searchChanged( const QString& text ) { d->proxyModel->setFilterRegExp(text); if( d->classicTree ) { d->classicCategory->changeModule( d->classicTree->currentIndex() ); } } void ClassicMode::selectModule( const QModelIndex& selectedModule ) { d->classicTree->setCurrentIndex( selectedModule ); if( d->proxyModel->rowCount(selectedModule) > 0 ) { d->classicTree->setExpanded(selectedModule, true); } changeModule( selectedModule ); } void ClassicMode::changeModule( const QModelIndex& activeModule ) { if( activeModule == d->currentItem ) { return; } if( !d->moduleView->resolveChanges() ) { return; } d->moduleView->closeModules(); d->currentItem = activeModule; if( d->proxyModel->rowCount(activeModule) > 0 ) { d->stackedWidget->setCurrentWidget( d->classicCategory ); d->classicCategory->changeModule(activeModule); emit viewChanged( false ); } else { d->moduleView->loadModule( activeModule ); } } void ClassicMode::moduleLoaded() { d->stackedWidget->setCurrentWidget( d->moduleView ); } void ClassicMode::initWidget() { // Create the widget d->classicTree = new QTreeView( d->classicWidget ); d->classicCategory = new CategoryList( d->classicWidget, d->proxyModel ); d->stackedWidget = new QStackedWidget( d->classicWidget ); - d->stackedWidget->layout()->setMargin(0); + d->stackedWidget->layout()->setContentsMargins(0, 0, 0, 0); d->stackedWidget->addWidget( d->classicCategory ); d->stackedWidget->addWidget( d->moduleView ); d->classicWidget->addWidget( d->classicTree ); d->classicWidget->addWidget( d->stackedWidget ); d->classicTree->setModel( d->proxyModel ); d->classicTree->setHeaderHidden( true ); d->classicTree->setIconSize( QSize( 24, 24 ) ); d->classicTree->setSortingEnabled( true ); d->classicTree->setMouseTracking( true ); d->classicTree->setMinimumWidth( 200 ); d->classicTree->setSelectionMode( QAbstractItemView::SingleSelection ); d->classicTree->sortByColumn( 0, Qt::AscendingOrder ); d->classicCategory->changeModule( d->classicTree->rootIndex() ); connect( d->classicCategory, &CategoryList::moduleSelected, this, &ClassicMode::selectModule ); connect( d->classicTree, &QAbstractItemView::activated, this, &ClassicMode::changeModule ); connect( d->classicTree, &QTreeView::collapsed, this, &ClassicMode::expandColumns ); connect( d->classicTree, &QTreeView::expanded, this, &ClassicMode::expandColumns ); connect( d->moduleView, &ModuleView::moduleChanged, this, &ClassicMode::moduleLoaded ); if( !qApp->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) ) { // Needed because otherwise activated() is not fired with single click, which is apparently expected for tree views connect( d->classicTree, &QAbstractItemView::clicked, this, &ClassicMode::changeModule ); } if( config().readEntry( "autoExpandOneLevel", false ) ) { for( int processed = 0; d->proxyModel->rowCount() > processed; processed++ ) { d->classicTree->setExpanded( d->proxyModel->index( processed, 0 ), true ); } } expandColumns(); QList defaultSizes; defaultSizes << 250 << 500; d->classicWidget->setSizes( config().readEntry( "viewLayout", defaultSizes ) ); emit changeToolBarItems( BaseMode::Search | BaseMode::Configure | BaseMode::Quit ); d->classicWidget->installEventFilter(this); } bool ClassicMode::eventFilter(QObject* watched, QEvent* event) { if (watched == d->classicWidget && event->type() == QEvent::Show) { emit changeToolBarItems( BaseMode::Search | BaseMode::Configure | BaseMode::Quit ); } return BaseMode::eventFilter(watched, event); } void ClassicMode::leaveModuleView() { d->moduleView->closeModules(); d->stackedWidget->setCurrentWidget( d->classicCategory ); } void ClassicMode::giveFocus() { d->classicTree->setFocus(); } void ClassicMode::addConfiguration( KConfigDialog * config ) { QWidget * configWidget = new QWidget( config ); d->classicConfig.setupUi( configWidget ); config->addPage( configWidget, i18n("Tree View"), QStringLiteral("view-list-tree") ); } void ClassicMode::loadConfiguration() { d->classicConfig.CbExpand->setChecked( config().readEntry( "autoExpandOneLevel", false ) ); } void ClassicMode::saveConfiguration() { config().writeEntry("autoExpandOneLevel", d->classicConfig.CbExpand->isChecked()); } void ClassicMode::moveUp( MenuItem * item ) { foreach( MenuItem * child, item->children() ) { if( child->children().count() == 1 ) { d->model->addException( child ); } moveUp( child ); } } #include "ClassicMode.moc" diff --git a/core/ModuleView.cpp b/core/ModuleView.cpp index eef6ff34..3c11a221 100644 --- a/core/ModuleView.cpp +++ b/core/ModuleView.cpp @@ -1,439 +1,439 @@ /***************************************************************************** * Copyright (C) 2009 Ben Cooksley * * Copyright (C) 2009 by Mathias Soeken * * * * 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. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *****************************************************************************/ #include "ModuleView.h" #include "ExternalAppModule.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MenuItem.h" class ModuleView::Private { public: Private() {} QMap mPages; QMap mModules; KPageWidget* mPageWidget = nullptr; QVBoxLayout* mLayout = nullptr; QDialogButtonBox* mButtons = nullptr; KAuth::ObjectDecorator* mApplyAuthorize = nullptr; QPushButton* mApply = nullptr; QPushButton* mReset = nullptr; QPushButton* mDefault = nullptr; QPushButton* mHelp = nullptr; bool pageChangeSupressed; }; ModuleView::ModuleView( QWidget * parent ) : QWidget( parent ) , d( new Private() ) { // Configure a layout first d->mLayout = new QVBoxLayout(this); // Create the Page Widget d->mPageWidget = new KPageWidget(this); - d->mPageWidget->layout()->setMargin(0); + d->mPageWidget->layout()->setContentsMargins(0, 0, 0, 0); d->mLayout->addWidget(d->mPageWidget); // Create the dialog d->mButtons = new QDialogButtonBox( Qt::Horizontal, this ); d->mLayout->addWidget(d->mButtons); // Create the buttons in it d->mApply = d->mButtons->addButton( QDialogButtonBox::Apply ); KGuiItem::assign(d->mApply, KStandardGuiItem::apply()); d->mDefault = d->mButtons->addButton( QDialogButtonBox::RestoreDefaults ); KGuiItem::assign(d->mDefault, KStandardGuiItem::defaults()); d->mReset = d->mButtons->addButton( QDialogButtonBox::Reset ); KGuiItem::assign(d->mReset, KStandardGuiItem::reset()); d->mHelp = d->mButtons->addButton( QDialogButtonBox::Help ); KGuiItem::assign(d->mHelp, KStandardGuiItem::help()); // Set some more sensible tooltips d->mReset->setToolTip( i18n("Reset all current changes to previous values") ); // Set Auto-Default mode ( KDE Bug #211187 ) d->mApply->setAutoDefault(true); d->mDefault->setAutoDefault(true); d->mReset->setAutoDefault(true); d->mHelp->setAutoDefault(true); // Prevent the buttons from being used d->mApply->setEnabled(false); d->mDefault->setEnabled(false); d->mReset->setEnabled(false); d->mHelp->setEnabled(false); // Connect up the buttons connect( d->mApply, SIGNAL(clicked()), this, SLOT(moduleSave()) ); connect( d->mReset, &QAbstractButton::clicked, this, &ModuleView::moduleLoad ); connect( d->mHelp, &QAbstractButton::clicked, this, &ModuleView::moduleHelp ); connect( d->mDefault, &QAbstractButton::clicked, this, &ModuleView::moduleDefaults ); connect( d->mPageWidget, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(activeModuleChanged(KPageWidgetItem*,KPageWidgetItem*)) ); connect( this, &ModuleView::moduleChanged, this, &ModuleView::updateButtons ); d->mApplyAuthorize = new KAuth::ObjectDecorator(d->mApply); d->mApplyAuthorize->setAuthAction( KAuth::Action() ); } ModuleView::~ModuleView() { delete d; } KCModuleInfo * ModuleView::activeModule() const { return d->mModules.value( d->mPageWidget->currentPage() ); } const KAboutData * ModuleView::aboutData() const { KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() ); KAboutData * aboutData = nullptr; if( activeModule ) { aboutData = const_cast( activeModule->aboutData() ); } return aboutData; } void ModuleView::loadModule( const QModelIndex &menuItem ) { if ( !menuItem.isValid() ) { return; } QList indexes; for ( int done = 0; menuItem.model()->rowCount( menuItem ) > done; done = 1 + done ) { indexes << menuItem.model()->index( done, 0, menuItem ); } if ( indexes.empty() ) { indexes << menuItem; } foreach ( const QModelIndex &module, indexes ) { MenuItem *newMenuItem = module.data( Qt::UserRole ).value(); addModule( &newMenuItem->item() ); } // changing state is not needed here as the adding / changing of pages does it } void ModuleView::addModule( KCModuleInfo *module ) { if( !module ) { return; } if( !module->service() ) { qWarning() << "ModuleInfo has no associated KService" ; return; } if ( !KAuthorized::authorizeControlModule( module->service()->menuId() ) ) { qWarning() << "Not authorised to load module" ; return; } if( module->service()->noDisplay() ) { return; } // Create the scroller QScrollArea * moduleScroll = new QScrollArea( this ); // Prepare the scroll area moduleScroll->setWidgetResizable( true ); moduleScroll->setFrameStyle( QFrame::NoFrame ); moduleScroll->viewport()->setAutoFillBackground( false ); // Create the page KPageWidgetItem *page = new KPageWidgetItem( moduleScroll, module->moduleName() ); // Provide information to the users if( module->service()->hasServiceType(QStringLiteral("SystemSettingsExternalApp")) || // Is it an external app? module->service()->substituteUid() ) { // ...or does it require UID substitution? QWidget * externalWidget = new ExternalAppModule( this, module ); moduleScroll->setWidget( externalWidget ); } else { // It must be a normal module then KCModuleProxy * moduleProxy = new KCModuleProxy( *module, moduleScroll ); moduleScroll->setWidget( moduleProxy ); moduleProxy->setAutoFillBackground( false ); connect( moduleProxy, SIGNAL(changed(bool)), this, SLOT(stateChanged())); d->mPages.insert( page, moduleProxy ); } d->mModules.insert( page, module ); updatePageIconHeader( page, true ); // Add the new page d->mPageWidget->addPage( page ); } void ModuleView::updatePageIconHeader( KPageWidgetItem * page, bool light ) { if( !page ) { // Page is invalid. Probably means we have a race condition during closure of everyone so do nothing return; } KCModuleProxy * moduleProxy = d->mPages.value( page ); KCModuleInfo * moduleInfo = d->mModules.value( page ); if( !moduleInfo ) { // Seems like we have some form of a race condition going on here... return; } page->setHeader( moduleInfo->moduleName() ); page->setIcon( QIcon::fromTheme( moduleInfo->icon() ) ); //HACK: not much other ways to detect is a qml kcm if ( moduleProxy && moduleProxy->realModule()->inherits("KCModuleQml") ) { page->setHeaderVisible(false); } if( light ) { return; } if( moduleProxy && moduleProxy->realModule()->useRootOnlyMessage() ) { page->setHeader( moduleInfo->moduleName() + QStringLiteral("
") + moduleProxy->realModule()->rootOnlyMessage() + QStringLiteral("") ); page->setIcon( KDE::icon( moduleInfo->icon(), QStringList() << QStringLiteral("dialog-warning") ) ); } } bool ModuleView::resolveChanges() { KCModuleProxy * currentProxy = d->mPages.value( d->mPageWidget->currentPage() ); return resolveChanges(currentProxy); } bool ModuleView::resolveChanges(KCModuleProxy * currentProxy) { if( !currentProxy || !currentProxy->changed() ) { return true; } // Let the user decide const int queryUser = KMessageBox::warningYesNoCancel( this, i18n("The settings of the current module have changed.\n" "Do you want to apply the changes or discard them?"), i18n("Apply Settings"), KStandardGuiItem::apply(), KStandardGuiItem::discard(), KStandardGuiItem::cancel() ); switch (queryUser) { case KMessageBox::Yes: return moduleSave(currentProxy); case KMessageBox::No: currentProxy->load(); return true; case KMessageBox::Cancel: return false; default: Q_ASSERT(false); return false; } } void ModuleView::closeModules() { d->pageChangeSupressed = true; d->mApplyAuthorize->setAuthAction( KAuth::Action() ); // Ensure KAuth knows that authentication is now pointless... QMap::iterator page = d->mModules.begin(); QMap::iterator pageEnd = d->mModules.end(); for ( ; page != pageEnd; ++page ) { d->mPageWidget->removePage( page.key() ); } d->mPages.clear(); d->mModules.clear(); d->pageChangeSupressed = false; } bool ModuleView::moduleSave() { KCModuleProxy * moduleProxy = d->mPages.value( d->mPageWidget->currentPage() ); return moduleSave( moduleProxy ); } bool ModuleView::moduleSave(KCModuleProxy *module) { if( !module ) { return false; } module->save(); return true; } void ModuleView::moduleLoad() { KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() ); if( activeModule ) { activeModule->load(); } } void ModuleView::moduleDefaults() { KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() ); if( activeModule ) { activeModule->defaults(); } } void ModuleView::moduleHelp() { KCModuleInfo * activeModule = d->mModules.value( d->mPageWidget->currentPage() ); if( !activeModule ) { return; } QString docPath = activeModule->docPath(); if( docPath.isEmpty() ) { return; } QUrl url( QStringLiteral("help:/")+docPath ); QProcess::startDetached(QStringLiteral("khelpcenter"), QStringList() << url.url()); } void ModuleView::activeModuleChanged(KPageWidgetItem * current, KPageWidgetItem * previous) { d->mPageWidget->blockSignals(true); d->mPageWidget->setCurrentPage(previous); KCModuleProxy * previousModule = d->mPages.value(previous); if( resolveChanges(previousModule) ) { d->mPageWidget->setCurrentPage(current); } d->mPageWidget->blockSignals(false); if( d->pageChangeSupressed ) { return; } // We need to get the state of the now active module stateChanged(); KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() ); if (activeModule) { KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("kcm:") + activeModule->moduleInfo().service()->storageId()), QStringLiteral("org.kde.systemsettings")); if (activeModule->realModule() && activeModule->realModule()->inherits("KCModuleQml")) { d->mButtons->setContentsMargins( style()->pixelMetric(QStyle::PM_LayoutLeftMargin), style()->pixelMetric(QStyle::PM_LayoutTopMargin), style()->pixelMetric(QStyle::PM_LayoutRightMargin), style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); d->mLayout->setContentsMargins(0, 0, 0, 0); } else { d->mButtons->setContentsMargins(0, 0, 0, 0); d->mLayout->setContentsMargins( style()->pixelMetric(QStyle::PM_LayoutLeftMargin), style()->pixelMetric(QStyle::PM_LayoutTopMargin), style()->pixelMetric(QStyle::PM_LayoutRightMargin), style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); } } } void ModuleView::stateChanged() { KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() ); KAuth::Action moduleAction; bool change = false; if( activeModule ) { change = activeModule->changed(); disconnect( d->mApplyAuthorize, SIGNAL(authorized(KAuth::Action)), this, SLOT(moduleSave()) ); disconnect( d->mApply, SIGNAL(clicked()), this, SLOT(moduleSave()) ); if( activeModule->realModule()->authAction().isValid() ) { connect( d->mApplyAuthorize, SIGNAL(authorized(KAuth::Action)), this, SLOT(moduleSave()) ); moduleAction = activeModule->realModule()->authAction(); } else { connect( d->mApply, SIGNAL(clicked()), this, SLOT(moduleSave()) ); } } updatePageIconHeader( d->mPageWidget->currentPage() ); d->mApplyAuthorize->setAuthAction( moduleAction ); d->mApply->setEnabled( change ); d->mReset->setEnabled( change ); emit moduleChanged( change ); } void ModuleView::keyPressEvent ( QKeyEvent * event ) { if ( event->key() == Qt::Key_F1 && d->mHelp->isVisible() && d->mHelp->isEnabled()) { d->mHelp->animateClick(); event->accept(); return; } else if ( event->key() == Qt::Key_Escape ) { event->accept(); emit closeRequest(); return; } else if ( event->key() == Qt::Key_F1 && event->modifiers() == Qt::ShiftModifier ) { QWhatsThis::enterWhatsThisMode(); event->accept(); return; } QWidget::keyPressEvent( event ); } void ModuleView::updateButtons() { KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() ); if( !activeModule ) { return; } const int buttons = activeModule->buttons(); d->mApply->setVisible(buttons & KCModule::Apply ); d->mReset->setVisible(buttons & KCModule::Apply ); d->mHelp->setEnabled(buttons & KCModule::Help ); d->mDefault->setEnabled(buttons & KCModule::Default ); } void ModuleView::setFaceType(KPageView::FaceType type) { d->mPageWidget->setFaceType(type); } KPageView::FaceType ModuleView::faceType() const { return d->mPageWidget->faceType(); }