KCMUtils

kpluginselector.cpp
1 /*
2  This file is part of the KDE project
3  SPDX-FileCopyrightText: 2007, 2006 Rafael Fernández López <[email protected]>
4  SPDX-FileCopyrightText: 2002-2003 Matthias Kretz <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #include "kpluginselector.h"
10 
11 #if KCMUTILS_BUILD_DEPRECATED_SINCE(5, 90)
12 
13 #include "kpluginselector_p.h"
14 
15 #include <kcmutils_debug.h>
16 
17 #include <QApplication>
18 #include <QCheckBox>
19 #include <QDialog>
20 #include <QDialogButtonBox>
21 #include <QDir>
22 #include <QDirIterator>
23 #include <QLabel>
24 #include <QLineEdit>
25 #include <QPainter>
26 #include <QPushButton>
27 #include <QStandardPaths>
28 #include <QStyle>
29 #include <QStyleOptionViewItem>
30 #include <QVBoxLayout>
31 
32 #include <KAboutPluginDialog>
33 #include <KCategorizedSortFilterProxyModel>
34 #include <KCategorizedView>
35 #include <KCategoryDrawer>
36 #include <KLocalizedString>
37 #include <KMessageBox>
38 #include <KPluginMetaData>
39 #include <KStandardGuiItem>
40 #include <KUrlLabel>
41 #include <kcmoduleinfo.h>
42 #include <kcmoduleproxy.h>
43 
44 #define MARGIN 5
45 
46 QT_WARNING_PUSH
47 QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
48 QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
49 
50 KPluginSelector::Private::Private(KPluginSelector *parent)
51  : QObject(parent)
52  , parent(parent)
53  , listView(nullptr)
54  , categoryDrawer(nullptr)
55  , pluginDelegate(nullptr)
56  , showIcons(false)
57  , showDefaultIndicator(false)
58 {
59 }
60 
61 KPluginSelector::Private::~Private()
62 {
63 }
64 
65 void KPluginSelector::Private::updateDependencies(PluginEntry *pluginEntry, bool added)
66 {
67  if (added) {
68  QStringList dependencyList = pluginEntry->pluginInfo.dependencies();
69 
70  if (dependencyList.isEmpty()) {
71  return;
72  }
73 
74  for (int i = 0; i < pluginModel->rowCount(); i++) {
75  const QModelIndex index = pluginModel->index(i, 0);
76  PluginEntry *pe = static_cast<PluginEntry *>(index.internalPointer());
77 
78  if ((pe->pluginInfo.pluginName() != pluginEntry->pluginInfo.pluginName()) && dependencyList.contains(pe->pluginInfo.pluginName()) && !pe->checked) {
79  dependenciesWidget->addDependency(pe->pluginInfo.name(), pluginEntry->pluginInfo.name(), added);
80  const_cast<QAbstractItemModel *>(index.model())->setData(index, added, Qt::CheckStateRole);
81  updateDependencies(pe, added);
82  }
83  }
84  } else {
85  for (int i = 0; i < pluginModel->rowCount(); i++) {
86  const QModelIndex index = pluginModel->index(i, 0);
87  PluginEntry *pe = static_cast<PluginEntry *>(index.internalPointer());
88 
89  if ((pe->pluginInfo.pluginName() != pluginEntry->pluginInfo.pluginName())
90  && pe->pluginInfo.dependencies().contains(pluginEntry->pluginInfo.pluginName()) && pe->checked) {
91  dependenciesWidget->addDependency(pe->pluginInfo.name(), pluginEntry->pluginInfo.name(), added);
92  const_cast<QAbstractItemModel *>(index.model())->setData(index, added, Qt::CheckStateRole);
93  updateDependencies(pe, added);
94  }
95  }
96  }
97 }
98 
99 int KPluginSelector::Private::dependantLayoutValue(int value, int width, int totalWidth) const
100 {
101  if (listView->layoutDirection() == Qt::LeftToRight) {
102  return value;
103  }
104 
105  return totalWidth - width - value;
106 }
107 
108 KPluginSelector::Private::DependenciesWidget::DependenciesWidget(QWidget *parent)
109  : QWidget(parent)
110  , addedByDependencies(0)
111  , removedByDependencies(0)
112 {
113  setVisible(false);
114 
115  details = new QLabel();
116 
117  QHBoxLayout *layout = new QHBoxLayout(this);
118 
119  QVBoxLayout *dataLayout = new QVBoxLayout;
121  layout->setAlignment(Qt::AlignLeft);
122  QLabel *label = new QLabel();
123  label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
124  label->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-information")).pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize)));
126  layout->addWidget(label);
127  KUrlLabel *link = new KUrlLabel();
128  link->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
129  link->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
130  link->setGlowEnabled(false);
131  link->setUnderline(false);
132  link->setFloatEnabled(true);
133  link->setUseCursor(true);
134  link->setHighlightedColor(palette().color(QPalette::Link));
135  link->setSelectedColor(palette().color(QPalette::Link));
136  link->setText(i18n("Automatic changes have been performed due to plugin dependencies. Click here for further information"));
137  dataLayout->addWidget(link);
138  dataLayout->addWidget(details);
139  layout->addLayout(dataLayout);
140 
141  QObject::connect(link, &KUrlLabel::leftClickedUrl, this, &KPluginSelector::Private::DependenciesWidget::showDependencyDetails);
142 }
143 
144 KPluginSelector::Private::DependenciesWidget::~DependenciesWidget()
145 {
146 }
147 
148 void KPluginSelector::Private::DependenciesWidget::addDependency(const QString &dependency, const QString &pluginCausant, bool added)
149 {
150  if (!isVisible()) {
151  setVisible(true);
152  }
153 
154  struct FurtherInfo furtherInfo;
155  furtherInfo.added = added;
156  furtherInfo.pluginCausant = pluginCausant;
157 
158  if (dependencyMap.contains(dependency)) { // The dependency moved from added to removed or vice-versa
159  if (added && removedByDependencies) {
160  removedByDependencies--;
161  } else if (addedByDependencies) {
162  addedByDependencies--;
163  }
164 
165  dependencyMap[dependency] = furtherInfo;
166  } else {
167  dependencyMap.insert(dependency, furtherInfo);
168  }
169 
170  if (added) {
171  addedByDependencies++;
172  } else {
173  removedByDependencies++;
174  }
175 
176  updateDetails();
177 }
178 
179 void KPluginSelector::Private::DependenciesWidget::userOverrideDependency(const QString &dependency)
180 {
181  if (dependencyMap.contains(dependency)) {
182  if (addedByDependencies && dependencyMap[dependency].added) {
183  addedByDependencies--;
184  } else if (removedByDependencies) {
185  removedByDependencies--;
186  }
187 
188  dependencyMap.remove(dependency);
189  }
190 
191  updateDetails();
192 }
193 
194 void KPluginSelector::Private::DependenciesWidget::clearDependencies()
195 {
196  addedByDependencies = 0;
197  removedByDependencies = 0;
198  dependencyMap.clear();
199  updateDetails();
200 }
201 
202 void KPluginSelector::Private::DependenciesWidget::showDependencyDetails()
203 {
204  QString message = i18n("Automatic changes have been performed in order to satisfy plugin dependencies:\n");
205 
206  for (auto it = dependencyMap.cbegin(); it != dependencyMap.cend(); ++it) {
207  const QString &dependency = it.key();
208  const FurtherInfo &info = it.value();
209  if (info.added) {
210  message += i18n("\n %1 plugin has been automatically checked because of the dependency of %2 plugin", dependency, info.pluginCausant);
211  } else {
212  message += i18n("\n %1 plugin has been automatically unchecked because of its dependency on %2 plugin", dependency, info.pluginCausant);
213  }
214  }
215 
216  KMessageBox::information(this, message, i18n("Dependency Check"));
217 
218  addedByDependencies = 0;
219  removedByDependencies = 0;
220  updateDetails();
221 }
222 
223 void KPluginSelector::Private::DependenciesWidget::updateDetails()
224 {
225  if (dependencyMap.isEmpty()) {
226  setVisible(false);
227  return;
228  }
229 
231 
232  if (addedByDependencies) {
233  message +=
234  i18np("%1 plugin automatically added due to plugin dependencies", "%1 plugins automatically added due to plugin dependencies", addedByDependencies);
235  }
236 
237  if (removedByDependencies && !message.isEmpty()) {
238  message += i18n(", ");
239  }
240 
241  if (removedByDependencies) {
242  message += i18np("%1 plugin automatically removed due to plugin dependencies",
243  "%1 plugins automatically removed due to plugin dependencies",
244  removedByDependencies);
245  }
246 
247  if (message.isEmpty()) {
248  details->setVisible(false);
249  } else {
250  details->setVisible(true);
251  details->setText(message);
252  }
253 }
254 
256  : QWidget(parent)
257  , d(new Private(this))
258 {
259  QVBoxLayout *layout = new QVBoxLayout(this);
260  layout->setContentsMargins(0, 0, 0, 0);
261 
262  d->lineEdit = new QLineEdit(this);
263  d->lineEdit->setClearButtonEnabled(true);
264  d->lineEdit->setPlaceholderText(i18n("Search..."));
265  d->listView = new KCategorizedView(this);
266  d->categoryDrawer = new KCategoryDrawer(d->listView);
267  d->listView->setVerticalScrollMode(QListView::ScrollPerPixel);
268  d->listView->setAlternatingRowColors(true);
269  d->listView->setCategoryDrawer(d->categoryDrawer);
270  d->dependenciesWidget = new Private::DependenciesWidget(this);
271 
272  d->pluginModel = new Private::PluginModel(d, this);
273  d->proxyModel = new Private::ProxyModel(d, this);
274  d->proxyModel->setCategorizedModel(true);
275  d->proxyModel->setSourceModel(d->pluginModel);
276  d->listView->setModel(d->proxyModel);
277  d->listView->setAlternatingRowColors(true);
278 
279  Private::PluginDelegate *pluginDelegate = new Private::PluginDelegate(d, this);
280  d->listView->setItemDelegate(pluginDelegate);
281 
282  d->listView->setMouseTracking(true);
283  d->listView->viewport()->setAttribute(Qt::WA_Hover);
284 
285  connect(d->lineEdit, &QLineEdit::textChanged, d->proxyModel, &QSortFilterProxyModel::invalidate);
286  connect(pluginDelegate, &Private::PluginDelegate::changed, this, &KPluginSelector::changed);
287  connect(pluginDelegate, &Private::PluginDelegate::configCommitted, this, &KPluginSelector::configCommitted);
288  connect(this, &KPluginSelector::defaultsIndicatorsVisible, pluginDelegate, &Private::PluginDelegate::slotResetModel);
289 
290  connect(this, &KPluginSelector::changed, [this] {
292  });
293 
294  layout->addWidget(d->lineEdit);
295  layout->addWidget(d->listView);
296  layout->addWidget(d->dependenciesWidget);
297 
298  // When a KPluginSelector instance gets focus,
299  // it should pass over the focus to its child searchbar.
300  setFocusProxy(d->lineEdit);
301 }
302 
304 {
305  delete d->listView->itemDelegate();
306  delete d->listView; // depends on some other things in d, make sure this dies first.
307  delete d;
308 }
309 
310 void KPluginSelector::addPlugins(const QString &componentName, const QString &categoryName, const QString &categoryKey, KSharedConfig::Ptr config)
311 {
312  QStringList desktopFileNames;
313  const QStringList dirs =
314  QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, componentName + QStringLiteral("/kpartplugins"), QStandardPaths::LocateDirectory);
315  for (const QString &dir : dirs) {
316  QDirIterator it(dir, QStringList() << QStringLiteral("*.desktop"), QDir::NoFilter, QDirIterator::Subdirectories);
317  while (it.hasNext()) {
318  desktopFileNames.append(it.next());
319  }
320  }
321 
322  QList<KPluginInfo> pluginInfoList = KPluginInfo::fromFiles(desktopFileNames);
323 
324  if (pluginInfoList.isEmpty()) {
325  return;
326  }
327 
328  if (!config) {
329  config = KSharedConfig::openConfig(componentName + QStringLiteral("rc"));
330  }
331  Q_ASSERT(config);
332 
333  KConfigGroup cfgGroup(config, "KParts Plugins");
334  // qDebug() << "cfgGroup = " << &cfgGroup;
335 
336  d->pluginModel->addPlugins(pluginInfoList, categoryName, categoryKey, cfgGroup);
337  d->proxyModel->sort(0);
338 }
339 
341  PluginLoadMethod pluginLoadMethod,
342  const QString &categoryName,
343  const QString &categoryKey,
344  const KSharedConfig::Ptr &config)
345 {
346  if (pluginInfoList.isEmpty()) {
347  return;
348  }
349 
350  KConfigGroup cfgGroup(config ? config : KSharedConfig::openConfig(), "Plugins");
351  // qDebug() << "cfgGroup = " << &cfgGroup;
352 
353  d->pluginModel->addPlugins(pluginInfoList, categoryName, categoryKey, cfgGroup, pluginLoadMethod, true /* manually added */);
354  d->proxyModel->sort(0);
355 }
356 
358 {
359  d->pluginModel->clear();
360 }
361 
363 {
364  for (int i = 0; i < d->pluginModel->rowCount(); i++) {
365  const QModelIndex index = d->pluginModel->index(i, 0);
366  PluginEntry *pluginEntry = static_cast<PluginEntry *>(index.internalPointer());
367  pluginEntry->pluginInfo.load(pluginEntry->cfgGroup);
368  d->pluginModel->setData(index, pluginEntry->pluginInfo.isPluginEnabled(), Qt::CheckStateRole);
369  }
370 
371  static_cast<KPluginSelector::Private::PluginDelegate *>(d->listView->itemDelegate())->clearChangedEntries();
372  Q_EMIT changed(false);
373 }
374 
376 {
377  for (int i = 0; i < d->pluginModel->rowCount(); i++) {
378  const QModelIndex index = d->pluginModel->index(i, 0);
379  PluginEntry *pluginEntry = static_cast<PluginEntry *>(index.internalPointer());
380  pluginEntry->pluginInfo.setPluginEnabled(pluginEntry->checked);
381  pluginEntry->pluginInfo.save(pluginEntry->cfgGroup);
382  pluginEntry->cfgGroup.sync();
383  }
384 
385  static_cast<KPluginSelector::Private::PluginDelegate *>(d->listView->itemDelegate())->clearChangedEntries();
386  Q_EMIT changed(false);
387 }
388 
390 {
391  for (int i = 0; i < d->pluginModel->rowCount(); i++) {
392  const QModelIndex index = d->pluginModel->index(i, 0);
393  PluginEntry *pluginEntry = static_cast<PluginEntry *>(index.internalPointer());
394  if (d->pluginModel->data(index, Qt::CheckStateRole).toBool() != pluginEntry->pluginInfo.isPluginEnabled()) {
395  return true;
396  }
397  }
398 
399  return false;
400 }
401 
403 {
404  bool isChanged = false;
405  auto delegate = static_cast<KPluginSelector::Private::PluginDelegate *>(d->listView->itemDelegate());
406  delegate->clearChangedEntries();
407  for (int i = 0; i < d->pluginModel->rowCount(); i++) {
408  const QModelIndex index = d->pluginModel->index(i, 0);
409  PluginEntry *pluginEntry = static_cast<PluginEntry *>(index.internalPointer());
410  bool entryChanged = pluginEntry->pluginInfo.isPluginEnabled() != pluginEntry->pluginInfo.isPluginEnabledByDefault();
411  isChanged |= entryChanged;
412  d->pluginModel->setData(index, pluginEntry->pluginInfo.isPluginEnabledByDefault(), Qt::CheckStateRole);
413  if (entryChanged) {
414  delegate->addChangedEntry(pluginEntry);
415  }
416  }
417 
418  Q_EMIT changed(isChanged);
419 }
420 
422 {
423  for (int i = 0; i < d->pluginModel->rowCount(); i++) {
424  const QModelIndex index = d->pluginModel->index(i, 0);
425  PluginEntry *pluginEntry = static_cast<PluginEntry *>(index.internalPointer());
426  if (d->pluginModel->data(index, Qt::CheckStateRole).toBool() != pluginEntry->pluginInfo.isPluginEnabledByDefault()) {
427  return false;
428  }
429  }
430 
431  return true;
432 }
433 
435 {
436  static_cast<KPluginSelector::Private::PluginDelegate *>(d->listView->itemDelegate())->clearChangedEntries();
437  for (int i = 0; i < d->pluginModel->rowCount(); i++) {
438  const QModelIndex index = d->pluginModel->index(i, 0);
439  PluginEntry *pluginEntry = static_cast<PluginEntry *>(index.internalPointer());
440  if (pluginEntry->manuallyAdded) {
441  pluginEntry->pluginInfo.setPluginEnabled(pluginEntry->checked);
442  }
443  }
444 }
445 
447 {
448  d->kcmArguments = arguments;
449 }
450 
451 QStringList KPluginSelector::configurationArguments() const
452 {
453  return d->kcmArguments;
454 }
455 
456 void KPluginSelector::showConfiguration(const QString &componentName)
457 {
458  QModelIndex idx;
459  for (int i = 0, c = d->proxyModel->rowCount(); i < c; ++i) {
460  const auto currentIndex = d->proxyModel->index(i, 0);
461  const auto entry = currentIndex.data(KPluginSelector::Private::PluginEntryRole).value<PluginEntry *>();
462  if (entry->pluginInfo.pluginName() == componentName) {
463  idx = currentIndex;
464  break;
465  }
466  }
467 
468  if (idx.isValid()) {
469  auto delegate = static_cast<KPluginSelector::Private::PluginDelegate *>(d->listView->itemDelegate());
470  delegate->configure(idx);
471  } else {
472  qCWarning(KCMUTILS_LOG) << "Could not find plugin" << componentName;
473  }
474 }
475 
477 {
478  static_cast<Private::PluginDelegate *>(d->listView->itemDelegate())->setHandler(handler);
479 }
480 
482 {
483  if (isVisible != d->showDefaultIndicator) {
484  d->showDefaultIndicator = isVisible;
486  }
487 }
488 
489 KPluginSelector::Private::PluginModel::PluginModel(KPluginSelector::Private *pluginSelector_d, QObject *parent)
490  : QAbstractListModel(parent)
491  , pluginSelector_d(pluginSelector_d)
492 {
493 }
494 
495 KPluginSelector::Private::PluginModel::~PluginModel()
496 {
497 }
498 
499 static bool hasServiceNoDisplaySet(const KPluginInfo &pluginInfo)
500 {
501  QT_WARNING_PUSH
502  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
503  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
504  return pluginInfo.service() && pluginInfo.service()->noDisplay();
505  QT_WARNING_POP
506 }
507 
508 void KPluginSelector::Private::PluginModel::addPlugins(const QList<KPluginInfo> &pluginList,
509  const QString &categoryName,
510  const QString &categoryKey,
511  const KConfigGroup &cfgGroup,
512  PluginLoadMethod pluginLoadMethod,
513  bool manuallyAdded)
514 {
515  QList<PluginEntry> listToAdd;
516 
517  for (const KPluginInfo &pluginInfo : pluginList) {
518  PluginEntry pluginEntry;
519  pluginEntry.category = categoryName;
520  pluginEntry.pluginInfo = pluginInfo;
521  if (pluginLoadMethod == ReadConfigFile) {
522  pluginEntry.pluginInfo.load(cfgGroup);
523  }
524  pluginEntry.checked = pluginInfo.isPluginEnabled();
525  pluginEntry.manuallyAdded = manuallyAdded;
526  if (cfgGroup.isValid()) {
527  pluginEntry.cfgGroup = cfgGroup;
528  } else {
529  pluginEntry.cfgGroup = pluginInfo.config();
530  }
531 
532  // this is where kiosk will set if a plugin is checkable or not (pluginName + "Enabled")
533  pluginEntry.isCheckable = !pluginInfo.isValid() || !pluginEntry.cfgGroup.isEntryImmutable(pluginInfo.pluginName() + QLatin1String("Enabled"));
534 
535  if (!pluginEntryList.contains(pluginEntry) && !listToAdd.contains(pluginEntry)
536  && (categoryKey.isEmpty() || !pluginInfo.category().compare(categoryKey, Qt::CaseInsensitive)) && (!hasServiceNoDisplaySet(pluginInfo))) {
537  listToAdd << pluginEntry;
538 
539  if (!pluginSelector_d->showIcons && !pluginInfo.icon().isEmpty()) {
540  pluginSelector_d->showIcons = true;
541  }
542  }
543  }
544 
545  if (!listToAdd.isEmpty()) {
546  beginInsertRows(QModelIndex(), pluginEntryList.count(), pluginEntryList.count() + listToAdd.count() - 1);
547  pluginEntryList << listToAdd;
548  endInsertRows();
549  }
550 }
551 
552 void KPluginSelector::Private::PluginModel::clear()
553 {
554  beginResetModel();
555  pluginEntryList.clear();
556  endResetModel();
557 }
558 
559 QModelIndex KPluginSelector::Private::PluginModel::index(int row, int column, const QModelIndex &parent) const
560 {
561  Q_UNUSED(parent)
562 
563  return createIndex(row, column, (row < pluginEntryList.count()) ? (void *)&pluginEntryList.at(row) : nullptr);
564 }
565 
566 QVariant KPluginSelector::Private::PluginModel::data(const QModelIndex &index, int role) const
567 {
568  if (!index.isValid() || !index.internalPointer()) {
569  return QVariant();
570  }
571 
572  PluginEntry *pluginEntry = static_cast<PluginEntry *>(index.internalPointer());
573 
574  switch (role) {
575  case Qt::DisplayRole:
576  return pluginEntry->pluginInfo.name();
577  case PluginEntryRole:
578  return QVariant::fromValue(pluginEntry);
579  case ServicesCountRole:
580  return pluginEntry->pluginInfo.kcmServices().count() +
581  // if we have a X-KDE-ConfigModule key, we know that we have a config module
582  (pluginEntry->pluginInfo.property(QStringLiteral("X-KDE-ConfigModule")).toString().isEmpty() ? 0 : 1);
583  case NameRole:
584  return pluginEntry->pluginInfo.name();
585  case CommentRole:
586  return pluginEntry->pluginInfo.comment();
587  case AuthorRole:
588  return pluginEntry->pluginInfo.author();
589  case EmailRole:
590  return pluginEntry->pluginInfo.email();
591  case WebsiteRole:
592  return pluginEntry->pluginInfo.website();
593  case VersionRole:
594  return pluginEntry->pluginInfo.version();
595  case LicenseRole:
596  return pluginEntry->pluginInfo.license();
597  case DependenciesRole:
598  return pluginEntry->pluginInfo.dependencies();
599  case IsCheckableRole:
600  return pluginEntry->isCheckable;
601  case Qt::DecorationRole:
602  return pluginEntry->pluginInfo.icon();
603  case Qt::CheckStateRole:
604  return pluginEntry->checked;
607  return pluginEntry->category;
608  default:
609  return QVariant();
610  }
611 }
612 
613 bool KPluginSelector::Private::PluginModel::setData(const QModelIndex &index, const QVariant &value, int role)
614 {
615  if (!index.isValid()) {
616  return false;
617  }
618 
619  bool ret = false;
620 
621  if (role == Qt::CheckStateRole) {
622  static_cast<PluginEntry *>(index.internalPointer())->checked = value.toBool();
623  ret = true;
624  }
625 
626  if (ret) {
627  Q_EMIT dataChanged(index, index);
628  }
629 
630  return ret;
631 }
632 
633 int KPluginSelector::Private::PluginModel::rowCount(const QModelIndex &parent) const
634 {
635  if (parent.isValid()) {
636  return 0;
637  }
638 
639  return pluginEntryList.count();
640 }
641 
642 KPluginSelector::Private::ProxyModel::ProxyModel(KPluginSelector::Private *pluginSelector_d, QObject *parent)
644  , pluginSelector_d(pluginSelector_d)
645 {
646  sort(0);
647 }
648 
649 KPluginSelector::Private::ProxyModel::~ProxyModel()
650 {
651 }
652 
653 bool KPluginSelector::Private::ProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
654 {
655  Q_UNUSED(sourceParent)
656 
657  if (!pluginSelector_d->lineEdit->text().isEmpty()) {
658  const QModelIndex index = sourceModel()->index(sourceRow, 0);
659  const KPluginInfo pluginInfo = static_cast<PluginEntry *>(index.internalPointer())->pluginInfo;
660  return pluginInfo.name().contains(pluginSelector_d->lineEdit->text(), Qt::CaseInsensitive)
661  || pluginInfo.comment().contains(pluginSelector_d->lineEdit->text(), Qt::CaseInsensitive);
662  }
663 
664  return true;
665 }
666 
667 bool KPluginSelector::Private::ProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const
668 {
669  return static_cast<PluginEntry *>(left.internalPointer())
670  ->pluginInfo.name()
671  .compare(static_cast<PluginEntry *>(right.internalPointer())->pluginInfo.name(), Qt::CaseInsensitive)
672  < 0;
673 }
674 
675 KPluginSelector::Private::PluginDelegate::PluginDelegate(KPluginSelector::Private *pluginSelector_d, QObject *parent)
676  : KWidgetItemDelegate(pluginSelector_d->listView, parent)
677  , checkBox(new QCheckBox)
678  , pushButton(new QPushButton)
679  , pluginSelector_d(pluginSelector_d)
680 {
681  pushButton->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); // only for getting size matters
682 }
683 
684 KPluginSelector::Private::PluginDelegate::~PluginDelegate()
685 {
686  delete checkBox;
687  delete pushButton;
688 }
689 
690 void KPluginSelector::Private::PluginDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
691 {
692  if (!index.isValid()) {
693  return;
694  }
695 
696  int xOffset = checkBox->sizeHint().width();
697  bool disabled = !index.model()->data(index, IsCheckableRole).toBool();
698 
699  painter->save();
700 
701  QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, nullptr);
702 
703  int iconSize = option.rect.height() - MARGIN * 2;
704  if (pluginSelector_d->showIcons) {
705  QIcon icon = QIcon::fromTheme(index.model()->data(index, Qt::DecorationRole).toString());
706  icon.paint(painter,
707  QRect(pluginSelector_d->dependantLayoutValue(MARGIN + option.rect.left() + xOffset, iconSize, option.rect.width()),
708  MARGIN + option.rect.top(),
709  iconSize,
710  iconSize));
711  } else {
712  iconSize = -MARGIN;
713  }
714 
715  QRect contentsRect(pluginSelector_d->dependantLayoutValue(MARGIN * 2 + iconSize + option.rect.left() + xOffset,
716  option.rect.width() - MARGIN * 3 - iconSize - xOffset,
717  option.rect.width()),
718  MARGIN + option.rect.top(),
719  option.rect.width() - MARGIN * 3 - iconSize - xOffset,
720  option.rect.height() - MARGIN * 2);
721 
722  int lessHorizontalSpace = MARGIN * 2 + pushButton->sizeHint().width();
723  if (index.model()->data(index, ServicesCountRole).toBool()) {
724  lessHorizontalSpace += MARGIN + pushButton->sizeHint().width();
725  }
726  // Reserve space for extra button
727  if (handler) {
728  lessHorizontalSpace += MARGIN + pushButton->sizeHint().width();
729  }
730 
731  contentsRect.setWidth(contentsRect.width() - lessHorizontalSpace);
732 
733  if (option.state & QStyle::State_Selected) {
734  painter->setPen(option.palette.highlightedText().color());
735  }
736 
737  if (pluginSelector_d->listView->layoutDirection() == Qt::RightToLeft) {
738  contentsRect.translate(lessHorizontalSpace, 0);
739  }
740 
741  painter->save();
742  if (disabled) {
743  QPalette pal(option.palette);
744  pal.setCurrentColorGroup(QPalette::Disabled);
745  painter->setPen(pal.text().color());
746  }
747 
748  painter->save();
749  QFont font = titleFont(option.font);
750  QFontMetrics fmTitle(font);
751  painter->setFont(font);
752  painter->drawText(contentsRect,
754  fmTitle.elidedText(index.model()->data(index, Qt::DisplayRole).toString(), Qt::ElideRight, contentsRect.width()));
755  painter->restore();
756 
757  painter->drawText(contentsRect,
759  option.fontMetrics.elidedText(index.model()->data(index, CommentRole).toString(), Qt::ElideRight, contentsRect.width()));
760 
761  painter->restore();
762  painter->restore();
763 }
764 
765 QSize KPluginSelector::Private::PluginDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
766 {
767  int i = 5;
768  int j = 1;
769  if (index.model()->data(index, ServicesCountRole).toBool()) {
770  i = 6;
771  j = 2;
772  }
773  // Reserve space for extra button
774  if (handler) {
775  ++j;
776  }
777 
778  if (!pluginSelector_d->showIcons) {
779  i--;
780  }
781 
782  const QFont font = titleFont(option.font);
783  const QFontMetrics fmTitle(font);
784  const QString text = index.model()->data(index, Qt::DisplayRole).toString();
785  const QString comment = index.model()->data(index, CommentRole).toString();
786  const int maxTextWidth = qMax(fmTitle.boundingRect(text).width(), option.fontMetrics.boundingRect(comment).width());
787 
788  const auto iconSize = pluginSelector_d->listView->style()->pixelMetric(QStyle::PM_IconViewIconSize);
789  return QSize(maxTextWidth + (pluginSelector_d->showIcons ? iconSize : 0) + MARGIN * i + pushButton->sizeHint().width() * j,
790  qMax(iconSize + MARGIN * 2, fmTitle.height() + option.fontMetrics.height() + MARGIN * 2));
791 }
792 
793 QList<QWidget *> KPluginSelector::Private::PluginDelegate::createItemWidgets(const QModelIndex &index) const
794 {
795  Q_UNUSED(index);
796  QList<QWidget *> widgetList;
797 
798  QCheckBox *enabledCheckBox = new QCheckBox;
799  connect(enabledCheckBox, &QAbstractButton::clicked, this, &PluginDelegate::slotStateChanged);
800  connect(enabledCheckBox, &QAbstractButton::clicked, this, &PluginDelegate::emitChanged);
801 
802  QPushButton *aboutPushButton = new QPushButton;
803  aboutPushButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-information")));
804  aboutPushButton->setToolTip(i18n("About"));
805  connect(aboutPushButton, &QAbstractButton::clicked, this, &PluginDelegate::slotAboutClicked);
806 
807  QPushButton *configurePushButton = new QPushButton;
808  configurePushButton->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
809  configurePushButton->setToolTip(i18n("Configure"));
810  connect(configurePushButton, &QAbstractButton::clicked, this, &PluginDelegate::slotConfigureClicked);
811 
812  setBlockedEventTypes(enabledCheckBox,
814  << QEvent::KeyRelease);
815 
816  setBlockedEventTypes(aboutPushButton,
818  << QEvent::KeyRelease);
819 
820  setBlockedEventTypes(configurePushButton,
822  << QEvent::KeyRelease);
823 
824  widgetList << enabledCheckBox << configurePushButton << aboutPushButton;
825  if (handler) {
826  QPushButton *btn = handler(pluginSelector_d->pluginModel->pluginEntryList.at(index.row()).pluginInfo);
827  if (btn) {
828  widgetList << btn;
829  }
830  }
831 
832  return widgetList;
833 }
834 
835 void KPluginSelector::Private::PluginDelegate::updateItemWidgets(const QList<QWidget *> widgets,
836  const QStyleOptionViewItem &option,
837  const QPersistentModelIndex &index) const
838 {
839  int extraButtonWidth = 0;
840  QPushButton *extraButton = nullptr;
841  if (widgets.count() == 4) {
842  extraButton = static_cast<QPushButton *>(widgets[3]);
843  extraButtonWidth = extraButton->sizeHint().width() + MARGIN;
844  }
845  QCheckBox *checkBox = static_cast<QCheckBox *>(widgets[0]);
846  checkBox->resize(checkBox->sizeHint());
847  checkBox->move(pluginSelector_d->dependantLayoutValue(MARGIN, checkBox->sizeHint().width(), option.rect.width()),
848  option.rect.height() / 2 - checkBox->sizeHint().height() / 2);
849 
850  QPushButton *aboutPushButton = static_cast<QPushButton *>(widgets[2]);
851  QSize aboutPushButtonSizeHint = aboutPushButton->sizeHint();
852  aboutPushButton->resize(aboutPushButtonSizeHint);
853  aboutPushButton->move(pluginSelector_d->dependantLayoutValue(option.rect.width() - MARGIN - aboutPushButtonSizeHint.width() - extraButtonWidth,
854  aboutPushButtonSizeHint.width(),
855  option.rect.width()),
856  option.rect.height() / 2 - aboutPushButtonSizeHint.height() / 2);
857 
858  QPushButton *configurePushButton = static_cast<QPushButton *>(widgets[1]);
859  QSize configurePushButtonSizeHint = configurePushButton->sizeHint();
860  configurePushButton->resize(configurePushButtonSizeHint);
861  configurePushButton->move(pluginSelector_d->dependantLayoutValue(option.rect.width() - MARGIN * 2 - configurePushButtonSizeHint.width()
862  - aboutPushButtonSizeHint.width() - extraButtonWidth,
863  configurePushButtonSizeHint.width(),
864  option.rect.width()),
865  option.rect.height() / 2 - configurePushButtonSizeHint.height() / 2);
866  if (extraButton) {
867  QSize extraPushButtonSizeHint = extraButton->sizeHint();
868  extraButton->resize(extraPushButtonSizeHint);
869  extraButton->move(pluginSelector_d->dependantLayoutValue(option.rect.width() - extraButtonWidth, extraPushButtonSizeHint.width(), option.rect.width()),
870  option.rect.height() / 2 - extraPushButtonSizeHint.height() / 2);
871  }
872 
873  if (!index.isValid() || !index.internalPointer()) {
874  checkBox->setVisible(false);
875  aboutPushButton->setVisible(false);
876  configurePushButton->setVisible(false);
877  if (extraButton) {
878  extraButton->setVisible(false);
879  }
880  } else {
881  PluginEntry *pluginEntry = index.model()->data(index, PluginEntryRole).value<PluginEntry *>();
882  bool isDefault = pluginEntry->pluginInfo.isPluginEnabledByDefault() == index.model()->data(index, Qt::CheckStateRole).toBool();
883  checkBox->setProperty("_kde_highlight_neutral", pluginSelector_d->showDefaultIndicator && !isDefault);
884 
885  checkBox->setChecked(index.model()->data(index, Qt::CheckStateRole).toBool());
886  checkBox->setEnabled(index.model()->data(index, IsCheckableRole).toBool());
887  configurePushButton->setVisible(index.model()->data(index, ServicesCountRole).toBool());
888  configurePushButton->setEnabled(index.model()->data(index, Qt::CheckStateRole).toBool());
889  }
890 }
891 
892 void KPluginSelector::Private::PluginDelegate::slotStateChanged(bool state)
893 {
894  if (!focusedIndex().isValid()) {
895  return;
896  }
897 
898  const QModelIndex index = focusedIndex();
899 
900  pluginSelector_d->dependenciesWidget->clearDependencies();
901 
902  PluginEntry *pluginEntry = index.model()->data(index, PluginEntryRole).value<PluginEntry *>();
903  pluginSelector_d->updateDependencies(pluginEntry, state);
904 
905  const_cast<QAbstractItemModel *>(index.model())->setData(index, state, Qt::CheckStateRole);
906 }
907 
908 void KPluginSelector::Private::PluginDelegate::emitChanged(bool state)
909 {
910  const QModelIndex index = focusedIndex();
911  PluginEntry *pluginEntry = index.model()->data(index, PluginEntryRole).value<PluginEntry *>();
912 
913  if (pluginEntry->pluginInfo.isPluginEnabled() != state) {
914  changedEntries << pluginEntry;
915  } else {
916  changedEntries.remove(pluginEntry);
917  }
918  Q_EMIT changed(!changedEntries.isEmpty());
919 }
920 
921 void KPluginSelector::Private::PluginDelegate::slotAboutClicked()
922 {
923  const QModelIndex index = focusedIndex();
924  const QAbstractItemModel *model = index.model();
925 
926  PluginEntry *pluginEntry = model->data(index, PluginEntryRole).value<PluginEntry *>();
927  KPluginMetaData pluginMetaData = pluginEntry->pluginInfo.toMetaData();
928 
929  auto *aboutPlugin = new KAboutPluginDialog(pluginMetaData, itemView());
930  aboutPlugin->setAttribute(Qt::WA_DeleteOnClose);
931  aboutPlugin->show();
932 }
933 
934 void KPluginSelector::Private::PluginDelegate::slotConfigureClicked()
935 {
936  configure(focusedIndex());
937 }
938 
939 void KPluginSelector::Private::PluginDelegate::configure(const QModelIndex &index)
940 {
941  const QAbstractItemModel *model = index.model();
942 
943  PluginEntry *pluginEntry = model->data(index, PluginEntryRole).value<PluginEntry *>();
944  KPluginInfo pluginInfo = pluginEntry->pluginInfo;
945 
946  QDialog configDialog(itemView());
947  configDialog.setWindowTitle(model->data(index, NameRole).toString());
948  // The number of KCModuleProxies in use determines whether to use a tabwidget
949  QTabWidget *newTabWidget = nullptr;
950  // Widget to use for the setting dialog's main widget,
951  // either a QTabWidget or a KCModuleProxy
952  QWidget *mainWidget = nullptr;
953  // Widget to use as the KCModuleProxy's parent.
954  // The first proxy is owned by the dialog itself
955  QWidget *moduleProxyParentWidget = &configDialog;
956 
957  QVector<KPluginMetaData> metaDataList;
958  const auto lstServices = KPluginInfo::fromServices(pluginInfo.kcmServices());
959  for (const KPluginInfo &info : lstServices) {
960  metaDataList << info.toMetaData();
961  }
962  const QString configModule = pluginInfo.property(QStringLiteral("X-KDE-ConfigModule")).toString();
963  if (!configModule.isEmpty()) {
964  const QString absoluteKCMPath = QPluginLoader(configModule).fileName();
965  // If we have a static plugin the filename does not exist
966  if (absoluteKCMPath.isEmpty()) {
967  const int idx = configModule.lastIndexOf(QLatin1Char('/'));
968  const QString pluginNamespace = configModule.left(idx);
969  const QString pluginId = configModule.mid(idx + 1);
970  metaDataList = {KPluginMetaData::findPluginById(pluginNamespace, pluginId)}; // Clear the list to avoid old desktop files to appear twice
971  } else {
972  // the KCMs don't need any metadata themselves, just use the one from the KPluginInfo object
973  // this way for example a KPackage plugin can specify plugin keyword
974  KPluginMetaData data(pluginInfo.toMetaData().rawData(), absoluteKCMPath);
975  metaDataList = {data}; // Clear the list to avoid old desktop files to appear twice
976  }
977  }
978  for (const KPluginMetaData &data : std::as_const(metaDataList)) {
979  if (!data.rawData().value(QStringLiteral("NoDisplay")).toBool()) {
980  KCModuleProxy *currentModuleProxy = new KCModuleProxy(data, moduleProxyParentWidget, pluginSelector_d->kcmArguments);
981  if (currentModuleProxy->realModule()) {
982  moduleProxyList << currentModuleProxy;
983  if (mainWidget && !newTabWidget) {
984  // we already created one KCModuleProxy, so we need a tab widget.
985  // Move the first proxy into the tab widget and ensure this and subsequent
986  // proxies are in the tab widget
987  newTabWidget = new QTabWidget(&configDialog);
988  moduleProxyParentWidget = newTabWidget;
989  mainWidget->setParent(newTabWidget);
990  KCModuleProxy *moduleProxy = qobject_cast<KCModuleProxy *>(mainWidget);
991  if (moduleProxy) {
992  newTabWidget->addTab(mainWidget, data.name());
993  mainWidget = newTabWidget;
994  } else {
995  delete newTabWidget;
996  newTabWidget = nullptr;
997  moduleProxyParentWidget = &configDialog;
998  mainWidget->setParent(nullptr);
999  }
1000  }
1001 
1002  if (newTabWidget) {
1003  newTabWidget->addTab(currentModuleProxy, pluginInfo.name());
1004  } else {
1005  mainWidget = currentModuleProxy;
1006  }
1007  } else {
1008  delete currentModuleProxy;
1009  }
1010  }
1011  }
1012 
1013  // it could happen that we had services to show, but none of them were real modules.
1014  if (!moduleProxyList.isEmpty()) {
1015  QVBoxLayout *layout = new QVBoxLayout(&configDialog);
1016  layout->addWidget(mainWidget);
1017 
1018  QDialogButtonBox *buttonBox = new QDialogButtonBox(&configDialog);
1023  connect(buttonBox, &QDialogButtonBox::accepted, &configDialog, &QDialog::accept);
1024  connect(buttonBox, &QDialogButtonBox::rejected, &configDialog, &QDialog::reject);
1025  connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this, &PluginDelegate::slotDefaultClicked);
1026  layout->addWidget(buttonBox);
1027 
1028  if (configDialog.exec() == QDialog::Accepted) {
1029  for (KCModuleProxy *moduleProxy : std::as_const(moduleProxyList)) {
1030  QStringList parentComponents;
1031 #if KCMUTILS_BUILD_DEPRECATED_SINCE(5, 88)
1032  if (moduleProxy->moduleInfo().isValid()) {
1033  parentComponents = moduleProxy->moduleInfo().property(QStringLiteral("X-KDE-ParentComponents")).toStringList();
1034  }
1035 #else
1036  if (moduleProxy->metaData().isValid()) {
1037  parentComponents = moduleProxy->metaData().rawData().value(QStringLiteral("X-KDE-ParentComponents")).toVariant().toStringList();
1038  }
1039 #endif
1040  moduleProxy->save();
1041  for (const QString &parentComponent : std::as_const(parentComponents)) {
1042  Q_EMIT configCommitted(parentComponent.toLatin1());
1043  }
1044  }
1045  } else {
1046  for (KCModuleProxy *moduleProxy : std::as_const(moduleProxyList)) {
1047  moduleProxy->load();
1048  }
1049  }
1050 
1051  qDeleteAll(moduleProxyList);
1052  moduleProxyList.clear();
1053  }
1054 }
1055 
1056 void KPluginSelector::Private::PluginDelegate::slotDefaultClicked()
1057 {
1058  for (KCModuleProxy *moduleProxy : std::as_const(moduleProxyList)) {
1059  moduleProxy->defaults();
1060  }
1061 }
1062 
1063 void KPluginSelector::Private::PluginDelegate::slotResetModel()
1064 {
1065  resetModel();
1066 }
1067 
1068 QFont KPluginSelector::Private::PluginDelegate::titleFont(const QFont &baseFont) const
1069 {
1070  QFont retFont(baseFont);
1071  retFont.setBold(true);
1072 
1073  return retFont;
1074 }
1075 void KPluginSelector::Private::PluginDelegate::setHandler(std::function<QPushButton *(const KPluginInfo &)> handler)
1076 {
1077  this->handler = handler;
1078 }
1079 
1080 #include "moc_kpluginselector.cpp"
1081 #include "moc_kpluginselector_p.cpp"
1082 #endif
void append(const T &value)
AlignLeft
QJsonObject rawData() const
QTextStream & right(QTextStream &stream)
void setParent(QWidget *parent)
virtual QSize sizeHint() const const override
void changed(bool hasChanged)
Tells you whether the configuration is changed or not.
void setPen(const QColor &color)
CheckStateRole
MouseButtonPress
const QAbstractItemModel * model() const const
Encapsulates a KCModule for embedding.
Definition: kcmoduleproxy.h:55
static KPluginInfo::List fromServices(const KService::List &services, const KConfigGroup &config=KConfigGroup())
~KPluginSelector() override
Destructor.
void load()
Load the state of the plugins (selected or not) from the KPluginInfo objects.
virtual void reject()
void load()
Calling it will cause the contained module to run its load() routine.
CaseInsensitive
QVariant fromValue(const T &value)
void * internalPointer() const const
A widget to select what plugins to load and configure the plugins.
KGuiItem configure()
Q_EMITQ_EMIT
virtual QVariant data(const QModelIndex &index, int role) const const=0
int count(const T &value) const const
T value() const const
QLayout * layout() const const
QString icon() const
QTextStream & left(QTextStream &stream)
bool hasNext() const const
KPluginSelector(QWidget *parent=nullptr)
Create a new KPluginSelector.
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void setConfigurationArguments(const QStringList &arguments)
Sets the arguments with which the configuration modules will be initialized.
void clicked(bool checked)
QIcon fromTheme(const QString &name)
bool isValid() const
void defaultsIndicatorsVisible()
Emitted when show defaults indicators changed.
void setFocusProxy(QWidget *w)
void load(const KConfigGroup &config=KConfigGroup())
void clearPlugins()
Remove all plugins from the entry list.
void leftClickedUrl()
static KPluginInfo::List fromFiles(const QStringList &files, const KConfigGroup &config=KConfigGroup())
QString next()
void setChecked(bool)
int width() const const
bool isValid() const const
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool contains(const T &value) const const
Definition: dialog.h:19
void drawText(const QPointF &position, const QString &text)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KGuiItem defaults()
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void setStandardButtons(QDialogButtonBox::StandardButtons buttons)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void updatePluginsState()
Updates plugins state (enabled or not)
bool isVisible() const const
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
void save()
Calling it will cause the contained module to run its save() routine.
static void assign(QPushButton *button, const KGuiItem &item)
QString pluginName() const
QString i18n(const char *text, const TYPE &arg...)
int height() const const
bool isSaveNeeded() const
Returns true if the plugin selector has any changes that are not yet saved to configuration.
void setAdditionalButtonHandler(std::function< QPushButton *(const KPluginInfo &)> handler)
Add additional widgets to each row of the plugin selector.
void textChanged(const QString &text)
bool isEmpty() const const
void defaults()
Change to applications defaults.
void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
QString category() const
void configCommitted(const QByteArray &componentName)
Emitted after the config of an embedded KCM has been saved.
virtual void accept()
bool isEmpty() const const
void save()
Save the configuration.
QJsonValue value(const QString &key) const const
QVariant toVariant() const const
KPluginMetaData metaData() const
Returns the KPluginMetaData used to load the KCM.
QVariant property(const QString &key) const
bool isValid() const const
bool isValid() const
void setEnabled(bool)
PM_MessageBoxIconSize
bool toBool() const const
int row() const const
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString label(StandardShortcut id)
void setIcon(const QIcon &icon)
KConfigGroup config() const
void addPlugins(const QString &componentName, const QString &categoryName=QString(), const QString &categoryKey=QString(), KSharedConfig::Ptr config=KSharedConfig::Ptr())
Add a list of KParts plugins.
bool setProperty(const char *name, const QVariant &value)
ElideRight
void resize(int w, int h)
virtual QSize sizeHint() const const override
QString name() const
void setToolTip(const QString &)
QPushButton * button(QDialogButtonBox::StandardButton which) const const
QString & insert(int position, QChar ch)
QString left(int n) const const
virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
bool isValid(QStringView ifopt)
void addWidget(QWidget *w)
int addTab(QWidget *page, const QString &label)
QStringList locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const const=0
LeftToRight
void setContentsMargins(int left, int top, int right, int bottom)
void restore()
void move(int x, int y)
bool setAlignment(QWidget *w, Qt::Alignment alignment)
bool isValid() const
Returns true if the KCM was found.
static KPluginMetaData findPluginById(const QString &directory, const QString &pluginId)
void save()
void addLayout(QLayout *layout, int stretch)
QString comment() const
void paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, QIcon::Mode mode, QIcon::State state) const const
int compare(const QString &other, Qt::CaseSensitivity cs) const const
QStringList toStringList() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
void setFont(const QFont &font)
KGuiItem cancel()
QString mid(int position, int n) const const
void defaults()
Calling it will cause the contained module to load its default values.
void setDefaultsIndicatorsVisible(bool isVisible)
Show an indicator when a plugin status is different from default.
QString message
const QAbstractItemModel * model() const const
WA_Hover
QStyle * style()
void defaulted(bool isDefault)
Emitted after configuration is changed, tell if configuration represent default or not.
void showConfiguration(const QString &pluginId)
Shows the configuration dialog for the plugin pluginId if it's available.
KCModule * realModule() const
Access to the actual module.
PE_PanelItemViewItem
QString toString() const const
bool isPluginEnabled() const
bool isDefault() const
Returns true if the plugin selector does not have any changes to application defaults.
KCModuleInfo moduleInfo() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu May 26 2022 03:50:00 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.