diff --git a/sidebar/CMakeLists.txt b/sidebar/CMakeLists.txt index 6eaca091..187c5b08 100644 --- a/sidebar/CMakeLists.txt +++ b/sidebar/CMakeLists.txt @@ -1,29 +1,26 @@ set( sidebar_mode_srcs SidebarMode.cpp - CategoryDrawer.cpp - CategorizedView.cpp - SidebarDelegate.cpp ToolTips/tooltipmanager.cpp ) add_library(systemsettings_sidebar_mode MODULE ${sidebar_mode_srcs}) target_link_libraries(systemsettings_sidebar_mode systemsettingsview KF5::ItemViews KF5::KCMUtils KF5::I18n KF5::KIOWidgets KF5::Service KF5::XmlGui KF5::Package KF5::Declarative KF5::ActivitiesStats Qt5::Qml Qt5::Quick Qt5::QuickWidgets ) install( TARGETS systemsettings_sidebar_mode DESTINATION ${KDE_INSTALL_PLUGINDIR} ) install( FILES settings-sidebar-view.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) install(DIRECTORY package/ DESTINATION ${KDE_INSTALL_DATAROOTDIR}/kpackage/genericqml/org.kde.systemsettings.sidebar) diff --git a/sidebar/CategorizedView.cpp b/sidebar/CategorizedView.cpp deleted file mode 100644 index cec3796f..00000000 --- a/sidebar/CategorizedView.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Rafael Fernández López * - * * - * 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 "CategorizedView.h" - -#include - -#include - -CategorizedView::CategorizedView( QWidget *parent ) - : KCategorizedView( parent ) -{ - setWordWrap( true ); - setViewportMargins(QMargins(0,0,-20,0)); -} - -void CategorizedView::setModel( QAbstractItemModel *model ) -{ - KCategorizedView::setModel( model ); -} - -void CategorizedView::wheelEvent(QWheelEvent* event) -{ - // this is a workaround because scrolling by mouse wheel is broken in Qt list views for big items - // https://bugreports.qt-project.org/browse/QTBUG-7232 - verticalScrollBar()->setSingleStep(10); - KCategorizedView::wheelEvent(event); -} diff --git a/sidebar/CategorizedView.h b/sidebar/CategorizedView.h deleted file mode 100644 index c3e63b97..00000000 --- a/sidebar/CategorizedView.h +++ /dev/null @@ -1,35 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Rafael Fernández López * - * * - * 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 * - ***************************************************************************/ - -#ifndef CATEGORIZEDVIEW_H -#define CATEGORIZEDVIEW_H - -#include - -class CategorizedView : public KCategorizedView -{ -public: - explicit CategorizedView( QWidget *parent = nullptr ); - - void setModel( QAbstractItemModel *model ) override; -protected: - void wheelEvent(QWheelEvent *) override; -}; - -#endif diff --git a/sidebar/CategoryDrawer.cpp b/sidebar/CategoryDrawer.cpp deleted file mode 100644 index 80752084..00000000 --- a/sidebar/CategoryDrawer.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Rafael Fernández López * - * * - * 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 "CategoryDrawer.h" - -#include "MenuProxyModel.h" - -#include -#include -#include - -CategoryDrawer::CategoryDrawer(KCategorizedView *view) -: KCategoryDrawer(view) -{ -} - -void CategoryDrawer::drawCategory(const QModelIndex &index, - int sortRole, - const QStyleOption &option, - QPainter *painter) const -{ - Q_UNUSED( option ) - Q_UNUSED( painter ) - Q_UNUSED( sortRole ) - - painter->setRenderHint(QPainter::Antialiasing); - - QFont font(QApplication::font()); - font.setBold(true); - const QFontMetrics fontMetrics = QFontMetrics(font); - const int height = categoryHeight(index, option); - - - const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); - QRect textRect = QRect(option.rect.topLeft()+QPoint(8,0), QSize(option.rect.width() - 2 - 3 - 3, height)); - - textRect.setLeft(textRect.left()); - painter->save(); - painter->setFont(font); - QColor penColor(option.palette.text().color()); - penColor.setAlphaF(0.6); - painter->setPen(penColor); - if (index.row() > 0) { - textRect.setTop(textRect.top() + 10); - painter->save(); - penColor.setAlphaF(0.3); - painter->fillRect(QRect(textRect.topLeft() + QPoint(-8, -5), QSize(option.rect.width(),1)), penColor); - painter->restore(); - } - - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignBottom, category); - painter->restore(); - -} - -int CategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &option) const -{ - Q_UNUSED( index ); - Q_UNUSED( option ); - - QFont font(QApplication::font()); - font.setBold(true); - const QFontMetrics fontMetrics = QFontMetrics(font); - //if (index.row() == 0) return fontMetrics.height(); - - return fontMetrics.height() * 1.6 /* vertical spacing */; -} - -int CategoryDrawer::leftMargin() const -{ - return 0; -} - -int CategoryDrawer::rightMargin() const -{ - return 0; -} diff --git a/sidebar/CategoryDrawer.h b/sidebar/CategoryDrawer.h deleted file mode 100644 index 6fbbde49..00000000 --- a/sidebar/CategoryDrawer.h +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Rafael Fernández López * - * * - * 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 * - ***************************************************************************/ - -#ifndef CATEGORYDRAWER_H -#define CATEGORYDRAWER_H - -#include - -class QPainter; -class QModelIndex; -class QStyleOption; - -class CategoryDrawer : public KCategoryDrawer -{ - Q_OBJECT -public: - explicit CategoryDrawer(KCategorizedView *view); - - void drawCategory(const QModelIndex &index, - int sortRole, - const QStyleOption &option, - QPainter *painter) const override; - - int categoryHeight(const QModelIndex &index, const QStyleOption &option) const override; - int leftMargin() const override; - int rightMargin() const override; -}; - -#endif diff --git a/sidebar/SidebarDelegate.cpp b/sidebar/SidebarDelegate.cpp deleted file mode 100644 index ff3d1b59..00000000 --- a/sidebar/SidebarDelegate.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/************************************************************************** - * Copyright (C) 2017 Marco Martin * - * * - * 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 "SidebarDelegate.h" - -#include -#include - -static const int s_margin = 10; - -SidebarDelegate::SidebarDelegate(QObject *parent) - : QAbstractItemDelegate(parent) -{ -} - -SidebarDelegate::~SidebarDelegate() -{ -} - - -QSize SidebarDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const -{ - Q_UNUSED(index) - return QSize(option.decorationSize.width() + s_margin * 2, option.decorationSize.height() + s_margin * 2); -} - -void SidebarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const -{ - Q_ASSERT(index.isValid()); - - painter->save(); - QStyleOptionViewItem opt = option; - initStyleOption(&opt, index); - - // Apparently some widget styles expect this hint to not be set - painter->setRenderHint(QPainter::Antialiasing, false); - - QStyle *style = option.widget ? option.widget->style() : QApplication::style(); - style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); - - painter->setRenderHint(QPainter::Antialiasing); - - QIcon::Mode iconMode; - - if (!(opt.state & QStyle::State_Enabled)) { - iconMode = QIcon::Disabled; - } else if ((opt.state & QStyle::State_Selected) && (opt.state & QStyle::State_Active)) { - iconMode = QIcon::Selected; - } else { - iconMode = QIcon::Normal; - } - - QIcon::State iconState = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; - QPixmap icon = opt.icon.pixmap(opt.decorationSize, iconMode, iconState); - - const QRect iconRect = QStyle::alignedRect(opt.direction, Qt::AlignVCenter | Qt::AlignLeft, opt.decorationSize, opt.rect.adjusted(s_margin, s_margin, -s_margin, -s_margin)); - painter->drawPixmap(iconRect.topLeft(), icon); - - QFontMetrics fontMetrics(opt.font); - const QString text = fontMetrics.elidedText(opt.text, Qt::ElideRight, opt.rect.width() - iconRect.width() - s_margin*3); - //TODO: LTR - const QRect textRect = opt.rect.adjusted(s_margin + iconRect.right(), - s_margin, -s_margin, -s_margin); - - painter->setFont(opt.font); - painter->setPen(QPen(foregroundBrush(opt, index), 0)); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); - painter->restore(); -} - -QBrush SidebarDelegate::foregroundBrush(const QStyleOptionViewItem &option, const QModelIndex &index) const -{ - Q_UNUSED(index); - QPalette::ColorGroup cg = QPalette::Active; - if (!(option.state & QStyle::State_Enabled)) { - cg = QPalette::Disabled; - } else if (!(option.state & QStyle::State_Active)) { - cg = QPalette::Inactive; - } - - // Always use the highlight color for selected items - if (option.state & QStyle::State_Selected) { - return option.palette.brush(cg, QPalette::HighlightedText); - } - - return option.palette.brush(cg, QPalette::Text); -} - -void SidebarDelegate::initStyleOption(QStyleOptionViewItem *option, - const QModelIndex &index) const -{ - QVariant value = index.data(Qt::FontRole); - if (value.isValid() && !value.isNull()) { - option->font = qvariant_cast(value).resolve(option->font); - option->fontMetrics = QFontMetrics(option->font); - } - - value = index.data(Qt::TextAlignmentRole); - if (value.isValid() && !value.isNull()) - option->displayAlignment = Qt::Alignment(value.toInt()); - - value = index.data(Qt::ForegroundRole); - if (value.canConvert()) - option->palette.setBrush(QPalette::Text, qvariant_cast(value)); - - option->index = index; - value = index.data(Qt::CheckStateRole); - if (value.isValid() && !value.isNull()) { - option->features |= QStyleOptionViewItem::HasCheckIndicator; - option->checkState = static_cast(value.toInt()); - } - - value = index.data(Qt::DecorationRole); - if (value.isValid() && !value.isNull()) { - option->features |= QStyleOptionViewItem::HasDecoration; - switch (value.type()) { - case QVariant::Icon: { - option->icon = qvariant_cast(value); - QIcon::Mode mode; - if (!(option->state & QStyle::State_Enabled)) - mode = QIcon::Disabled; - else if (option->state & QStyle::State_Selected) - mode = QIcon::Selected; - else - mode = QIcon::Normal; - QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off; - QSize actualSize = option->icon.actualSize(option->decorationSize, mode, state); - // For highdpi icons actualSize might be larger than decorationSize, which we don't want. Clamp it to decorationSize. - option->decorationSize = QSize(qMin(option->decorationSize.width(), actualSize.width()), - qMin(option->decorationSize.height(), actualSize.height())); - break; - } - case QVariant::Color: { - QPixmap pixmap(option->decorationSize); - pixmap.fill(qvariant_cast(value)); - option->icon = QIcon(pixmap); - break; - } - case QVariant::Image: { - QImage image = qvariant_cast(value); - option->icon = QIcon(QPixmap::fromImage(image)); - option->decorationSize = image.size() / image.devicePixelRatio(); - break; - } - case QVariant::Pixmap: { - QPixmap pixmap = qvariant_cast(value); - option->icon = QIcon(pixmap); - option->decorationSize = pixmap.size() / pixmap.devicePixelRatio(); - break; - } - default: - break; - } - } - - value = index.data(Qt::DisplayRole); - if (value.isValid() && !value.isNull()) { - option->features |= QStyleOptionViewItem::HasDisplay; - option->text = value.toString(); - } - - option->backgroundBrush = qvariant_cast(index.data(Qt::BackgroundRole)); - - // disable style animations for checkboxes etc. within itemviews (QTBUG-30146) - option->styleObject = nullptr; -} diff --git a/sidebar/SidebarDelegate.h b/sidebar/SidebarDelegate.h deleted file mode 100644 index 699746da..00000000 --- a/sidebar/SidebarDelegate.h +++ /dev/null @@ -1,44 +0,0 @@ -/************************************************************************** - * Copyright (C) 2017 Marco Martin * - * * - * 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. * -***************************************************************************/ - -#ifndef SIDEBARDELEGATE_H -#define SIDEBARDELEGATE_H - -#include - -class SidebarDelegate : public QAbstractItemDelegate -{ - Q_OBJECT - -public: - explicit SidebarDelegate(QObject *parent = nullptr); - ~SidebarDelegate() override; - - - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; - - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - -protected: - void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const; - QBrush foregroundBrush(const QStyleOptionViewItem &option, const QModelIndex &index) const; -}; - -#endif - diff --git a/sidebar/SidebarMode.cpp b/sidebar/SidebarMode.cpp index 3f5811e0..5f6d82e4 100644 --- a/sidebar/SidebarMode.cpp +++ b/sidebar/SidebarMode.cpp @@ -1,585 +1,582 @@ /************************************************************************** * Copyright (C) 2009 by Ben Cooksley * * * * 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 "SidebarMode.h" -#include "CategoryDrawer.h" -#include "CategorizedView.h" #include "MenuItem.h" #include "MenuModel.h" #include "ModuleView.h" #include "MenuProxyModel.h" #include "BaseData.h" -#include "SidebarDelegate.h" #include "ToolTips/tooltipmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KAStats = KActivities::Stats; using namespace KAStats; using namespace KAStats::Terms; K_PLUGIN_FACTORY( SidebarModeFactory, registerPlugin(); ) FocusHackWidget::FocusHackWidget(QWidget *parent) : QWidget(parent) {} FocusHackWidget::~FocusHackWidget() {} void FocusHackWidget::focusNext() { focusNextChild(); } void FocusHackWidget::focusPrevious() { focusNextPrevChild(false); } class SubcategoryModel : public QStandardItemModel { public: explicit SubcategoryModel(QAbstractItemModel *parentModel, QObject *parent = nullptr) : QStandardItemModel(parent), m_parentModel(parentModel) {} void setParentIndex(const QModelIndex &activeModule) { blockSignals(true); //make the view receive a single signal when the new subcategory is loaded, //never make the view believe there are zero items if this is not the final count //this avoids the brief flash it had clear(); const int subRows = m_parentModel->rowCount(activeModule); if ( subRows > 1) { for (int i = 0; i < subRows; ++i) { const QModelIndex& index = m_parentModel->index(i, 0, activeModule); QStandardItem *item = new QStandardItem(m_parentModel->data(index, Qt::DecorationRole).value(), m_parentModel->data(index, Qt::DisplayRole).toString()); item->setData(index.data(Qt::UserRole), Qt::UserRole); appendRow(item); } } blockSignals(false); beginResetModel(); endResetModel(); } private: QAbstractItemModel *m_parentModel; }; class MostUsedModel : public QSortFilterProxyModel { public: explicit MostUsedModel(QObject *parent = nullptr) : QSortFilterProxyModel (parent) { sort(0, Qt::DescendingOrder); setSortRole(ResultModel::ScoreRole); setDynamicSortFilter(true); //prepare default items m_defaultModel = new QStandardItemModel(this); QStandardItem *item = new QStandardItem(); item->setData(QUrl(QStringLiteral("kcm:kcm_lookandfeel.desktop")), ResultModel::ResourceRole); m_defaultModel->appendRow(item); item = new QStandardItem(); item->setData(QUrl(QStringLiteral("kcm:user_manager.desktop")), ResultModel::ResourceRole); m_defaultModel->appendRow(item); item = new QStandardItem(); item->setData(QUrl(QStringLiteral("kcm:screenlocker.desktop")), ResultModel::ResourceRole); m_defaultModel->appendRow(item); item = new QStandardItem(); item->setData(QUrl(QStringLiteral("kcm:powerdevilprofilesconfig.desktop")), ResultModel::ResourceRole); m_defaultModel->appendRow(item); item = new QStandardItem(); item->setData(QUrl(QStringLiteral("kcm:kcm_kscreen.desktop")), ResultModel::ResourceRole); m_defaultModel->appendRow(item); } void setResultModel(ResultModel *model) { if (m_resultModel == model) { return; } auto updateModel = [this]() { if (m_resultModel->rowCount() >= 5) { setSourceModel(m_resultModel); } else { setSourceModel(m_defaultModel); } }; m_resultModel = model; connect(m_resultModel, &QAbstractItemModel::rowsInserted, this, updateModel); connect(m_resultModel, &QAbstractItemModel::rowsRemoved, this, updateModel); updateModel(); } QHash roleNames() const override { QHash roleNames; roleNames.insert(Qt::DisplayRole, "display"); roleNames.insert(Qt::DecorationRole, "decoration"); roleNames.insert(ResultModel::ScoreRole, "score"); return roleNames; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { MenuItem *mi; const QString desktopName = QSortFilterProxyModel::data(index, ResultModel::ResourceRole).toUrl().path(); if (m_menuItems.contains(desktopName)) { mi = m_menuItems.value(desktopName); } else { mi = new MenuItem(false, nullptr); const_cast(this)->m_menuItems.insert(desktopName, mi); KService::Ptr service = KService::serviceByStorageId(desktopName); if (!service || !service->isValid()) { qWarning()<forgetResource(QStringLiteral("kcm:") % desktopName); return QVariant(); } mi->setService(service); } switch (role) { case Qt::UserRole: return QVariant::fromValue(mi); case Qt::DisplayRole: if (mi->service() && mi->service()->isValid()) { return mi->service()->name(); } else { return QVariant(); } case Qt::DecorationRole: if (mi->service() && mi->service()->isValid()) { return mi->service()->icon(); } else { return QVariant(); } case ResultModel::ScoreRole: return QSortFilterProxyModel::data(index, ResultModel::ScoreRole).toInt(); default: return QVariant(); } } private: QHash m_menuItems; QStandardItemModel *m_defaultModel; ResultModel *m_resultModel; }; class SidebarMode::Private { public: Private() : quickWidget( nullptr ), moduleView( nullptr ), collection( nullptr ), activeCategory( -1 ), activeSubCategory( -1 ) {} virtual ~Private() { delete aboutIcon; } ToolTipManager *toolTipManager = nullptr; ToolTipManager *subCategoryToolTipManager = nullptr; QQuickWidget * quickWidget = nullptr; KPackage::Package package; SubcategoryModel * subCategoryModel = nullptr; MostUsedModel * mostUsedModel = nullptr; FocusHackWidget * mainWidget = nullptr; QQuickWidget * placeHolderWidget = nullptr; QHBoxLayout * mainLayout = nullptr; KDeclarative::KDeclarative kdeclarative; MenuProxyModel * categorizedModel = nullptr; MenuProxyModel * searchModel = nullptr; KAboutData * aboutIcon = nullptr; ModuleView * moduleView = nullptr; KActionCollection *collection = nullptr; QPersistentModelIndex activeCategoryIndex; int activeCategory; int activeSubCategory; }; SidebarMode::SidebarMode( QObject *parent, const QVariantList& ) : BaseMode( parent ) , d( new Private() ) { qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); d->aboutIcon = new KAboutData( QStringLiteral("SidebarView"), i18n( "Sidebar View" ), QStringLiteral("1.0"), i18n( "Provides a categorized sidebar for control modules." ), KAboutLicense::GPL, i18n( "(c) 2017, Marco Martin" ) ); d->aboutIcon->addAuthor( i18n( "Marco Martin" ), i18n( "Author" ), QStringLiteral("mart@kde.org") ); d->aboutIcon->addAuthor( i18n( "Ben Cooksley" ), i18n( "Author" ), QStringLiteral("bcooksley@kde.org") ); d->aboutIcon->addAuthor( i18n( "Mathias Soeken" ), i18n( "Developer" ), QStringLiteral("msoeken@informatik.uni-bremen.de") ); qmlRegisterType(); } SidebarMode::~SidebarMode() { delete d; } KAboutData * SidebarMode::aboutData() { return d->aboutIcon; } ModuleView * SidebarMode::moduleView() const { return d->moduleView; } QWidget * SidebarMode::mainWidget() { if( !d->quickWidget ) { initWidget(); } return d->mainWidget; } QAbstractItemModel * SidebarMode::categoryModel() const { return d->searchModel; } QAbstractItemModel * SidebarMode::subCategoryModel() const { return d->subCategoryModel; } QAbstractItemModel * SidebarMode::mostUsedModel() const { return d->mostUsedModel; } QList SidebarMode::views() const { QList list; //list.append( d->categoryView ); return list; } void SidebarMode::initEvent() { MenuModel * model = new MenuModel( rootItem(), this ); foreach( MenuItem * child, rootItem()->children() ) { model->addException( child ); } d->categorizedModel = new MenuProxyModel( this ); d->categorizedModel->setCategorizedModel( true ); d->categorizedModel->setSourceModel( model ); d->categorizedModel->sort( 0 ); d->categorizedModel->setFilterHighlightsEntries( false ); d->searchModel = new MenuProxyModel( this ); d->searchModel->setFilterHighlightsEntries( false ); d->searchModel->setSourceModel( d->categorizedModel ); connect( d->searchModel, &MenuProxyModel::filterRegExpChanged, this, [this] () { if (d->activeCategoryIndex.isValid() && d->activeCategoryIndex.row() >= 0) { d->subCategoryModel->setParentIndex( d->activeCategoryIndex ); emit activeCategoryChanged(); } }); d->mostUsedModel = new MostUsedModel( this ); d->subCategoryModel = new SubcategoryModel( d->searchModel, this ); d->mainWidget = new FocusHackWidget(); d->mainWidget->installEventFilter(this); d->mainLayout = new QHBoxLayout(d->mainWidget); d->mainLayout->setContentsMargins(0, 0, 0, 0); d->moduleView = new ModuleView( d->mainWidget ); connect( d->moduleView, &ModuleView::moduleChanged, this, &SidebarMode::moduleLoaded ); d->quickWidget = nullptr; moduleView()->setFaceType(KPageView::Plain); } QAction *SidebarMode::action(const QString &name) const { if (!d->collection) { return nullptr; } return d->collection->action(name); } QString SidebarMode::actionIconName(const QString &name) const { if (QAction *a = action(name)) { return a->icon().name(); } return QString(); } void SidebarMode::requestToolTip(int index, const QRectF &rect) { if (showToolTips()) { d->toolTipManager->requestToolTip(d->searchModel->index(index, 0), rect.toRect()); } } void SidebarMode::requestSubCategoryToolTip(int index, const QRectF &rect) { if (showToolTips()) { d->subCategoryToolTipManager->requestToolTip(d->subCategoryModel->index(index, 0), rect.toRect()); } } void SidebarMode::hideToolTip() { d->toolTipManager->hideToolTip(); } void SidebarMode::hideSubCategoryToolTip() { d->subCategoryToolTipManager->hideToolTip(); } void SidebarMode::loadMostUsed(int index) { const QModelIndex idx = d->mostUsedModel->index(index, 0); d->moduleView->closeModules(); d->moduleView->loadModule( idx ); } void SidebarMode::changeModule( const QModelIndex& activeModule ) { d->moduleView->closeModules(); const int subRows = d->searchModel->rowCount(activeModule); if ( subRows < 2) { d->moduleView->loadModule( activeModule ); } else { d->moduleView->loadModule( d->searchModel->index(0, 0, activeModule) ); } d->subCategoryModel->setParentIndex( activeModule ); } void SidebarMode::moduleLoaded() { d->placeHolderWidget->hide(); d->moduleView->show(); } int SidebarMode::activeCategory() const { return d->searchModel->mapFromSource(d->searchModel->sourceModel()->index(d->activeCategory, 0)).row(); } void SidebarMode::setActiveCategory(int cat) { const QModelIndex idx = d->searchModel->index(cat, 0); const int newCategoryRow = d->searchModel->mapToSource(idx).row(); if (d->activeCategory == newCategoryRow) { return; } if( !d->moduleView->resolveChanges() ) { return; } d->activeCategoryIndex = idx; d->activeCategory = newCategoryRow; changeModule(idx); d->activeSubCategory = 0; emit activeCategoryChanged(); emit activeSubCategoryChanged(); } int SidebarMode::activeSubCategory() const { return d->activeSubCategory; } void SidebarMode::setActiveSubCategory(int cat) { if (d->activeSubCategory == cat) { return; } if( !d->moduleView->resolveChanges() ) { return; } d->activeSubCategory = cat; d->moduleView->closeModules(); d->moduleView->loadModule( d->subCategoryModel->index(cat, 0) ); emit activeSubCategoryChanged(); } int SidebarMode::width() const { return d->mainWidget->width(); } void SidebarMode::initWidget() { // Create the widgets if (!KMainWindow::memberList().isEmpty()) { KXmlGuiWindow *mainWindow = qobject_cast(KMainWindow::memberList().first()); if (mainWindow) { d->collection = mainWindow->actionCollection(); } } d->quickWidget = new QQuickWidget(d->mainWidget); d->quickWidget->quickWindow()->setTitle(i18n("Sidebar")); d->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); d->quickWidget->engine()->rootContext()->setContextProperty(QStringLiteral("systemsettings"), this); d->package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/GenericQML")); d->package.setPath(QStringLiteral("org.kde.systemsettings.sidebar")); d->kdeclarative.setDeclarativeEngine(d->quickWidget->engine()); d->kdeclarative.setupEngine(d->quickWidget->engine()); d->kdeclarative.setupContext(); d->quickWidget->setSource(QUrl::fromLocalFile(d->package.filePath("mainscript"))); if (!d->quickWidget->rootObject()) { for (const auto &err : d->quickWidget->errors()) { qWarning() << err.toString(); } qFatal("Fatal error while loading the sidebar view qml component"); } const int rootImplicitWidth = d->quickWidget->rootObject()->property("implicitWidth").toInt(); if (rootImplicitWidth != 0) { d->quickWidget->setFixedWidth(rootImplicitWidth); } else { d->quickWidget->setFixedWidth(240); } connect(d->quickWidget->rootObject(), &QQuickItem::implicitWidthChanged, this, [this]() { const int rootImplicitWidth = d->quickWidget->rootObject()->property("implicitWidth").toInt(); if (rootImplicitWidth != 0) { d->quickWidget->setFixedWidth(rootImplicitWidth); } else { d->quickWidget->setFixedWidth(240); } }); connect(d->quickWidget->rootObject(), SIGNAL(focusNextRequest()), d->mainWidget, SLOT(focusNext())); connect(d->quickWidget->rootObject(), SIGNAL(focusPreviousRequest()), d->mainWidget, SLOT(focusPrevious())); d->quickWidget->installEventFilter(this); d->toolTipManager = new ToolTipManager(d->searchModel, d->quickWidget); d->subCategoryToolTipManager = new ToolTipManager(d->subCategoryModel, d->quickWidget); d->placeHolderWidget = new QQuickWidget(d->mainWidget); d->placeHolderWidget->quickWindow()->setTitle(i18n("Most Used")); d->placeHolderWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); d->placeHolderWidget->engine()->rootContext()->setContextObject(new KLocalizedContext(d->placeHolderWidget)); d->placeHolderWidget->engine()->rootContext()->setContextProperty(QStringLiteral("systemsettings"), this); d->placeHolderWidget->setSource(QUrl::fromLocalFile(d->package.filePath("ui", QStringLiteral("introPage.qml")))); connect(d->placeHolderWidget->rootObject(), SIGNAL(focusNextRequest()), d->mainWidget, SLOT(focusNext())); connect(d->placeHolderWidget->rootObject(), SIGNAL(focusPreviousRequest()), d->mainWidget, SLOT(focusPrevious())); d->placeHolderWidget->installEventFilter(this); d->mainLayout->addWidget( d->quickWidget ); d->moduleView->hide(); d->mainLayout->addWidget( d->moduleView ); d->mainLayout->addWidget( d->placeHolderWidget ); emit changeToolBarItems(BaseMode::NoItems); d->mostUsedModel->setResultModel(new ResultModel( AllResources | Agent(QStringLiteral("org.kde.systemsettings")) | HighScoredFirst | Limit(5), this)); } bool SidebarMode::eventFilter(QObject* watched, QEvent* event) { //FIXME: those are all workarounds around the QQuickWidget brokeness if ((watched == d->quickWidget || watched == d->placeHolderWidget) && event->type() == QEvent::KeyPress) { //allow tab navigation inside the qquickwidget QKeyEvent *ke = static_cast(event); QQuickWidget *qqw = static_cast(watched); if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { QCoreApplication::sendEvent(qqw->quickWindow(), event); return true; } } else if ((watched == d->quickWidget || watched == d->placeHolderWidget) && event->type() == QEvent::FocusIn) { QFocusEvent *fe = static_cast(event); QQuickWidget *qqw = static_cast(watched); if (qqw && qqw->rootObject()) { if (fe->reason() == Qt::TabFocusReason) { QMetaObject::invokeMethod(qqw->rootObject(), "focusFirstChild"); } else if (fe->reason() == Qt::BacktabFocusReason) { QMetaObject::invokeMethod(qqw->rootObject(), "focusLastChild"); } } } else if (watched == d->quickWidget && event->type() == QEvent::Leave) { QCoreApplication::sendEvent(d->quickWidget->quickWindow(), event); } else if (watched == d->mainWidget && event->type() == QEvent::Resize) { emit widthChanged(); } else if (watched == d->mainWidget && event->type() == QEvent::Show) { emit changeToolBarItems(BaseMode::NoItems); } return BaseMode::eventFilter(watched, event); } void SidebarMode::giveFocus() { d->quickWidget->setFocus(); } #include "SidebarMode.moc"