00001
00021 #include "kpluginselector.h"
00022 #include "kpluginselector_p.h"
00023
00024 #include <QtGui/QLabel>
00025 #include <QtGui/QPainter>
00026 #include <QtGui/QBoxLayout>
00027 #include <QtGui/QApplication>
00028 #include <QtGui/QCheckBox>
00029 #include <QtGui/QStyleOptionViewItemV4>
00030
00031 #include <kdebug.h>
00032 #include <klineedit.h>
00033 #include <kdialog.h>
00034 #include <kurllabel.h>
00035 #include <ktabwidget.h>
00036 #include <kcmoduleinfo.h>
00037 #include <kcmoduleproxy.h>
00038 #include <kmessagebox.h>
00039 #include <kpushbutton.h>
00040 #include <kiconloader.h>
00041 #include <kstandarddirs.h>
00042 #include <klocalizedstring.h>
00043 #include <kcategorydrawer.h>
00044 #include <kcategorizedview.h>
00045 #include <kcategorizedsortfilterproxymodel.h>
00046 #include <kaboutapplicationdialog.h>
00047
00048 #define MARGIN 5
00049
00050 KPluginSelector::Private::Private(KPluginSelector *parent)
00051 : QObject(parent)
00052 , parent(parent)
00053 , listView(0)
00054 , categoryDrawer(new KCategoryDrawer)
00055 , showIcons(false)
00056 {
00057 }
00058
00059 KPluginSelector::Private::~Private()
00060 {
00061 delete categoryDrawer;
00062 }
00063
00064 void KPluginSelector::Private::updateDependencies(PluginEntry *pluginEntry, bool added)
00065 {
00066 if (added) {
00067 QStringList dependencyList = pluginEntry->pluginInfo.dependencies();
00068
00069 if (!dependencyList.count()) {
00070 return;
00071 }
00072
00073 for (int i = 0; i < pluginModel->rowCount(); i++) {
00074 const QModelIndex index = pluginModel->index(i, 0);
00075 PluginEntry *pe = static_cast<PluginEntry*>(index.internalPointer());
00076
00077 if ((pe->pluginInfo.pluginName() != pluginEntry->pluginInfo.pluginName()) &&
00078 dependencyList.contains(pe->pluginInfo.pluginName()) && !pe->checked) {
00079 dependenciesWidget->addDependency(pe->pluginInfo.name(), pluginEntry->pluginInfo.name(), added);
00080 const_cast<QAbstractItemModel*>(index.model())->setData(index, added, Qt::CheckStateRole);
00081 updateDependencies(pe, added);
00082 }
00083 }
00084 } else {
00085 for (int i = 0; i < pluginModel->rowCount(); i++) {
00086 const QModelIndex index = pluginModel->index(i, 0);
00087 PluginEntry *pe = static_cast<PluginEntry*>(index.internalPointer());
00088
00089 if ((pe->pluginInfo.pluginName() != pluginEntry->pluginInfo.pluginName()) &&
00090 pe->pluginInfo.dependencies().contains(pluginEntry->pluginInfo.pluginName()) && pe->checked) {
00091 dependenciesWidget->addDependency(pe->pluginInfo.name(), pluginEntry->pluginInfo.name(), added);
00092 const_cast<QAbstractItemModel*>(index.model())->setData(index, added, Qt::CheckStateRole);
00093 updateDependencies(pe, added);
00094 }
00095 }
00096 }
00097 }
00098
00099 int KPluginSelector::Private::dependantLayoutValue(int value, int width, int totalWidth) const
00100 {
00101 if (listView->layoutDirection() == Qt::LeftToRight) {
00102 return value;
00103 }
00104
00105 return totalWidth - width - value;
00106 }
00107
00108 KPluginSelector::Private::DependenciesWidget::DependenciesWidget(QWidget *parent)
00109 : QWidget(parent)
00110 , addedByDependencies(0)
00111 , removedByDependencies(0)
00112 {
00113 setVisible(false);
00114
00115 details = new QLabel();
00116
00117 QHBoxLayout *layout = new QHBoxLayout;
00118
00119 QVBoxLayout *dataLayout = new QVBoxLayout;
00120 dataLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
00121 layout->setAlignment(Qt::AlignLeft);
00122 QLabel *label = new QLabel();
00123 label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
00124 label->setPixmap(KIconLoader::global()->loadIcon("dialog-information", KIconLoader::Dialog));
00125 label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00126 layout->addWidget(label);
00127 KUrlLabel *link = new KUrlLabel();
00128 link->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
00129 link->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00130 link->setGlowEnabled(false);
00131 link->setUnderline(false);
00132 link->setFloatEnabled(true);
00133 link->setUseCursor(true);
00134 link->setHighlightedColor(palette().color(QPalette::Link));
00135 link->setSelectedColor(palette().color(QPalette::Link));
00136 link->setText(i18n("Automatic changes have been performed due to plugin dependencies. Click here for further information"));
00137 dataLayout->addWidget(link);
00138 dataLayout->addWidget(details);
00139 layout->addLayout(dataLayout);
00140 setLayout(layout);
00141
00142 QObject::connect(link, SIGNAL(leftClickedUrl()), this, SLOT(showDependencyDetails()));
00143 }
00144
00145 KPluginSelector::Private::DependenciesWidget::~DependenciesWidget()
00146 {
00147 }
00148
00149 void KPluginSelector::Private::DependenciesWidget::addDependency(const QString &dependency, const QString &pluginCausant, bool added)
00150 {
00151 if (!isVisible())
00152 setVisible(true);
00153
00154 struct FurtherInfo furtherInfo;
00155 furtherInfo.added = added;
00156 furtherInfo.pluginCausant = pluginCausant;
00157
00158 if (dependencyMap.contains(dependency))
00159 {
00160 if (added && removedByDependencies)
00161 removedByDependencies--;
00162 else if (addedByDependencies)
00163 addedByDependencies--;
00164
00165 dependencyMap[dependency] = furtherInfo;
00166 }
00167 else
00168 dependencyMap.insert(dependency, furtherInfo);
00169
00170 if (added)
00171 addedByDependencies++;
00172 else
00173 removedByDependencies++;
00174
00175 updateDetails();
00176 }
00177
00178 void KPluginSelector::Private::DependenciesWidget::userOverrideDependency(const QString &dependency)
00179 {
00180 if (dependencyMap.contains(dependency))
00181 {
00182 if (addedByDependencies && dependencyMap[dependency].added)
00183 addedByDependencies--;
00184 else if (removedByDependencies)
00185 removedByDependencies--;
00186
00187 dependencyMap.remove(dependency);
00188 }
00189
00190 updateDetails();
00191 }
00192
00193 void KPluginSelector::Private::DependenciesWidget::clearDependencies()
00194 {
00195 addedByDependencies = 0;
00196 removedByDependencies = 0;
00197 dependencyMap.clear();
00198 updateDetails();
00199 }
00200
00201 void KPluginSelector::Private::DependenciesWidget::showDependencyDetails()
00202 {
00203 QString message = i18n("Automatic changes have been performed in order to satisfy plugin dependencies:\n");
00204 foreach(const QString &dependency, dependencyMap.keys())
00205 {
00206 if (dependencyMap[dependency].added)
00207 message += i18n("\n %1 plugin has been automatically checked because of the dependency of %2 plugin", dependency, dependencyMap[dependency].pluginCausant);
00208 else
00209 message += i18n("\n %1 plugin has been automatically unchecked because of its dependency on %2 plugin", dependency, dependencyMap[dependency].pluginCausant);
00210 }
00211 KMessageBox::information(this, message, i18n("Dependency Check"));
00212
00213 addedByDependencies = 0;
00214 removedByDependencies = 0;
00215 updateDetails();
00216 }
00217
00218 void KPluginSelector::Private::DependenciesWidget::updateDetails()
00219 {
00220 if (!dependencyMap.count())
00221 {
00222 setVisible(false);
00223 return;
00224 }
00225
00226 QString message;
00227
00228 if (addedByDependencies)
00229 message += i18np("%1 plugin automatically added due to plugin dependencies", "%1 plugins automatically added due to plugin dependencies", addedByDependencies);
00230
00231 if (removedByDependencies && !message.isEmpty())
00232 message += i18n(", ");
00233
00234 if (removedByDependencies)
00235 message += i18np("%1 plugin automatically removed due to plugin dependencies", "%1 plugins automatically removed due to plugin dependencies", removedByDependencies);
00236
00237 if (message.isEmpty())
00238 details->setVisible(false);
00239 else
00240 {
00241 details->setVisible(true);
00242 details->setText(message);
00243 }
00244 }
00245
00246
00247 KPluginSelector::KPluginSelector(QWidget *parent)
00248 : QWidget(parent)
00249 , d(new Private(this))
00250 {
00251 QVBoxLayout *layout = new QVBoxLayout;
00252 layout->setMargin(0);
00253 setLayout(layout);
00254
00255 d->lineEdit = new KLineEdit(this);
00256 d->lineEdit->setClearButtonShown(true);
00257 d->lineEdit->setClickMessage(i18n("Search Plugins"));
00258 d->listView = new KCategorizedView(this);
00259 d->listView->setVerticalScrollMode(QListView::ScrollPerPixel);
00260 d->listView->setAlternatingRowColors(true);
00261 d->listView->setCategoryDrawer(d->categoryDrawer);
00262 d->dependenciesWidget = new Private::DependenciesWidget(this);
00263
00264 d->pluginModel = new Private::PluginModel(d, this);
00265 d->proxyModel = new Private::ProxyModel(d, this);
00266 d->proxyModel->setCategorizedModel(true);
00267 d->proxyModel->setSourceModel(d->pluginModel);
00268 d->listView->setModel(d->proxyModel);
00269 d->listView->setAlternatingRowColors(true);
00270
00271 Private::PluginDelegate *pluginDelegate = new Private::PluginDelegate(d, this);
00272 d->listView->setItemDelegate(pluginDelegate);
00273
00274 d->listView->setMouseTracking(true);
00275 d->listView->viewport()->setAttribute(Qt::WA_Hover);
00276
00277 connect(d->lineEdit, SIGNAL(textChanged(QString)), d->proxyModel, SLOT(invalidate()));
00278 connect(pluginDelegate, SIGNAL(changed(bool)), this, SIGNAL(changed(bool)));
00279 connect(pluginDelegate, SIGNAL(configCommitted(QByteArray)), this, SIGNAL(configCommitted(QByteArray)));
00280
00281 layout->addWidget(d->lineEdit);
00282 layout->addWidget(d->listView);
00283 layout->addWidget(d->dependenciesWidget);
00284 }
00285
00286 KPluginSelector::~KPluginSelector()
00287 {
00288 delete d->listView;
00289 delete d;
00290 }
00291
00292 void KPluginSelector::addPlugins(const QString &componentName,
00293 const QString &categoryName,
00294 const QString &categoryKey,
00295 KSharedConfig::Ptr config)
00296 {
00297 QStringList desktopFileNames = KGlobal::dirs()->findAllResources("data",
00298 componentName + "/kpartplugins/*.desktop", KStandardDirs::Recursive);
00299
00300 QList<KPluginInfo> pluginInfoList = KPluginInfo::fromFiles(desktopFileNames);
00301
00302 if (pluginInfoList.isEmpty())
00303 return;
00304
00305 Q_ASSERT(config);
00306 if (!config)
00307 config = KSharedConfig::openConfig(componentName);
00308
00309 KConfigGroup cfgGroup(config, "KParts Plugins");
00310 kDebug( 702 ) << "cfgGroup = " << &cfgGroup;
00311
00312 d->pluginModel->addPlugins(pluginInfoList, categoryName, categoryKey, cfgGroup);
00313 }
00314
00315 void KPluginSelector::addPlugins(const KComponentData &instance,
00316 const QString &categoryName,
00317 const QString &categoryKey,
00318 const KSharedConfig::Ptr &config)
00319 {
00320 addPlugins(instance.componentName(), categoryName, categoryKey, config);
00321 }
00322
00323 void KPluginSelector::addPlugins(const QList<KPluginInfo> &pluginInfoList,
00324 PluginLoadMethod pluginLoadMethod,
00325 const QString &categoryName,
00326 const QString &categoryKey,
00327 const KSharedConfig::Ptr &config)
00328 {
00329 if (pluginInfoList.isEmpty())
00330 return;
00331
00332 KConfigGroup cfgGroup(config ? config : KGlobal::config(), "Plugins");
00333 kDebug( 702 ) << "cfgGroup = " << &cfgGroup;
00334
00335 d->pluginModel->addPlugins(pluginInfoList, categoryName, categoryKey, cfgGroup, pluginLoadMethod, true );
00336 }
00337
00338 void KPluginSelector::load()
00339 {
00340 for (int i = 0; i < d->pluginModel->rowCount(); i++) {
00341 const QModelIndex index = d->pluginModel->index(i, 0);
00342 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer());
00343 pluginEntry->pluginInfo.load(pluginEntry->cfgGroup);
00344 d->pluginModel->setData(index, pluginEntry->pluginInfo.isPluginEnabled(), Qt::CheckStateRole);
00345 }
00346
00347 emit changed(false);
00348 }
00349
00350 void KPluginSelector::save()
00351 {
00352 for (int i = 0; i < d->pluginModel->rowCount(); i++) {
00353 const QModelIndex index = d->pluginModel->index(i, 0);
00354 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer());
00355 pluginEntry->pluginInfo.setPluginEnabled(pluginEntry->checked);
00356 pluginEntry->pluginInfo.save(pluginEntry->cfgGroup);
00357 pluginEntry->cfgGroup.sync();
00358 }
00359
00360 emit changed(false);
00361 }
00362
00363 void KPluginSelector::defaults()
00364 {
00365 for (int i = 0; i < d->pluginModel->rowCount(); i++) {
00366 const QModelIndex index = d->pluginModel->index(i, 0);
00367 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer());
00368 d->pluginModel->setData(index, pluginEntry->pluginInfo.isPluginEnabledByDefault(), Qt::CheckStateRole);
00369 }
00370
00371 emit changed(true);
00372 }
00373
00374 bool KPluginSelector::isDefault() const
00375 {
00376 for (int i = 0; i < d->pluginModel->rowCount(); i++) {
00377 const QModelIndex index = d->pluginModel->index(i, 0);
00378 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer());
00379 if (d->pluginModel->data(index, Qt::CheckStateRole).toBool() != pluginEntry->pluginInfo.isPluginEnabledByDefault()) {
00380 return false;
00381 }
00382 }
00383
00384 return true;
00385 }
00386
00387 void KPluginSelector::updatePluginsState()
00388 {
00389 for (int i = 0; i < d->pluginModel->rowCount(); i++) {
00390 const QModelIndex index = d->pluginModel->index(i, 0);
00391 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer());
00392 if (pluginEntry->manuallyAdded) {
00393 pluginEntry->pluginInfo.setPluginEnabled(pluginEntry->checked);
00394 }
00395 }
00396 }
00397
00398 KPluginSelector::Private::PluginModel::PluginModel(KPluginSelector::Private *pluginSelector_d, QObject *parent)
00399 : QAbstractListModel(parent)
00400 , pluginSelector_d(pluginSelector_d)
00401 {
00402 }
00403
00404 KPluginSelector::Private::PluginModel::~PluginModel()
00405 {
00406 }
00407
00408 void KPluginSelector::Private::PluginModel::addPlugins(const QList<KPluginInfo> &pluginList, const QString &categoryName, const QString &categoryKey, const KConfigGroup &cfgGroup, PluginLoadMethod pluginLoadMethod, bool manuallyAdded)
00409 {
00410 QList<PluginEntry> listToAdd;
00411
00412 foreach (const KPluginInfo &pluginInfo, pluginList) {
00413 PluginEntry pluginEntry;
00414 pluginEntry.category = categoryName;
00415 pluginEntry.pluginInfo = pluginInfo;
00416 if (pluginLoadMethod == ReadConfigFile) {
00417 pluginEntry.pluginInfo.load(cfgGroup);
00418 }
00419 pluginEntry.checked = pluginInfo.isPluginEnabled();
00420 pluginEntry.manuallyAdded = manuallyAdded;
00421 if (cfgGroup.isValid()) {
00422 pluginEntry.cfgGroup = cfgGroup;
00423 } else {
00424 pluginEntry.cfgGroup = pluginInfo.config();
00425 }
00426
00427
00428 pluginEntry.isCheckable = !pluginInfo.isValid() || !pluginEntry.cfgGroup.isEntryImmutable(pluginInfo.pluginName() + QLatin1String("Enabled"));
00429
00430 if (!pluginEntryList.contains(pluginEntry) && !listToAdd.contains(pluginEntry) &&
00431 (!pluginInfo.property("X-KDE-PluginInfo-Category").isValid() ||
00432 !pluginInfo.property("X-KDE-PluginInfo-Category").toString().compare(categoryKey, Qt::CaseInsensitive)) &&
00433 (pluginInfo.service().isNull() || !pluginInfo.service()->noDisplay())) {
00434 listToAdd << pluginEntry;
00435
00436 if (!pluginSelector_d->showIcons && !pluginInfo.icon().isEmpty()) {
00437 pluginSelector_d->showIcons = true;
00438 }
00439 }
00440 }
00441
00442 if (listToAdd.count()) {
00443 beginInsertRows(QModelIndex(), pluginEntryList.count(), pluginEntryList.count() + listToAdd.count() - 1);
00444 pluginEntryList << listToAdd;
00445 endInsertRows();
00446 }
00447 }
00448
00449 QList<KService::Ptr> KPluginSelector::Private::PluginModel::pluginServices(const QModelIndex &index) const
00450 {
00451 return static_cast<PluginEntry*>(index.internalPointer())->pluginInfo.kcmServices();
00452 }
00453
00454 QModelIndex KPluginSelector::Private::PluginModel::index(int row, int column, const QModelIndex &parent) const
00455 {
00456 Q_UNUSED(parent)
00457
00458 return createIndex(row, column, (row < pluginEntryList.count()) ? (void*) &pluginEntryList.at(row)
00459 : 0);
00460 }
00461
00462 QVariant KPluginSelector::Private::PluginModel::data(const QModelIndex &index, int role) const
00463 {
00464 if (!index.isValid() || !index.internalPointer()) {
00465 return QVariant();
00466 }
00467
00468 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer());
00469
00470 switch (role) {
00471 case Qt::DisplayRole:
00472 return pluginEntry->pluginInfo.name();
00473 case PluginEntryRole:
00474 return QVariant::fromValue(pluginEntry);
00475 case ServicesCountRole:
00476 return pluginEntry->pluginInfo.kcmServices().count();
00477 case NameRole:
00478 return pluginEntry->pluginInfo.name();
00479 case CommentRole:
00480 return pluginEntry->pluginInfo.comment();
00481 case AuthorRole:
00482 return pluginEntry->pluginInfo.author();
00483 case EmailRole:
00484 return pluginEntry->pluginInfo.email();
00485 case WebsiteRole:
00486 return pluginEntry->pluginInfo.website();
00487 case VersionRole:
00488 return pluginEntry->pluginInfo.version();
00489 case LicenseRole:
00490 return pluginEntry->pluginInfo.license();
00491 case DependenciesRole:
00492 return pluginEntry->pluginInfo.dependencies();
00493 case IsCheckableRole:
00494 return pluginEntry->isCheckable;
00495 case Qt::DecorationRole:
00496 return pluginEntry->pluginInfo.icon();
00497 case Qt::CheckStateRole:
00498 return pluginEntry->checked;
00499 case KCategorizedSortFilterProxyModel::CategoryDisplayRole:
00500 case KCategorizedSortFilterProxyModel::CategorySortRole:
00501 return pluginEntry->category;
00502 default:
00503 return QVariant();
00504 }
00505 }
00506
00507 bool KPluginSelector::Private::PluginModel::setData(const QModelIndex &index, const QVariant &value, int role)
00508 {
00509 if (!index.isValid()) {
00510 return false;
00511 }
00512
00513 bool ret = false;
00514
00515 if (role == Qt::CheckStateRole) {
00516 static_cast<PluginEntry*>(index.internalPointer())->checked = value.toBool();
00517 ret = true;
00518 }
00519
00520 if (ret) {
00521 emit dataChanged(index, index);
00522 }
00523
00524 return ret;
00525 }
00526
00527 int KPluginSelector::Private::PluginModel::rowCount(const QModelIndex &parent) const
00528 {
00529 if (parent.isValid()) {
00530 return 0;
00531 }
00532
00533 return pluginEntryList.count();
00534 }
00535
00536 KPluginSelector::Private::ProxyModel::ProxyModel(KPluginSelector::Private *pluginSelector_d, QObject *parent)
00537 : KCategorizedSortFilterProxyModel(parent)
00538 , pluginSelector_d(pluginSelector_d)
00539 {
00540 sort(0);
00541 }
00542
00543 KPluginSelector::Private::ProxyModel::~ProxyModel()
00544 {
00545 }
00546
00547 bool KPluginSelector::Private::ProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
00548 {
00549 Q_UNUSED(sourceParent)
00550
00551 if (!pluginSelector_d->lineEdit->text().isEmpty()) {
00552 const QModelIndex index = sourceModel()->index(sourceRow, 0);
00553 const KPluginInfo pluginInfo = static_cast<PluginEntry*>(index.internalPointer())->pluginInfo;
00554 return pluginInfo.name().contains(pluginSelector_d->lineEdit->text(), Qt::CaseInsensitive) ||
00555 pluginInfo.comment().contains(pluginSelector_d->lineEdit->text(), Qt::CaseInsensitive);
00556 }
00557
00558 return true;
00559 }
00560
00561 bool KPluginSelector::Private::ProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const
00562 {
00563 return static_cast<PluginEntry*>(left.internalPointer())->pluginInfo.name().compare(static_cast<PluginEntry*>(right.internalPointer())->pluginInfo.name(), Qt::CaseInsensitive) < 0;
00564 }
00565
00566 KPluginSelector::Private::PluginDelegate::PluginDelegate(KPluginSelector::Private *pluginSelector_d, QObject *parent)
00567 : KWidgetItemDelegate(pluginSelector_d->listView, parent)
00568 , checkBox(new QCheckBox)
00569 , pushButton(new KPushButton)
00570 , pluginSelector_d(pluginSelector_d)
00571 {
00572 pushButton->setIcon(KIcon("configure"));
00573 }
00574
00575 KPluginSelector::Private::PluginDelegate::~PluginDelegate()
00576 {
00577 delete checkBox;
00578 delete pushButton;
00579 }
00580
00581 void KPluginSelector::Private::PluginDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
00582 {
00583 if (!index.isValid()) {
00584 return;
00585 }
00586
00587 int xOffset = checkBox->sizeHint().width();
00588 bool disabled = !index.model()->data(index, IsCheckableRole).toBool();
00589
00590 painter->save();
00591
00592 QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0);
00593
00594 int iconSize = option.rect.height() - MARGIN * 2;
00595 if (pluginSelector_d->showIcons) {
00596 QPixmap pixmap = KIconLoader::global()->loadIcon(index.model()->data(index, Qt::DecorationRole).toString(),
00597 KIconLoader::Desktop, iconSize, disabled ? KIconLoader::DisabledState : KIconLoader::DefaultState);
00598
00599 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));
00600 } else {
00601 iconSize = -MARGIN;
00602 }
00603
00604 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);
00605
00606 int lessHorizontalSpace = MARGIN * 2 + pushButton->sizeHint().width();
00607 if (index.model()->data(index, ServicesCountRole).toBool()) {
00608 lessHorizontalSpace += MARGIN + pushButton->sizeHint().width();
00609 }
00610
00611 contentsRect.setWidth(contentsRect.width() - lessHorizontalSpace);
00612
00613 if (option.state & QStyle::State_Selected) {
00614 painter->setPen(option.palette.highlightedText().color());
00615 }
00616
00617 if (pluginSelector_d->listView->layoutDirection() == Qt::RightToLeft) {
00618 contentsRect.translate(lessHorizontalSpace, 0);
00619 }
00620
00621 painter->save();
00622 if (disabled) {
00623 QPalette pal(option.palette);
00624 pal.setCurrentColorGroup(QPalette::Disabled);
00625 painter->setPen(pal.text().color());
00626 }
00627
00628 painter->save();
00629 QFont font = titleFont(option.font);
00630 QFontMetrics fmTitle(font);
00631 painter->setFont(font);
00632 painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignTop, fmTitle.elidedText(index.model()->data(index, Qt::DisplayRole).toString(), Qt::ElideRight, contentsRect.width()));
00633 painter->restore();
00634
00635 painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignBottom, option.fontMetrics.elidedText(index.model()->data(index, CommentRole).toString(), Qt::ElideRight, contentsRect.width()));
00636
00637 painter->restore();
00638 painter->restore();
00639 }
00640
00641 QSize KPluginSelector::Private::PluginDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
00642 {
00643 int i = 5;
00644 int j = 1;
00645 if (index.model()->data(index, ServicesCountRole).toBool()) {
00646 i = 6;
00647 j = 2;
00648 }
00649
00650 if (!pluginSelector_d->showIcons) {
00651 i--;
00652 }
00653
00654 QFont font = titleFont(option.font);
00655 QFontMetrics fmTitle(font);
00656
00657 return QSize(qMax(fmTitle.width(index.model()->data(index, Qt::DisplayRole).toString()),
00658 option.fontMetrics.width(index.model()->data(index, CommentRole).toString())) +
00659 pluginSelector_d->showIcons ? KIconLoader::SizeMedium : 0 + MARGIN * i + pushButton->sizeHint().width() * j,
00660 qMax(KIconLoader::SizeMedium + MARGIN * 2, fmTitle.height() + option.fontMetrics.height() + MARGIN * 2));
00661 }
00662
00663 QList<QWidget*> KPluginSelector::Private::PluginDelegate::createItemWidgets() const
00664 {
00665 QList<QWidget*> widgetList;
00666
00667 QCheckBox *enabledCheckBox = new QCheckBox;
00668 connect(enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(slotStateChanged(bool)));
00669 connect(enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(emitChanged()));
00670
00671 KPushButton *aboutPushButton = new KPushButton;
00672 aboutPushButton->setIcon(KIcon("dialog-information"));
00673 connect(aboutPushButton, SIGNAL(clicked(bool)), this, SLOT(slotAboutClicked()));
00674
00675 KPushButton *configurePushButton = new KPushButton;
00676 configurePushButton->setIcon(KIcon("configure"));
00677 connect(configurePushButton, SIGNAL(clicked(bool)), this, SLOT(slotConfigureClicked()));
00678
00679 setBlockedEventTypes(enabledCheckBox, QList<QEvent::Type>() << QEvent::MouseButtonPress
00680 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick
00681 << QEvent::KeyPress << QEvent::KeyRelease);
00682
00683 setBlockedEventTypes(aboutPushButton, QList<QEvent::Type>() << QEvent::MouseButtonPress
00684 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick
00685 << QEvent::KeyPress << QEvent::KeyRelease);
00686
00687 setBlockedEventTypes(configurePushButton, QList<QEvent::Type>() << QEvent::MouseButtonPress
00688 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick
00689 << QEvent::KeyPress << QEvent::KeyRelease);
00690
00691 widgetList << enabledCheckBox << configurePushButton << aboutPushButton;
00692
00693 return widgetList;
00694 }
00695
00696 void KPluginSelector::Private::PluginDelegate::updateItemWidgets(const QList<QWidget*> widgets,
00697 const QStyleOptionViewItem &option,
00698 const QPersistentModelIndex &index) const
00699 {
00700 QCheckBox *checkBox = static_cast<QCheckBox*>(widgets[0]);
00701 checkBox->resize(checkBox->sizeHint());
00702 checkBox->move(pluginSelector_d->dependantLayoutValue(MARGIN, checkBox->sizeHint().width(), option.rect.width()), option.rect.height() / 2 - checkBox->sizeHint().height() / 2);
00703
00704 KPushButton *aboutPushButton = static_cast<KPushButton*>(widgets[2]);
00705 QSize aboutPushButtonSizeHint = aboutPushButton->sizeHint();
00706 aboutPushButton->resize(aboutPushButtonSizeHint);
00707 aboutPushButton->move(pluginSelector_d->dependantLayoutValue(option.rect.width() - MARGIN - aboutPushButtonSizeHint.width(), aboutPushButtonSizeHint.width(), option.rect.width()), option.rect.height() / 2 - aboutPushButtonSizeHint.height() / 2);
00708
00709 KPushButton *configurePushButton = static_cast<KPushButton*>(widgets[1]);
00710 QSize configurePushButtonSizeHint = configurePushButton->sizeHint();
00711 configurePushButton->resize(configurePushButtonSizeHint);
00712 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);
00713
00714 if (!index.isValid() || !index.internalPointer()) {
00715 checkBox->setVisible(false);
00716 aboutPushButton->setVisible(false);
00717 configurePushButton->setVisible(false);
00718 } else {
00719 checkBox->setChecked(index.model()->data(index, Qt::CheckStateRole).toBool());
00720 checkBox->setEnabled(index.model()->data(index, IsCheckableRole).toBool());
00721 configurePushButton->setVisible(index.model()->data(index, ServicesCountRole).toBool());
00722 configurePushButton->setEnabled(index.model()->data(index, Qt::CheckStateRole).toBool());
00723 }
00724 }
00725
00726 void KPluginSelector::Private::PluginDelegate::slotStateChanged(bool state)
00727 {
00728 if (!focusedIndex().isValid())
00729 return;
00730
00731 const QModelIndex index = focusedIndex();
00732
00733 pluginSelector_d->dependenciesWidget->clearDependencies();
00734
00735 PluginEntry *pluginEntry = index.model()->data(index, PluginEntryRole).value<PluginEntry*>();
00736 pluginSelector_d->updateDependencies(pluginEntry, state);
00737
00738 const_cast<QAbstractItemModel*>(index.model())->setData(index, state, Qt::CheckStateRole);
00739 }
00740
00741 void KPluginSelector::Private::PluginDelegate::emitChanged()
00742 {
00743 emit changed(true);
00744 }
00745
00746 void KPluginSelector::Private::PluginDelegate::slotAboutClicked()
00747 {
00748 const QModelIndex index = focusedIndex();
00749 const QAbstractItemModel *model = index.model();
00750
00751
00752
00753
00754
00755 PluginEntry *entry = index.model()->data(index, PluginEntryRole).value<PluginEntry*>();
00756 KService::Ptr entryService = entry->pluginInfo.service();
00757 if (entryService) {
00758 KPluginLoader loader(*entryService);
00759 KPluginFactory *factory = loader.factory();
00760 if (factory) {
00761 const KAboutData *aboutData = factory->componentData().aboutData();
00762 if (!aboutData->programName().isEmpty()) {
00763 KAboutApplicationDialog aboutPlugin(aboutData, itemView());
00764 aboutPlugin.exec();
00765 return;
00766 }
00767 }
00768 }
00769
00770 const QString name = model->data(index, NameRole).toString();
00771 const QString comment = model->data(index, CommentRole).toString();
00772 const QString author = model->data(index, AuthorRole).toString();
00773 const QString email = model->data(index, EmailRole).toString();
00774 const QString website = model->data(index, WebsiteRole).toString();
00775 const QString version = model->data(index, VersionRole).toString();
00776 const QString license = model->data(index, LicenseRole).toString();
00777
00778 KAboutData aboutData(name.toUtf8(), name.toUtf8(), ki18n(name.toUtf8()), version.toUtf8(), ki18n(comment.toUtf8()), KAboutLicense::byKeyword(license).key(), ki18n(QByteArray()), ki18n(QByteArray()), website.toLatin1());
00779 aboutData.setProgramIconName(index.model()->data(index, Qt::DecorationRole).toString());
00780 const QStringList authors = author.split(',');
00781 const QStringList emails = email.split(',');
00782 int i = 0;
00783 if (authors.count() == emails.count()) {
00784 foreach (const QString &author, authors) {
00785 if (!author.isEmpty()) {
00786 aboutData.addAuthor(ki18n(author.toUtf8()), ki18n(QByteArray()), emails[i].toUtf8(), 0);
00787 }
00788 i++;
00789 }
00790 }
00791 KAboutApplicationDialog aboutPlugin(&aboutData, itemView());
00792 aboutPlugin.exec();
00793 }
00794
00795 void KPluginSelector::Private::PluginDelegate::slotConfigureClicked()
00796 {
00797 const QModelIndex index = focusedIndex();
00798 const QAbstractItemModel *model = index.model();
00799
00800 PluginEntry *pluginEntry = model->data(index, PluginEntryRole).value<PluginEntry*>();
00801 KPluginInfo pluginInfo = pluginEntry->pluginInfo;
00802
00803 KDialog configDialog(itemView());
00804 configDialog.setWindowTitle(model->data(index, NameRole).toString());
00805
00806 KTabWidget *newTabWidget = 0;
00807
00808
00809 QWidget * mainWidget = 0;
00810
00811
00812 QWidget *moduleProxyParentWidget = &configDialog;
00813
00814 foreach (const KService::Ptr &servicePtr, pluginInfo.kcmServices()) {
00815 if(!servicePtr->noDisplay()) {
00816 KCModuleInfo moduleInfo(servicePtr);
00817 KCModuleProxy *currentModuleProxy = new KCModuleProxy(moduleInfo, moduleProxyParentWidget);
00818 if (currentModuleProxy->realModule()) {
00819 moduleProxyList << currentModuleProxy;
00820 if (mainWidget && !newTabWidget) {
00821
00822
00823
00824 newTabWidget = new KTabWidget(&configDialog);
00825 moduleProxyParentWidget = newTabWidget;
00826 mainWidget->setParent( newTabWidget );
00827 KCModuleProxy *moduleProxy = qobject_cast<KCModuleProxy*>(mainWidget);
00828 if (moduleProxy) {
00829 newTabWidget->addTab(mainWidget, moduleProxy->moduleInfo().moduleName());
00830 mainWidget = newTabWidget;
00831 } else {
00832 delete newTabWidget;
00833 newTabWidget = 0;
00834 moduleProxyParentWidget = &configDialog;
00835 mainWidget->setParent(0);
00836 }
00837 }
00838
00839 if (newTabWidget) {
00840 newTabWidget->addTab(currentModuleProxy, servicePtr->name());
00841 } else {
00842 mainWidget = currentModuleProxy;
00843 }
00844 } else {
00845 delete currentModuleProxy;
00846 }
00847 }
00848 }
00849
00850
00851 if (moduleProxyList.count()) {
00852 configDialog.setButtons(KDialog::Ok | KDialog::Cancel | KDialog::Default);
00853
00854 QWidget *showWidget = new QWidget(&configDialog);
00855 QVBoxLayout *layout = new QVBoxLayout;
00856 showWidget->setLayout(layout);
00857 layout->addWidget(mainWidget);
00858 layout->insertSpacing(-1, KDialog::marginHint());
00859 configDialog.setMainWidget(showWidget);
00860
00861 connect(&configDialog, SIGNAL(defaultClicked()), this, SLOT(slotDefaultClicked()));
00862
00863 if (configDialog.exec() == QDialog::Accepted) {
00864 foreach (KCModuleProxy *moduleProxy, moduleProxyList) {
00865 QStringList parentComponents = moduleProxy->moduleInfo().service()->property("X-KDE-ParentComponents").toStringList();
00866 moduleProxy->save();
00867 foreach (const QString &parentComponent, parentComponents) {
00868 emit configCommitted(parentComponent.toLatin1());
00869 }
00870 }
00871 } else {
00872 foreach (KCModuleProxy *moduleProxy, moduleProxyList) {
00873 moduleProxy->load();
00874 }
00875 }
00876
00877 qDeleteAll(moduleProxyList);
00878 moduleProxyList.clear();
00879 }
00880 }
00881
00882 void KPluginSelector::Private::PluginDelegate::slotDefaultClicked()
00883 {
00884 foreach (KCModuleProxy *moduleProxy, moduleProxyList) {
00885 moduleProxy->defaults();
00886 }
00887 }
00888
00889 QFont KPluginSelector::Private::PluginDelegate::titleFont(const QFont &baseFont) const
00890 {
00891 QFont retFont(baseFont);
00892 retFont.setBold(true);
00893
00894 return retFont;
00895 }
00896
00897 #include "kpluginselector_p.moc"
00898 #include "kpluginselector.moc"