2 * This file is part of the KDE project
3 * Copyright (C) 2007, 2006 Rafael Fernández López <ereslibre@kde.org>
4 * Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License version 2 as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 #include "kpluginselector.h"
22 #include "kpluginselector_p.h"
24 #include <QtGui/QLabel>
25 #include <QtGui/QPainter>
26 #include <QtGui/QBoxLayout>
27 #include <QtGui/QApplication>
28 #include <QtGui/QCheckBox>
29 #include <QtGui/QStyleOptionViewItemV4>
32 #include <klineedit.h>
34 #include <kurllabel.h>
35 #include <ktabwidget.h>
36 #include <kcmoduleinfo.h>
37 #include <kcmoduleproxy.h>
38 #include <kmessagebox.h>
39 #include <kpushbutton.h>
40 #include <kiconloader.h>
41 #include <kstandarddirs.h>
42 #include <klocalizedstring.h>
43 #include <kcategorydrawer.h>
44 #include <kcategorizedview.h>
45 #include <kcategorizedsortfilterproxymodel.h>
46 #include <kaboutapplicationdialog.h>
50 KPluginSelector::Private::Private(KPluginSelector
*parent
)
54 , categoryDrawer(new KCategoryDrawer
)
59 KPluginSelector::Private::~Private()
61 delete categoryDrawer
;
64 void KPluginSelector::Private::updateDependencies(PluginEntry
*pluginEntry
, bool added
)
67 QStringList dependencyList
= pluginEntry
->pluginInfo
.dependencies();
69 if (!dependencyList
.count()) {
73 for (int i
= 0; i
< pluginModel
->rowCount(); i
++) {
74 const QModelIndex index
= pluginModel
->index(i
, 0);
75 PluginEntry
*pe
= static_cast<PluginEntry
*>(index
.internalPointer());
77 if ((pe
->pluginInfo
.pluginName() != pluginEntry
->pluginInfo
.pluginName()) &&
78 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
);
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());
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
);
99 int KPluginSelector::Private::dependantLayoutValue(int value
, int width
, int totalWidth
) const
101 if (listView
->layoutDirection() == Qt::LeftToRight
) {
105 return totalWidth
- width
- value
;
108 KPluginSelector::Private::DependenciesWidget::DependenciesWidget(QWidget
*parent
)
110 , addedByDependencies(0)
111 , removedByDependencies(0)
115 details
= new QLabel();
117 QHBoxLayout
*layout
= new QHBoxLayout
;
119 QVBoxLayout
*dataLayout
= new QVBoxLayout
;
120 dataLayout
->setAlignment(Qt::AlignLeft
| Qt::AlignVCenter
);
121 layout
->setAlignment(Qt::AlignLeft
);
122 QLabel
*label
= new QLabel();
123 label
->setAlignment(Qt::AlignLeft
| Qt::AlignVCenter
);
124 label
->setPixmap(KIconLoader::global()->loadIcon("dialog-information", KIconLoader::Dialog
));
125 label
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
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
);
142 QObject::connect(link
, SIGNAL(leftClickedUrl()), this, SLOT(showDependencyDetails()));
145 KPluginSelector::Private::DependenciesWidget::~DependenciesWidget()
149 void KPluginSelector::Private::DependenciesWidget::addDependency(const QString
&dependency
, const QString
&pluginCausant
, bool added
)
154 struct FurtherInfo furtherInfo
;
155 furtherInfo
.added
= added
;
156 furtherInfo
.pluginCausant
= pluginCausant
;
158 if (dependencyMap
.contains(dependency
)) // The dependency moved from added to removed or vice-versa
160 if (added
&& removedByDependencies
)
161 removedByDependencies
--;
162 else if (addedByDependencies
)
163 addedByDependencies
--;
165 dependencyMap
[dependency
] = furtherInfo
;
168 dependencyMap
.insert(dependency
, furtherInfo
);
171 addedByDependencies
++;
173 removedByDependencies
++;
178 void KPluginSelector::Private::DependenciesWidget::userOverrideDependency(const QString
&dependency
)
180 if (dependencyMap
.contains(dependency
))
182 if (addedByDependencies
&& dependencyMap
[dependency
].added
)
183 addedByDependencies
--;
184 else if (removedByDependencies
)
185 removedByDependencies
--;
187 dependencyMap
.remove(dependency
);
193 void KPluginSelector::Private::DependenciesWidget::clearDependencies()
195 addedByDependencies
= 0;
196 removedByDependencies
= 0;
197 dependencyMap
.clear();
201 void KPluginSelector::Private::DependenciesWidget::showDependencyDetails()
203 QString message
= i18n("Automatic changes have been performed in order to satisfy plugin dependencies:\n");
204 foreach(const QString
&dependency
, dependencyMap
.keys())
206 if (dependencyMap
[dependency
].added
)
207 message
+= i18n("\n %1 plugin has been automatically checked because of the dependency of %2 plugin", dependency
, dependencyMap
[dependency
].pluginCausant
);
209 message
+= i18n("\n %1 plugin has been automatically unchecked because of its dependency on %2 plugin", dependency
, dependencyMap
[dependency
].pluginCausant
);
211 KMessageBox::information(this, message
, i18n("Dependency Check"));
213 addedByDependencies
= 0;
214 removedByDependencies
= 0;
218 void KPluginSelector::Private::DependenciesWidget::updateDetails()
220 if (!dependencyMap
.count())
228 if (addedByDependencies
)
229 message
+= i18np("%1 plugin automatically added due to plugin dependencies", "%1 plugins automatically added due to plugin dependencies", addedByDependencies
);
231 if (removedByDependencies
&& !message
.isEmpty())
232 message
+= i18n(", ");
234 if (removedByDependencies
)
235 message
+= i18np("%1 plugin automatically removed due to plugin dependencies", "%1 plugins automatically removed due to plugin dependencies", removedByDependencies
);
237 if (message
.isEmpty())
238 details
->setVisible(false);
241 details
->setVisible(true);
242 details
->setText(message
);
247 KPluginSelector::KPluginSelector(QWidget
*parent
)
249 , d(new Private(this))
251 QVBoxLayout
*layout
= new QVBoxLayout
;
252 layout
->setMargin(0);
255 d
->lineEdit
= new KLineEdit(this);
256 d
->lineEdit
->setClearButtonShown(true);
257 d
->lineEdit
->setClickMessage(i18n("Search Plugins"));
258 d
->listView
= new KCategorizedView(this);
259 d
->listView
->setCategoryDrawer(d
->categoryDrawer
);
260 d
->dependenciesWidget
= new Private::DependenciesWidget(this);
262 d
->pluginModel
= new Private::PluginModel(d
, this);
263 d
->proxyModel
= new Private::ProxyModel(d
, this);
264 d
->proxyModel
->setCategorizedModel(true);
265 d
->proxyModel
->setSourceModel(d
->pluginModel
);
266 d
->listView
->setModel(d
->proxyModel
);
267 d
->listView
->setAlternatingRowColors(true);
269 Private::PluginDelegate
*pluginDelegate
= new Private::PluginDelegate(d
, this);
270 d
->listView
->setItemDelegate(pluginDelegate
);
272 d
->listView
->setMouseTracking(true);
273 d
->listView
->viewport()->setAttribute(Qt::WA_Hover
);
275 connect(d
->lineEdit
, SIGNAL(textChanged(QString
)), d
->proxyModel
, SLOT(invalidate()));
276 connect(pluginDelegate
, SIGNAL(changed(bool)), this, SIGNAL(changed(bool)));
277 connect(pluginDelegate
, SIGNAL(configCommitted(QByteArray
)), this, SIGNAL(configCommitted(QByteArray
)));
279 layout
->addWidget(d
->lineEdit
);
280 layout
->addWidget(d
->listView
);
281 layout
->addWidget(d
->dependenciesWidget
);
284 KPluginSelector::~KPluginSelector()
286 delete d
->listView
; // depends on some other things in d, make sure this dies first.
290 void KPluginSelector::addPlugins(const QString
&componentName
,
291 const QString
&categoryName
,
292 const QString
&categoryKey
,
293 KSharedConfig::Ptr config
)
295 QStringList desktopFileNames
= KGlobal::dirs()->findAllResources("data",
296 componentName
+ "/kpartplugins/*.desktop", KStandardDirs::Recursive
);
298 QList
<KPluginInfo
> pluginInfoList
= KPluginInfo::fromFiles(desktopFileNames
);
300 if (pluginInfoList
.isEmpty())
305 config
= KSharedConfig::openConfig(componentName
);
307 KConfigGroup
cfgGroup(config
, "KParts Plugins");
308 kDebug( 702 ) << "cfgGroup = " << &cfgGroup
;
310 d
->pluginModel
->addPlugins(pluginInfoList
, categoryName
, categoryKey
, cfgGroup
);
313 void KPluginSelector::addPlugins(const KComponentData
&instance
,
314 const QString
&categoryName
,
315 const QString
&categoryKey
,
316 const KSharedConfig::Ptr
&config
)
318 addPlugins(instance
.componentName(), categoryName
, categoryKey
, config
);
321 void KPluginSelector::addPlugins(const QList
<KPluginInfo
> &pluginInfoList
,
322 PluginLoadMethod pluginLoadMethod
,
323 const QString
&categoryName
,
324 const QString
&categoryKey
,
325 const KSharedConfig::Ptr
&config
)
327 if (pluginInfoList
.isEmpty())
330 KConfigGroup
cfgGroup(config
? config
: KGlobal::config(), "Plugins");
331 kDebug( 702 ) << "cfgGroup = " << &cfgGroup
;
333 d
->pluginModel
->addPlugins(pluginInfoList
, categoryName
, categoryKey
, cfgGroup
, pluginLoadMethod
, true /* manually added */);
336 void KPluginSelector::load()
338 for (int i
= 0; i
< d
->pluginModel
->rowCount(); i
++) {
339 const QModelIndex index
= d
->pluginModel
->index(i
, 0);
340 PluginEntry
*pluginEntry
= static_cast<PluginEntry
*>(index
.internalPointer());
341 pluginEntry
->pluginInfo
.load(pluginEntry
->cfgGroup
);
342 d
->pluginModel
->setData(index
, pluginEntry
->pluginInfo
.isPluginEnabled(), Qt::CheckStateRole
);
348 void KPluginSelector::save()
350 for (int i
= 0; i
< d
->pluginModel
->rowCount(); i
++) {
351 const QModelIndex index
= d
->pluginModel
->index(i
, 0);
352 PluginEntry
*pluginEntry
= static_cast<PluginEntry
*>(index
.internalPointer());
353 pluginEntry
->pluginInfo
.setPluginEnabled(pluginEntry
->checked
);
354 pluginEntry
->pluginInfo
.save(pluginEntry
->cfgGroup
);
355 pluginEntry
->cfgGroup
.sync();
361 void KPluginSelector::defaults()
363 for (int i
= 0; i
< d
->pluginModel
->rowCount(); i
++) {
364 const QModelIndex index
= d
->pluginModel
->index(i
, 0);
365 PluginEntry
*pluginEntry
= static_cast<PluginEntry
*>(index
.internalPointer());
366 d
->pluginModel
->setData(index
, pluginEntry
->pluginInfo
.isPluginEnabledByDefault(), Qt::CheckStateRole
);
372 bool KPluginSelector::isDefault() const
374 for (int i
= 0; i
< d
->pluginModel
->rowCount(); i
++) {
375 const QModelIndex index
= d
->pluginModel
->index(i
, 0);
376 PluginEntry
*pluginEntry
= static_cast<PluginEntry
*>(index
.internalPointer());
377 if (d
->pluginModel
->data(index
, Qt::CheckStateRole
).toBool() != pluginEntry
->pluginInfo
.isPluginEnabledByDefault()) {
385 void KPluginSelector::updatePluginsState()
387 for (int i
= 0; i
< d
->pluginModel
->rowCount(); i
++) {
388 const QModelIndex index
= d
->pluginModel
->index(i
, 0);
389 PluginEntry
*pluginEntry
= static_cast<PluginEntry
*>(index
.internalPointer());
390 if (pluginEntry
->manuallyAdded
) {
391 pluginEntry
->pluginInfo
.setPluginEnabled(pluginEntry
->checked
);
396 KPluginSelector::Private::PluginModel::PluginModel(KPluginSelector::Private
*pluginSelector_d
, QObject
*parent
)
397 : QAbstractListModel(parent
)
398 , pluginSelector_d(pluginSelector_d
)
402 KPluginSelector::Private::PluginModel::~PluginModel()
406 void KPluginSelector::Private::PluginModel::addPlugins(const QList
<KPluginInfo
> &pluginList
, const QString
&categoryName
, const QString
&categoryKey
, const KConfigGroup
&cfgGroup
, PluginLoadMethod pluginLoadMethod
, bool manuallyAdded
)
408 QList
<PluginEntry
> listToAdd
;
410 foreach (const KPluginInfo
&pluginInfo
, pluginList
) {
411 PluginEntry pluginEntry
;
412 pluginEntry
.category
= categoryName
;
413 pluginEntry
.pluginInfo
= pluginInfo
;
414 if (pluginLoadMethod
== ReadConfigFile
) {
415 pluginEntry
.pluginInfo
.load(cfgGroup
);
417 pluginEntry
.checked
= pluginInfo
.isPluginEnabled();
418 pluginEntry
.manuallyAdded
= manuallyAdded
;
419 if (cfgGroup
.isValid()) {
420 pluginEntry
.cfgGroup
= cfgGroup
;
422 pluginEntry
.cfgGroup
= pluginInfo
.config();
425 // this is where kiosk will set if a plugin is checkable or not (pluginName + "Enabled")
426 pluginEntry
.isCheckable
= !pluginInfo
.isValid() || !pluginEntry
.cfgGroup
.isEntryImmutable(pluginInfo
.pluginName() + QLatin1String("Enabled"));
428 if (!pluginEntryList
.contains(pluginEntry
) && !listToAdd
.contains(pluginEntry
) &&
429 (!pluginInfo
.property("X-KDE-PluginInfo-Category").isValid() ||
430 !pluginInfo
.property("X-KDE-PluginInfo-Category").toString().compare(categoryKey
, Qt::CaseInsensitive
)) &&
431 (pluginInfo
.service().isNull() || !pluginInfo
.service()->noDisplay())) {
432 listToAdd
<< pluginEntry
;
434 if (!pluginSelector_d
->showIcons
&& !pluginInfo
.icon().isEmpty()) {
435 pluginSelector_d
->showIcons
= true;
440 if (listToAdd
.count()) {
441 beginInsertRows(QModelIndex(), pluginEntryList
.count(), pluginEntryList
.count() + listToAdd
.count() - 1);
442 pluginEntryList
<< listToAdd
;
447 QList
<KService::Ptr
> KPluginSelector::Private::PluginModel::pluginServices(const QModelIndex
&index
) const
449 return static_cast<PluginEntry
*>(index
.internalPointer())->pluginInfo
.kcmServices();
452 QModelIndex
KPluginSelector::Private::PluginModel::index(int row
, int column
, const QModelIndex
&parent
) const
456 return createIndex(row
, column
, (row
< pluginEntryList
.count()) ? (void*) &pluginEntryList
.at(row
)
460 QVariant
KPluginSelector::Private::PluginModel::data(const QModelIndex
&index
, int role
) const
462 if (!index
.isValid() || !index
.internalPointer()) {
466 PluginEntry
*pluginEntry
= static_cast<PluginEntry
*>(index
.internalPointer());
469 case Qt::DisplayRole
:
470 return pluginEntry
->pluginInfo
.name();
471 case PluginEntryRole
:
472 return QVariant::fromValue(pluginEntry
);
473 case ServicesCountRole
:
474 return pluginEntry
->pluginInfo
.kcmServices().count();
476 return pluginEntry
->pluginInfo
.name();
478 return pluginEntry
->pluginInfo
.comment();
480 return pluginEntry
->pluginInfo
.author();
482 return pluginEntry
->pluginInfo
.email();
484 return pluginEntry
->pluginInfo
.website();
486 return pluginEntry
->pluginInfo
.version();
488 return pluginEntry
->pluginInfo
.license();
489 case DependenciesRole
:
490 return pluginEntry
->pluginInfo
.dependencies();
491 case IsCheckableRole
:
492 return pluginEntry
->isCheckable
;
493 case Qt::DecorationRole
:
494 return pluginEntry
->pluginInfo
.icon();
495 case Qt::CheckStateRole
:
496 return pluginEntry
->checked
;
497 case KCategorizedSortFilterProxyModel::CategoryDisplayRole
: // fall through
498 case KCategorizedSortFilterProxyModel::CategorySortRole
:
499 return pluginEntry
->category
;
505 bool KPluginSelector::Private::PluginModel::setData(const QModelIndex
&index
, const QVariant
&value
, int role
)
507 if (!index
.isValid()) {
513 if (role
== Qt::CheckStateRole
) {
514 static_cast<PluginEntry
*>(index
.internalPointer())->checked
= value
.toBool();
519 emit
dataChanged(index
, index
);
525 int KPluginSelector::Private::PluginModel::rowCount(const QModelIndex
&parent
) const
527 if (parent
.isValid()) {
531 return pluginEntryList
.count();
534 KPluginSelector::Private::ProxyModel::ProxyModel(KPluginSelector::Private
*pluginSelector_d
, QObject
*parent
)
535 : KCategorizedSortFilterProxyModel(parent
)
536 , pluginSelector_d(pluginSelector_d
)
541 KPluginSelector::Private::ProxyModel::~ProxyModel()
545 bool KPluginSelector::Private::ProxyModel::filterAcceptsRow(int sourceRow
, const QModelIndex
&sourceParent
) const
547 Q_UNUSED(sourceParent
)
549 if (!pluginSelector_d
->lineEdit
->text().isEmpty()) {
550 const QModelIndex index
= sourceModel()->index(sourceRow
, 0);
551 const KPluginInfo pluginInfo
= static_cast<PluginEntry
*>(index
.internalPointer())->pluginInfo
;
552 return pluginInfo
.name().contains(pluginSelector_d
->lineEdit
->text(), Qt::CaseInsensitive
) ||
553 pluginInfo
.comment().contains(pluginSelector_d
->lineEdit
->text(), Qt::CaseInsensitive
);
559 bool KPluginSelector::Private::ProxyModel::subSortLessThan(const QModelIndex
&left
, const QModelIndex
&right
) const
561 return static_cast<PluginEntry
*>(left
.internalPointer())->pluginInfo
.name().compare(static_cast<PluginEntry
*>(right
.internalPointer())->pluginInfo
.name(), Qt::CaseInsensitive
) < 0;
564 KPluginSelector::Private::PluginDelegate::PluginDelegate(KPluginSelector::Private
*pluginSelector_d
, QObject
*parent
)
565 : KWidgetItemDelegate(pluginSelector_d
->listView
, parent
)
566 , checkBox(new QCheckBox
)
567 , pushButton(new KPushButton
)
568 , pluginSelector_d(pluginSelector_d
)
570 pushButton
->setIcon(KIcon("configure")); // only for getting size matters
573 KPluginSelector::Private::PluginDelegate::~PluginDelegate()
579 void KPluginSelector::Private::PluginDelegate::paint(QPainter
*painter
, const QStyleOptionViewItem
&option
, const QModelIndex
&index
) const
581 if (!index
.isValid()) {
585 int xOffset
= checkBox
->sizeHint().width();
586 bool disabled
= !index
.model()->data(index
, IsCheckableRole
).toBool();
590 QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem
, &option
, painter
, 0);
592 int iconSize
= option
.rect
.height() - MARGIN
* 2;
593 if (pluginSelector_d
->showIcons
) {
594 QPixmap pixmap
= KIconLoader::global()->loadIcon(index
.model()->data(index
, Qt::DecorationRole
).toString(),
595 KIconLoader::Desktop
, iconSize
, disabled
? KIconLoader::DisabledState
: KIconLoader::DefaultState
);
597 painter
->drawPixmap(QRect(pluginSelector_d
->dependantLayoutValue(MARGIN
+ option
.rect
.left() + xOffset
, iconSize
, option
.rect
.width()), MARGIN
+ option
.rect
.top(), iconSize
, iconSize
), pixmap
, QRect(0, 0, iconSize
, iconSize
));
602 QRect
contentsRect(pluginSelector_d
->dependantLayoutValue(MARGIN
* 2 + iconSize
+ option
.rect
.left() + xOffset
, option
.rect
.width() - MARGIN
* 3 - iconSize
- xOffset
, option
.rect
.width()), MARGIN
+ option
.rect
.top(), option
.rect
.width() - MARGIN
* 3 - iconSize
- xOffset
, option
.rect
.height() - MARGIN
* 2);
604 int lessHorizontalSpace
= MARGIN
* 2 + pushButton
->sizeHint().width();
605 if (index
.model()->data(index
, ServicesCountRole
).toBool()) {
606 lessHorizontalSpace
+= MARGIN
+ pushButton
->sizeHint().width();
609 contentsRect
.setWidth(contentsRect
.width() - lessHorizontalSpace
);
611 if (option
.state
& QStyle::State_Selected
) {
612 painter
->setPen(option
.palette
.highlightedText().color());
615 if (pluginSelector_d
->listView
->layoutDirection() == Qt::RightToLeft
) {
616 contentsRect
.translate(lessHorizontalSpace
, 0);
621 QPalette
pal(option
.palette
);
622 pal
.setCurrentColorGroup(QPalette::Disabled
);
623 painter
->setPen(pal
.text().color());
627 QFont font
= titleFont(option
.font
);
628 QFontMetrics
fmTitle(font
);
629 painter
->setFont(font
);
630 painter
->drawText(contentsRect
, Qt::AlignLeft
| Qt::AlignTop
, fmTitle
.elidedText(index
.model()->data(index
, Qt::DisplayRole
).toString(), Qt::ElideRight
, contentsRect
.width()));
633 painter
->drawText(contentsRect
, Qt::AlignLeft
| Qt::AlignBottom
, option
.fontMetrics
.elidedText(index
.model()->data(index
, CommentRole
).toString(), Qt::ElideRight
, contentsRect
.width()));
639 QSize
KPluginSelector::Private::PluginDelegate::sizeHint(const QStyleOptionViewItem
&option
, const QModelIndex
&index
) const
643 if (index
.model()->data(index
, ServicesCountRole
).toBool()) {
648 if (!pluginSelector_d
->showIcons
) {
652 QFont font
= titleFont(option
.font
);
653 QFontMetrics
fmTitle(font
);
655 return QSize(qMax(fmTitle
.width(index
.model()->data(index
, Qt::DisplayRole
).toString()),
656 option
.fontMetrics
.width(index
.model()->data(index
, CommentRole
).toString())) +
657 pluginSelector_d
->showIcons
? KIconLoader::SizeMedium
: 0 + MARGIN
* i
+ pushButton
->sizeHint().width() * j
,
658 qMax(KIconLoader::SizeMedium
+ MARGIN
* 2, fmTitle
.height() + option
.fontMetrics
.height() + MARGIN
* 2));
661 QList
<QWidget
*> KPluginSelector::Private::PluginDelegate::createItemWidgets() const
663 QList
<QWidget
*> widgetList
;
665 QCheckBox
*enabledCheckBox
= new QCheckBox
;
666 connect(enabledCheckBox
, SIGNAL(clicked(bool)), this, SLOT(slotStateChanged(bool)));
667 connect(enabledCheckBox
, SIGNAL(clicked(bool)), this, SLOT(emitChanged()));
669 KPushButton
*aboutPushButton
= new KPushButton
;
670 aboutPushButton
->setIcon(KIcon("dialog-information"));
671 connect(aboutPushButton
, SIGNAL(clicked(bool)), this, SLOT(slotAboutClicked()));
673 KPushButton
*configurePushButton
= new KPushButton
;
674 configurePushButton
->setIcon(KIcon("configure"));
675 connect(configurePushButton
, SIGNAL(clicked(bool)), this, SLOT(slotConfigureClicked()));
677 setBlockedEventTypes(enabledCheckBox
, QList
<QEvent::Type
>() << QEvent::MouseButtonPress
678 << QEvent::MouseButtonRelease
<< QEvent::MouseButtonDblClick
);
680 setBlockedEventTypes(aboutPushButton
, QList
<QEvent::Type
>() << QEvent::MouseButtonPress
681 << QEvent::MouseButtonRelease
<< QEvent::MouseButtonDblClick
);
683 setBlockedEventTypes(configurePushButton
, QList
<QEvent::Type
>() << QEvent::MouseButtonPress
684 << QEvent::MouseButtonRelease
<< QEvent::MouseButtonDblClick
);
686 widgetList
<< enabledCheckBox
<< configurePushButton
<< aboutPushButton
;
691 void KPluginSelector::Private::PluginDelegate::updateItemWidgets(const QList
<QWidget
*> widgets
,
692 const QStyleOptionViewItem
&option
,
693 const QPersistentModelIndex
&index
) const
695 QCheckBox
*checkBox
= static_cast<QCheckBox
*>(widgets
[0]);
696 checkBox
->resize(checkBox
->sizeHint());
697 checkBox
->move(pluginSelector_d
->dependantLayoutValue(MARGIN
, checkBox
->sizeHint().width(), option
.rect
.width()), option
.rect
.height() / 2 - checkBox
->sizeHint().height() / 2);
699 KPushButton
*aboutPushButton
= static_cast<KPushButton
*>(widgets
[2]);
700 QSize aboutPushButtonSizeHint
= aboutPushButton
->sizeHint();
701 aboutPushButton
->resize(aboutPushButtonSizeHint
);
702 aboutPushButton
->move(pluginSelector_d
->dependantLayoutValue(option
.rect
.width() - MARGIN
- aboutPushButtonSizeHint
.width(), aboutPushButtonSizeHint
.width(), option
.rect
.width()), option
.rect
.height() / 2 - aboutPushButtonSizeHint
.height() / 2);
704 KPushButton
*configurePushButton
= static_cast<KPushButton
*>(widgets
[1]);
705 QSize configurePushButtonSizeHint
= configurePushButton
->sizeHint();
706 configurePushButton
->resize(configurePushButtonSizeHint
);
707 configurePushButton
->move(pluginSelector_d
->dependantLayoutValue(option
.rect
.width() - MARGIN
* 2 - configurePushButtonSizeHint
.width() - aboutPushButtonSizeHint
.width(), configurePushButtonSizeHint
.width(), option
.rect
.width()), option
.rect
.height() / 2 - configurePushButtonSizeHint
.height() / 2);
709 if (!index
.isValid() || !index
.internalPointer()) {
710 checkBox
->setVisible(false);
711 aboutPushButton
->setVisible(false);
712 configurePushButton
->setVisible(false);
714 checkBox
->setChecked(index
.model()->data(index
, Qt::CheckStateRole
).toBool());
715 checkBox
->setEnabled(index
.model()->data(index
, IsCheckableRole
).toBool());
716 configurePushButton
->setVisible(index
.model()->data(index
, ServicesCountRole
).toBool());
717 configurePushButton
->setEnabled(index
.model()->data(index
, Qt::CheckStateRole
).toBool());
721 void KPluginSelector::Private::PluginDelegate::slotStateChanged(bool state
)
723 if (!focusedIndex().isValid())
726 const QModelIndex index
= focusedIndex();
728 pluginSelector_d
->dependenciesWidget
->clearDependencies();
730 PluginEntry
*pluginEntry
= index
.model()->data(index
, PluginEntryRole
).value
<PluginEntry
*>();
731 pluginSelector_d
->updateDependencies(pluginEntry
, state
);
733 const_cast<QAbstractItemModel
*>(index
.model())->setData(index
, state
, Qt::CheckStateRole
);
736 void KPluginSelector::Private::PluginDelegate::emitChanged()
741 void KPluginSelector::Private::PluginDelegate::slotAboutClicked()
743 const QModelIndex index
= focusedIndex();
744 const QAbstractItemModel
*model
= index
.model();
746 // Try to retrieve the plugin information from the KComponentData object of the plugin.
747 // If there is no valid information, go and fetch it from the service itself (the .desktop
750 PluginEntry
*entry
= index
.model()->data(index
, PluginEntryRole
).value
<PluginEntry
*>();
751 KService::Ptr entryService
= entry
->pluginInfo
.service();
753 KPluginLoader
loader(*entryService
);
754 KPluginFactory
*factory
= loader
.factory();
756 const KAboutData
*aboutData
= factory
->componentData().aboutData();
757 if (!aboutData
->programName().isEmpty()) { // Be sure the about data is not completely empty
758 KAboutApplicationDialog
aboutPlugin(aboutData
, itemView());
765 const QString name
= model
->data(index
, NameRole
).toString();
766 const QString comment
= model
->data(index
, CommentRole
).toString();
767 const QString author
= model
->data(index
, AuthorRole
).toString();
768 const QString email
= model
->data(index
, EmailRole
).toString();
769 const QString website
= model
->data(index
, WebsiteRole
).toString();
770 const QString version
= model
->data(index
, VersionRole
).toString();
771 const QString license
= model
->data(index
, LicenseRole
).toString();
773 KAboutData
aboutData(name
.toUtf8(), name
.toUtf8(), ki18n(name
.toUtf8()), version
.toUtf8(), ki18n(comment
.toUtf8()), KAboutLicense::byKeyword(license
).key(), ki18n(QByteArray()), ki18n(QByteArray()), website
.toLatin1());
774 aboutData
.setProgramIconName(index
.model()->data(index
, Qt::DecorationRole
).toString());
775 const QStringList authors
= author
.split(',');
776 const QStringList emails
= email
.split(',');
778 if (authors
.count() == emails
.count()) {
779 foreach (const QString
&author
, authors
) {
780 if (!author
.isEmpty()) {
781 aboutData
.addAuthor(ki18n(author
.toUtf8()), ki18n(QByteArray()), emails
[i
].toUtf8(), 0);
786 KAboutApplicationDialog
aboutPlugin(&aboutData
, itemView());
790 void KPluginSelector::Private::PluginDelegate::slotConfigureClicked()
792 const QModelIndex index
= focusedIndex();
793 const QAbstractItemModel
*model
= index
.model();
795 PluginEntry
*pluginEntry
= model
->data(index
, PluginEntryRole
).value
<PluginEntry
*>();
796 KPluginInfo pluginInfo
= pluginEntry
->pluginInfo
;
798 KDialog
configDialog(itemView());
799 configDialog
.setWindowTitle(model
->data(index
, NameRole
).toString());
800 // The number of KCModuleProxies in use determines whether to use a tabwidget
801 KTabWidget
*newTabWidget
= 0;
802 // Widget to use for the setting dialog's main widget,
803 // either a KTabWidget or a KCModuleProxy
804 QWidget
* mainWidget
= 0;
805 // Widget to use as the KCModuleProxy's parent.
806 // The first proxy is owned by the dialog itself
807 QWidget
*moduleProxyParentWidget
= &configDialog
;
809 foreach (const KService::Ptr
&servicePtr
, pluginInfo
.kcmServices()) {
810 if(!servicePtr
->noDisplay()) {
811 KCModuleInfo
moduleInfo(servicePtr
);
812 KCModuleProxy
*currentModuleProxy
= new KCModuleProxy(moduleInfo
, moduleProxyParentWidget
);
813 if (currentModuleProxy
->realModule()) {
814 moduleProxyList
<< currentModuleProxy
;
815 if (mainWidget
&& !newTabWidget
) {
816 // we already created one KCModuleProxy, so we need a tab widget.
817 // Move the first proxy into the tab widget and ensure this and subsequent
818 // proxies are in the tab widget
819 newTabWidget
= new KTabWidget(&configDialog
);
820 moduleProxyParentWidget
= newTabWidget
;
821 mainWidget
->setParent( newTabWidget
);
822 KCModuleProxy
*moduleProxy
= qobject_cast
<KCModuleProxy
*>(mainWidget
);
824 newTabWidget
->addTab(mainWidget
, moduleProxy
->moduleInfo().moduleName());
825 mainWidget
= newTabWidget
;
829 moduleProxyParentWidget
= &configDialog
;
830 mainWidget
->setParent(0);
835 newTabWidget
->addTab(currentModuleProxy
, servicePtr
->name());
837 mainWidget
= currentModuleProxy
;
840 delete currentModuleProxy
;
845 // it could happen that we had services to show, but none of them were real modules.
846 if (moduleProxyList
.count()) {
847 configDialog
.setButtons(KDialog::Ok
| KDialog::Cancel
| KDialog::Default
);
849 QWidget
*showWidget
= new QWidget(&configDialog
);
850 QVBoxLayout
*layout
= new QVBoxLayout
;
851 showWidget
->setLayout(layout
);
852 layout
->addWidget(mainWidget
);
853 layout
->insertSpacing(-1, KDialog::marginHint());
854 configDialog
.setMainWidget(showWidget
);
856 connect(&configDialog
, SIGNAL(defaultClicked()), this, SLOT(slotDefaultClicked()));
858 if (configDialog
.exec() == QDialog::Accepted
) {
859 foreach (KCModuleProxy
*moduleProxy
, moduleProxyList
) {
860 QStringList parentComponents
= moduleProxy
->moduleInfo().service()->property("X-KDE-ParentComponents").toStringList();
862 foreach (const QString
&parentComponent
, parentComponents
) {
863 emit
configCommitted(parentComponent
.toLatin1());
867 foreach (KCModuleProxy
*moduleProxy
, moduleProxyList
) {
872 qDeleteAll(moduleProxyList
);
873 moduleProxyList
.clear();
877 void KPluginSelector::Private::PluginDelegate::slotDefaultClicked()
879 foreach (KCModuleProxy
*moduleProxy
, moduleProxyList
) {
880 moduleProxy
->defaults();
884 QFont
KPluginSelector::Private::PluginDelegate::titleFont(const QFont
&baseFont
) const
886 QFont
retFont(baseFont
);
887 retFont
.setBold(true);
892 #include "kpluginselector_p.moc"
893 #include "kpluginselector.moc"