some more win32'fication to fix non-ascii filename handling
[kdelibs.git] / kutils / kpluginselector.cpp
blob2373a87911c6fdf50c39bd1c371bb268033f0153
1 /**
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>
31 #include <kdebug.h>
32 #include <klineedit.h>
33 #include <kdialog.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>
48 #define MARGIN 5
50 KPluginSelector::Private::Private(KPluginSelector *parent)
51 : QObject(parent)
52 , parent(parent)
53 , listView(0)
54 , categoryDrawer(new KCategoryDrawer)
55 , showIcons(false)
59 KPluginSelector::Private::~Private()
61 delete categoryDrawer;
64 void KPluginSelector::Private::updateDependencies(PluginEntry *pluginEntry, bool added)
66 if (added) {
67 QStringList dependencyList = pluginEntry->pluginInfo.dependencies();
69 if (!dependencyList.count()) {
70 return;
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);
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());
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) {
102 return value;
105 return totalWidth - width - value;
108 KPluginSelector::Private::DependenciesWidget::DependenciesWidget(QWidget *parent)
109 : QWidget(parent)
110 , addedByDependencies(0)
111 , removedByDependencies(0)
113 setVisible(false);
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);
140 setLayout(layout);
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)
151 if (!isVisible())
152 setVisible(true);
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;
167 else
168 dependencyMap.insert(dependency, furtherInfo);
170 if (added)
171 addedByDependencies++;
172 else
173 removedByDependencies++;
175 updateDetails();
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);
190 updateDetails();
193 void KPluginSelector::Private::DependenciesWidget::clearDependencies()
195 addedByDependencies = 0;
196 removedByDependencies = 0;
197 dependencyMap.clear();
198 updateDetails();
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);
208 else
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;
215 updateDetails();
218 void KPluginSelector::Private::DependenciesWidget::updateDetails()
220 if (!dependencyMap.count())
222 setVisible(false);
223 return;
226 QString message;
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);
239 else
241 details->setVisible(true);
242 details->setText(message);
247 KPluginSelector::KPluginSelector(QWidget *parent)
248 : QWidget(parent)
249 , d(new Private(this))
251 QVBoxLayout *layout = new QVBoxLayout;
252 layout->setMargin(0);
253 setLayout(layout);
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.
287 delete d;
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())
301 return;
303 Q_ASSERT(config);
304 if (!config)
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())
328 return;
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);
345 emit changed(false);
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();
358 emit changed(false);
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);
369 emit changed(true);
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()) {
378 return false;
382 return true;
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;
421 } else {
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;
443 endInsertRows();
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
454 Q_UNUSED(parent)
456 return createIndex(row, column, (row < pluginEntryList.count()) ? (void*) &pluginEntryList.at(row)
457 : 0);
460 QVariant KPluginSelector::Private::PluginModel::data(const QModelIndex &index, int role) const
462 if (!index.isValid() || !index.internalPointer()) {
463 return QVariant();
466 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer());
468 switch (role) {
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();
475 case NameRole:
476 return pluginEntry->pluginInfo.name();
477 case CommentRole:
478 return pluginEntry->pluginInfo.comment();
479 case AuthorRole:
480 return pluginEntry->pluginInfo.author();
481 case EmailRole:
482 return pluginEntry->pluginInfo.email();
483 case WebsiteRole:
484 return pluginEntry->pluginInfo.website();
485 case VersionRole:
486 return pluginEntry->pluginInfo.version();
487 case LicenseRole:
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;
500 default:
501 return QVariant();
505 bool KPluginSelector::Private::PluginModel::setData(const QModelIndex &index, const QVariant &value, int role)
507 if (!index.isValid()) {
508 return false;
511 bool ret = false;
513 if (role == Qt::CheckStateRole) {
514 static_cast<PluginEntry*>(index.internalPointer())->checked = value.toBool();
515 ret = true;
518 if (ret) {
519 emit dataChanged(index, index);
522 return ret;
525 int KPluginSelector::Private::PluginModel::rowCount(const QModelIndex &parent) const
527 if (parent.isValid()) {
528 return 0;
531 return pluginEntryList.count();
534 KPluginSelector::Private::ProxyModel::ProxyModel(KPluginSelector::Private *pluginSelector_d, QObject *parent)
535 : KCategorizedSortFilterProxyModel(parent)
536 , pluginSelector_d(pluginSelector_d)
538 sort(0);
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);
556 return true;
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()
575 delete checkBox;
576 delete pushButton;
579 void KPluginSelector::Private::PluginDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
581 if (!index.isValid()) {
582 return;
585 int xOffset = checkBox->sizeHint().width();
586 bool disabled = !index.model()->data(index, IsCheckableRole).toBool();
588 painter->save();
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));
598 } else {
599 iconSize = -MARGIN;
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);
619 painter->save();
620 if (disabled) {
621 QPalette pal(option.palette);
622 pal.setCurrentColorGroup(QPalette::Disabled);
623 painter->setPen(pal.text().color());
626 painter->save();
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()));
631 painter->restore();
633 painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignBottom, option.fontMetrics.elidedText(index.model()->data(index, CommentRole).toString(), Qt::ElideRight, contentsRect.width()));
635 painter->restore();
636 painter->restore();
639 QSize KPluginSelector::Private::PluginDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
641 int i = 5;
642 int j = 1;
643 if (index.model()->data(index, ServicesCountRole).toBool()) {
644 i = 6;
645 j = 2;
648 if (!pluginSelector_d->showIcons) {
649 i--;
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;
688 return widgetList;
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);
713 } else {
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())
724 return;
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()
738 emit changed(true);
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
748 // file).
750 PluginEntry *entry = index.model()->data(index, PluginEntryRole).value<PluginEntry*>();
751 KService::Ptr entryService = entry->pluginInfo.service();
752 if (entryService) {
753 KPluginLoader loader(*entryService);
754 KPluginFactory *factory = loader.factory();
755 if (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());
759 aboutPlugin.exec();
760 return;
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(',');
777 int i = 0;
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);
783 i++;
786 KAboutApplicationDialog aboutPlugin(&aboutData, itemView());
787 aboutPlugin.exec();
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);
823 if (moduleProxy) {
824 newTabWidget->addTab(mainWidget, moduleProxy->moduleInfo().moduleName());
825 mainWidget = newTabWidget;
826 } else {
827 delete newTabWidget;
828 newTabWidget = 0;
829 moduleProxyParentWidget = &configDialog;
830 mainWidget->setParent(0);
834 if (newTabWidget) {
835 newTabWidget->addTab(currentModuleProxy, servicePtr->name());
836 } else {
837 mainWidget = currentModuleProxy;
839 } else {
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();
861 moduleProxy->save();
862 foreach (const QString &parentComponent, parentComponents) {
863 emit configCommitted(parentComponent.toLatin1());
866 } else {
867 foreach (KCModuleProxy *moduleProxy, moduleProxyList) {
868 moduleProxy->load();
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);
889 return retFont;
892 #include "kpluginselector_p.moc"
893 #include "kpluginselector.moc"