KUtils
kpluginselector.cpp
Go to the documentation of this file.
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)) // The dependency moved from added to removed or vice-versa 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->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // bug 213068 00261 d->listView->setAlternatingRowColors(true); 00262 d->listView->setCategoryDrawer(d->categoryDrawer); 00263 d->dependenciesWidget = new Private::DependenciesWidget(this); 00264 00265 d->pluginModel = new Private::PluginModel(d, this); 00266 d->proxyModel = new Private::ProxyModel(d, this); 00267 d->proxyModel->setCategorizedModel(true); 00268 d->proxyModel->setSourceModel(d->pluginModel); 00269 d->listView->setModel(d->proxyModel); 00270 d->listView->setAlternatingRowColors(true); 00271 00272 Private::PluginDelegate *pluginDelegate = new Private::PluginDelegate(d, this); 00273 d->listView->setItemDelegate(pluginDelegate); 00274 00275 d->listView->setMouseTracking(true); 00276 d->listView->viewport()->setAttribute(Qt::WA_Hover); 00277 00278 connect(d->lineEdit, SIGNAL(textChanged(QString)), d->proxyModel, SLOT(invalidate())); 00279 connect(pluginDelegate, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); 00280 connect(pluginDelegate, SIGNAL(configCommitted(QByteArray)), this, SIGNAL(configCommitted(QByteArray))); 00281 00282 layout->addWidget(d->lineEdit); 00283 layout->addWidget(d->listView); 00284 layout->addWidget(d->dependenciesWidget); 00285 } 00286 00287 KPluginSelector::~KPluginSelector() 00288 { 00289 delete d->listView->itemDelegate(); 00290 delete d->listView; // depends on some other things in d, make sure this dies first. 00291 delete d; 00292 } 00293 00294 void KPluginSelector::addPlugins(const QString &componentName, 00295 const QString &categoryName, 00296 const QString &categoryKey, 00297 KSharedConfig::Ptr config) 00298 { 00299 QStringList desktopFileNames = KGlobal::dirs()->findAllResources("data", 00300 componentName + "/kpartplugins/*.desktop", KStandardDirs::Recursive); 00301 00302 QList<KPluginInfo> pluginInfoList = KPluginInfo::fromFiles(desktopFileNames); 00303 00304 if (pluginInfoList.isEmpty()) 00305 return; 00306 00307 Q_ASSERT(config); 00308 if (!config) 00309 config = KSharedConfig::openConfig(componentName); 00310 00311 KConfigGroup cfgGroup(config, "KParts Plugins"); 00312 kDebug( 702 ) << "cfgGroup = " << &cfgGroup; 00313 00314 d->pluginModel->addPlugins(pluginInfoList, categoryName, categoryKey, cfgGroup); 00315 d->proxyModel->sort(0); 00316 } 00317 00318 void KPluginSelector::addPlugins(const KComponentData &instance, 00319 const QString &categoryName, 00320 const QString &categoryKey, 00321 const KSharedConfig::Ptr &config) 00322 { 00323 addPlugins(instance.componentName(), categoryName, categoryKey, config); 00324 } 00325 00326 void KPluginSelector::addPlugins(const QList<KPluginInfo> &pluginInfoList, 00327 PluginLoadMethod pluginLoadMethod, 00328 const QString &categoryName, 00329 const QString &categoryKey, 00330 const KSharedConfig::Ptr &config) 00331 { 00332 if (pluginInfoList.isEmpty()) 00333 return; 00334 00335 KConfigGroup cfgGroup(config ? config : KGlobal::config(), "Plugins"); 00336 kDebug( 702 ) << "cfgGroup = " << &cfgGroup; 00337 00338 d->pluginModel->addPlugins(pluginInfoList, categoryName, categoryKey, cfgGroup, pluginLoadMethod, true /* manually added */); 00339 d->proxyModel->sort(0); 00340 } 00341 00342 void KPluginSelector::load() 00343 { 00344 for (int i = 0; i < d->pluginModel->rowCount(); i++) { 00345 const QModelIndex index = d->pluginModel->index(i, 0); 00346 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer()); 00347 pluginEntry->pluginInfo.load(pluginEntry->cfgGroup); 00348 d->pluginModel->setData(index, pluginEntry->pluginInfo.isPluginEnabled(), Qt::CheckStateRole); 00349 } 00350 00351 emit changed(false); 00352 } 00353 00354 void KPluginSelector::save() 00355 { 00356 for (int i = 0; i < d->pluginModel->rowCount(); i++) { 00357 const QModelIndex index = d->pluginModel->index(i, 0); 00358 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer()); 00359 pluginEntry->pluginInfo.setPluginEnabled(pluginEntry->checked); 00360 pluginEntry->pluginInfo.save(pluginEntry->cfgGroup); 00361 pluginEntry->cfgGroup.sync(); 00362 } 00363 00364 emit changed(false); 00365 } 00366 00367 void KPluginSelector::defaults() 00368 { 00369 for (int i = 0; i < d->pluginModel->rowCount(); i++) { 00370 const QModelIndex index = d->pluginModel->index(i, 0); 00371 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer()); 00372 d->pluginModel->setData(index, pluginEntry->pluginInfo.isPluginEnabledByDefault(), Qt::CheckStateRole); 00373 } 00374 00375 emit changed(true); 00376 } 00377 00378 bool KPluginSelector::isDefault() const 00379 { 00380 for (int i = 0; i < d->pluginModel->rowCount(); i++) { 00381 const QModelIndex index = d->pluginModel->index(i, 0); 00382 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer()); 00383 if (d->pluginModel->data(index, Qt::CheckStateRole).toBool() != pluginEntry->pluginInfo.isPluginEnabledByDefault()) { 00384 return false; 00385 } 00386 } 00387 00388 return true; 00389 } 00390 00391 void KPluginSelector::updatePluginsState() 00392 { 00393 for (int i = 0; i < d->pluginModel->rowCount(); i++) { 00394 const QModelIndex index = d->pluginModel->index(i, 0); 00395 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer()); 00396 if (pluginEntry->manuallyAdded) { 00397 pluginEntry->pluginInfo.setPluginEnabled(pluginEntry->checked); 00398 } 00399 } 00400 } 00401 00402 KPluginSelector::Private::PluginModel::PluginModel(KPluginSelector::Private *pluginSelector_d, QObject *parent) 00403 : QAbstractListModel(parent) 00404 , pluginSelector_d(pluginSelector_d) 00405 { 00406 } 00407 00408 KPluginSelector::Private::PluginModel::~PluginModel() 00409 { 00410 } 00411 00412 void KPluginSelector::Private::PluginModel::addPlugins(const QList<KPluginInfo> &pluginList, const QString &categoryName, const QString &categoryKey, const KConfigGroup &cfgGroup, PluginLoadMethod pluginLoadMethod, bool manuallyAdded) 00413 { 00414 QList<PluginEntry> listToAdd; 00415 00416 foreach (const KPluginInfo &pluginInfo, pluginList) { 00417 PluginEntry pluginEntry; 00418 pluginEntry.category = categoryName; 00419 pluginEntry.pluginInfo = pluginInfo; 00420 if (pluginLoadMethod == ReadConfigFile) { 00421 pluginEntry.pluginInfo.load(cfgGroup); 00422 } 00423 pluginEntry.checked = pluginInfo.isPluginEnabled(); 00424 pluginEntry.manuallyAdded = manuallyAdded; 00425 if (cfgGroup.isValid()) { 00426 pluginEntry.cfgGroup = cfgGroup; 00427 } else { 00428 pluginEntry.cfgGroup = pluginInfo.config(); 00429 } 00430 00431 // this is where kiosk will set if a plugin is checkable or not (pluginName + "Enabled") 00432 pluginEntry.isCheckable = !pluginInfo.isValid() || !pluginEntry.cfgGroup.isEntryImmutable(pluginInfo.pluginName() + QLatin1String("Enabled")); 00433 00434 if (!pluginEntryList.contains(pluginEntry) && !listToAdd.contains(pluginEntry) && 00435 (!pluginInfo.property("X-KDE-PluginInfo-Category").isValid() || 00436 !pluginInfo.property("X-KDE-PluginInfo-Category").toString().compare(categoryKey, Qt::CaseInsensitive)) && 00437 (pluginInfo.service().isNull() || !pluginInfo.service()->noDisplay())) { 00438 listToAdd << pluginEntry; 00439 00440 if (!pluginSelector_d->showIcons && !pluginInfo.icon().isEmpty()) { 00441 pluginSelector_d->showIcons = true; 00442 } 00443 } 00444 } 00445 00446 if (listToAdd.count()) { 00447 beginInsertRows(QModelIndex(), pluginEntryList.count(), pluginEntryList.count() + listToAdd.count() - 1); 00448 pluginEntryList << listToAdd; 00449 endInsertRows(); 00450 } 00451 } 00452 00453 QList<KService::Ptr> KPluginSelector::Private::PluginModel::pluginServices(const QModelIndex &index) const 00454 { 00455 return static_cast<PluginEntry*>(index.internalPointer())->pluginInfo.kcmServices(); 00456 } 00457 00458 QModelIndex KPluginSelector::Private::PluginModel::index(int row, int column, const QModelIndex &parent) const 00459 { 00460 Q_UNUSED(parent) 00461 00462 return createIndex(row, column, (row < pluginEntryList.count()) ? (void*) &pluginEntryList.at(row) 00463 : 0); 00464 } 00465 00466 QVariant KPluginSelector::Private::PluginModel::data(const QModelIndex &index, int role) const 00467 { 00468 if (!index.isValid() || !index.internalPointer()) { 00469 return QVariant(); 00470 } 00471 00472 PluginEntry *pluginEntry = static_cast<PluginEntry*>(index.internalPointer()); 00473 00474 switch (role) { 00475 case Qt::DisplayRole: 00476 return pluginEntry->pluginInfo.name(); 00477 case PluginEntryRole: 00478 return QVariant::fromValue(pluginEntry); 00479 case ServicesCountRole: 00480 return pluginEntry->pluginInfo.kcmServices().count(); 00481 case NameRole: 00482 return pluginEntry->pluginInfo.name(); 00483 case CommentRole: 00484 return pluginEntry->pluginInfo.comment(); 00485 case AuthorRole: 00486 return pluginEntry->pluginInfo.author(); 00487 case EmailRole: 00488 return pluginEntry->pluginInfo.email(); 00489 case WebsiteRole: 00490 return pluginEntry->pluginInfo.website(); 00491 case VersionRole: 00492 return pluginEntry->pluginInfo.version(); 00493 case LicenseRole: 00494 return pluginEntry->pluginInfo.license(); 00495 case DependenciesRole: 00496 return pluginEntry->pluginInfo.dependencies(); 00497 case IsCheckableRole: 00498 return pluginEntry->isCheckable; 00499 case Qt::DecorationRole: 00500 return pluginEntry->pluginInfo.icon(); 00501 case Qt::CheckStateRole: 00502 return pluginEntry->checked; 00503 case KCategorizedSortFilterProxyModel::CategoryDisplayRole: // fall through 00504 case KCategorizedSortFilterProxyModel::CategorySortRole: 00505 return pluginEntry->category; 00506 default: 00507 return QVariant(); 00508 } 00509 } 00510 00511 bool KPluginSelector::Private::PluginModel::setData(const QModelIndex &index, const QVariant &value, int role) 00512 { 00513 if (!index.isValid()) { 00514 return false; 00515 } 00516 00517 bool ret = false; 00518 00519 if (role == Qt::CheckStateRole) { 00520 static_cast<PluginEntry*>(index.internalPointer())->checked = value.toBool(); 00521 ret = true; 00522 } 00523 00524 if (ret) { 00525 emit dataChanged(index, index); 00526 } 00527 00528 return ret; 00529 } 00530 00531 int KPluginSelector::Private::PluginModel::rowCount(const QModelIndex &parent) const 00532 { 00533 if (parent.isValid()) { 00534 return 0; 00535 } 00536 00537 return pluginEntryList.count(); 00538 } 00539 00540 KPluginSelector::Private::ProxyModel::ProxyModel(KPluginSelector::Private *pluginSelector_d, QObject *parent) 00541 : KCategorizedSortFilterProxyModel(parent) 00542 , pluginSelector_d(pluginSelector_d) 00543 { 00544 sort(0); 00545 } 00546 00547 KPluginSelector::Private::ProxyModel::~ProxyModel() 00548 { 00549 } 00550 00551 bool KPluginSelector::Private::ProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const 00552 { 00553 Q_UNUSED(sourceParent) 00554 00555 if (!pluginSelector_d->lineEdit->text().isEmpty()) { 00556 const QModelIndex index = sourceModel()->index(sourceRow, 0); 00557 const KPluginInfo pluginInfo = static_cast<PluginEntry*>(index.internalPointer())->pluginInfo; 00558 return pluginInfo.name().contains(pluginSelector_d->lineEdit->text(), Qt::CaseInsensitive) || 00559 pluginInfo.comment().contains(pluginSelector_d->lineEdit->text(), Qt::CaseInsensitive); 00560 } 00561 00562 return true; 00563 } 00564 00565 bool KPluginSelector::Private::ProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const 00566 { 00567 return static_cast<PluginEntry*>(left.internalPointer())->pluginInfo.name().compare(static_cast<PluginEntry*>(right.internalPointer())->pluginInfo.name(), Qt::CaseInsensitive) < 0; 00568 } 00569 00570 KPluginSelector::Private::PluginDelegate::PluginDelegate(KPluginSelector::Private *pluginSelector_d, QObject *parent) 00571 : KWidgetItemDelegate(pluginSelector_d->listView, parent) 00572 , checkBox(new QCheckBox) 00573 , pushButton(new KPushButton) 00574 , pluginSelector_d(pluginSelector_d) 00575 { 00576 pushButton->setIcon(KIcon("configure")); // only for getting size matters 00577 } 00578 00579 KPluginSelector::Private::PluginDelegate::~PluginDelegate() 00580 { 00581 delete checkBox; 00582 delete pushButton; 00583 } 00584 00585 void KPluginSelector::Private::PluginDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 00586 { 00587 if (!index.isValid()) { 00588 return; 00589 } 00590 00591 int xOffset = checkBox->sizeHint().width(); 00592 bool disabled = !index.model()->data(index, IsCheckableRole).toBool(); 00593 00594 painter->save(); 00595 00596 QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0); 00597 00598 int iconSize = option.rect.height() - MARGIN * 2; 00599 if (pluginSelector_d->showIcons) { 00600 QPixmap pixmap = KIconLoader::global()->loadIcon(index.model()->data(index, Qt::DecorationRole).toString(), 00601 KIconLoader::Desktop, iconSize, disabled ? KIconLoader::DisabledState : KIconLoader::DefaultState); 00602 00603 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)); 00604 } else { 00605 iconSize = -MARGIN; 00606 } 00607 00608 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); 00609 00610 int lessHorizontalSpace = MARGIN * 2 + pushButton->sizeHint().width(); 00611 if (index.model()->data(index, ServicesCountRole).toBool()) { 00612 lessHorizontalSpace += MARGIN + pushButton->sizeHint().width(); 00613 } 00614 00615 contentsRect.setWidth(contentsRect.width() - lessHorizontalSpace); 00616 00617 if (option.state & QStyle::State_Selected) { 00618 painter->setPen(option.palette.highlightedText().color()); 00619 } 00620 00621 if (pluginSelector_d->listView->layoutDirection() == Qt::RightToLeft) { 00622 contentsRect.translate(lessHorizontalSpace, 0); 00623 } 00624 00625 painter->save(); 00626 if (disabled) { 00627 QPalette pal(option.palette); 00628 pal.setCurrentColorGroup(QPalette::Disabled); 00629 painter->setPen(pal.text().color()); 00630 } 00631 00632 painter->save(); 00633 QFont font = titleFont(option.font); 00634 QFontMetrics fmTitle(font); 00635 painter->setFont(font); 00636 painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignTop, fmTitle.elidedText(index.model()->data(index, Qt::DisplayRole).toString(), Qt::ElideRight, contentsRect.width())); 00637 painter->restore(); 00638 00639 painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignBottom, option.fontMetrics.elidedText(index.model()->data(index, CommentRole).toString(), Qt::ElideRight, contentsRect.width())); 00640 00641 painter->restore(); 00642 painter->restore(); 00643 } 00644 00645 QSize KPluginSelector::Private::PluginDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const 00646 { 00647 int i = 5; 00648 int j = 1; 00649 if (index.model()->data(index, ServicesCountRole).toBool()) { 00650 i = 6; 00651 j = 2; 00652 } 00653 00654 if (!pluginSelector_d->showIcons) { 00655 i--; 00656 } 00657 00658 QFont font = titleFont(option.font); 00659 QFontMetrics fmTitle(font); 00660 00661 return QSize(qMax(fmTitle.width(index.model()->data(index, Qt::DisplayRole).toString()), 00662 option.fontMetrics.width(index.model()->data(index, CommentRole).toString())) + 00663 pluginSelector_d->showIcons ? KIconLoader::SizeMedium : 0 + MARGIN * i + pushButton->sizeHint().width() * j, 00664 qMax(KIconLoader::SizeMedium + MARGIN * 2, fmTitle.height() + option.fontMetrics.height() + MARGIN * 2)); 00665 } 00666 00667 QList<QWidget*> KPluginSelector::Private::PluginDelegate::createItemWidgets() const 00668 { 00669 QList<QWidget*> widgetList; 00670 00671 QCheckBox *enabledCheckBox = new QCheckBox; 00672 connect(enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(slotStateChanged(bool))); 00673 connect(enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(emitChanged())); 00674 00675 KPushButton *aboutPushButton = new KPushButton; 00676 aboutPushButton->setIcon(KIcon("dialog-information")); 00677 connect(aboutPushButton, SIGNAL(clicked(bool)), this, SLOT(slotAboutClicked())); 00678 00679 KPushButton *configurePushButton = new KPushButton; 00680 configurePushButton->setIcon(KIcon("configure")); 00681 connect(configurePushButton, SIGNAL(clicked(bool)), this, SLOT(slotConfigureClicked())); 00682 00683 setBlockedEventTypes(enabledCheckBox, QList<QEvent::Type>() << QEvent::MouseButtonPress 00684 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick 00685 << QEvent::KeyPress << QEvent::KeyRelease); 00686 00687 setBlockedEventTypes(aboutPushButton, QList<QEvent::Type>() << QEvent::MouseButtonPress 00688 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick 00689 << QEvent::KeyPress << QEvent::KeyRelease); 00690 00691 setBlockedEventTypes(configurePushButton, QList<QEvent::Type>() << QEvent::MouseButtonPress 00692 << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick 00693 << QEvent::KeyPress << QEvent::KeyRelease); 00694 00695 widgetList << enabledCheckBox << configurePushButton << aboutPushButton; 00696 00697 return widgetList; 00698 } 00699 00700 void KPluginSelector::Private::PluginDelegate::updateItemWidgets(const QList<QWidget*> widgets, 00701 const QStyleOptionViewItem &option, 00702 const QPersistentModelIndex &index) const 00703 { 00704 QCheckBox *checkBox = static_cast<QCheckBox*>(widgets[0]); 00705 checkBox->resize(checkBox->sizeHint()); 00706 checkBox->move(pluginSelector_d->dependantLayoutValue(MARGIN, checkBox->sizeHint().width(), option.rect.width()), option.rect.height() / 2 - checkBox->sizeHint().height() / 2); 00707 00708 KPushButton *aboutPushButton = static_cast<KPushButton*>(widgets[2]); 00709 QSize aboutPushButtonSizeHint = aboutPushButton->sizeHint(); 00710 aboutPushButton->resize(aboutPushButtonSizeHint); 00711 aboutPushButton->move(pluginSelector_d->dependantLayoutValue(option.rect.width() - MARGIN - aboutPushButtonSizeHint.width(), aboutPushButtonSizeHint.width(), option.rect.width()), option.rect.height() / 2 - aboutPushButtonSizeHint.height() / 2); 00712 00713 KPushButton *configurePushButton = static_cast<KPushButton*>(widgets[1]); 00714 QSize configurePushButtonSizeHint = configurePushButton->sizeHint(); 00715 configurePushButton->resize(configurePushButtonSizeHint); 00716 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); 00717 00718 if (!index.isValid() || !index.internalPointer()) { 00719 checkBox->setVisible(false); 00720 aboutPushButton->setVisible(false); 00721 configurePushButton->setVisible(false); 00722 } else { 00723 checkBox->setChecked(index.model()->data(index, Qt::CheckStateRole).toBool()); 00724 checkBox->setEnabled(index.model()->data(index, IsCheckableRole).toBool()); 00725 configurePushButton->setVisible(index.model()->data(index, ServicesCountRole).toBool()); 00726 configurePushButton->setEnabled(index.model()->data(index, Qt::CheckStateRole).toBool()); 00727 } 00728 } 00729 00730 void KPluginSelector::Private::PluginDelegate::slotStateChanged(bool state) 00731 { 00732 if (!focusedIndex().isValid()) 00733 return; 00734 00735 const QModelIndex index = focusedIndex(); 00736 00737 pluginSelector_d->dependenciesWidget->clearDependencies(); 00738 00739 PluginEntry *pluginEntry = index.model()->data(index, PluginEntryRole).value<PluginEntry*>(); 00740 pluginSelector_d->updateDependencies(pluginEntry, state); 00741 00742 const_cast<QAbstractItemModel*>(index.model())->setData(index, state, Qt::CheckStateRole); 00743 } 00744 00745 void KPluginSelector::Private::PluginDelegate::emitChanged() 00746 { 00747 emit changed(true); 00748 } 00749 00750 void KPluginSelector::Private::PluginDelegate::slotAboutClicked() 00751 { 00752 const QModelIndex index = focusedIndex(); 00753 const QAbstractItemModel *model = index.model(); 00754 00755 // Try to retrieve the plugin information from the KComponentData object of the plugin. 00756 // If there is no valid information, go and fetch it from the service itself (the .desktop 00757 // file). 00758 00759 PluginEntry *entry = index.model()->data(index, PluginEntryRole).value<PluginEntry*>(); 00760 KService::Ptr entryService = entry->pluginInfo.service(); 00761 if (entryService) { 00762 KPluginLoader loader(*entryService); 00763 KPluginFactory *factory = loader.factory(); 00764 if (factory) { 00765 const KAboutData *aboutData = factory->componentData().aboutData(); 00766 if (!aboutData->programName().isEmpty()) { // Be sure the about data is not completely empty 00767 KAboutApplicationDialog aboutPlugin(aboutData, itemView()); 00768 aboutPlugin.setPlainCaption(i18nc("Used only for plugins", "About %1", aboutData->programName())); 00769 aboutPlugin.exec(); 00770 return; 00771 } 00772 } 00773 } 00774 00775 const QString name = model->data(index, NameRole).toString(); 00776 const QString comment = model->data(index, CommentRole).toString(); 00777 const QString author = model->data(index, AuthorRole).toString(); 00778 const QString email = model->data(index, EmailRole).toString(); 00779 const QString website = model->data(index, WebsiteRole).toString(); 00780 const QString version = model->data(index, VersionRole).toString(); 00781 const QString license = model->data(index, LicenseRole).toString(); 00782 00783 KAboutData aboutData(name.toUtf8(), name.toUtf8(), ki18n(name.toUtf8()), version.toUtf8(), ki18n(comment.toUtf8()), KAboutLicense::byKeyword(license).key(), ki18n(QByteArray()), ki18n(QByteArray()), website.toLatin1()); 00784 aboutData.setProgramIconName(index.model()->data(index, Qt::DecorationRole).toString()); 00785 const QStringList authors = author.split(','); 00786 const QStringList emails = email.split(','); 00787 if (authors.count() == emails.count()) { 00788 int i = 0; 00789 foreach (const QString &author, authors) { 00790 if (!author.isEmpty()) { 00791 aboutData.addAuthor(ki18n(author.toUtf8()), ki18n(QByteArray()), emails[i].toUtf8(), 0); 00792 } 00793 i++; 00794 } 00795 } 00796 KAboutApplicationDialog aboutPlugin(&aboutData, itemView()); 00797 aboutPlugin.setPlainCaption(i18nc("Used only for plugins", "About %1", aboutData.programName())); 00798 aboutPlugin.exec(); 00799 } 00800 00801 void KPluginSelector::Private::PluginDelegate::slotConfigureClicked() 00802 { 00803 const QModelIndex index = focusedIndex(); 00804 const QAbstractItemModel *model = index.model(); 00805 00806 PluginEntry *pluginEntry = model->data(index, PluginEntryRole).value<PluginEntry*>(); 00807 KPluginInfo pluginInfo = pluginEntry->pluginInfo; 00808 00809 KDialog configDialog(itemView()); 00810 configDialog.setWindowTitle(model->data(index, NameRole).toString()); 00811 // The number of KCModuleProxies in use determines whether to use a tabwidget 00812 KTabWidget *newTabWidget = 0; 00813 // Widget to use for the setting dialog's main widget, 00814 // either a KTabWidget or a KCModuleProxy 00815 QWidget * mainWidget = 0; 00816 // Widget to use as the KCModuleProxy's parent. 00817 // The first proxy is owned by the dialog itself 00818 QWidget *moduleProxyParentWidget = &configDialog; 00819 00820 foreach (const KService::Ptr &servicePtr, pluginInfo.kcmServices()) { 00821 if(!servicePtr->noDisplay()) { 00822 KCModuleInfo moduleInfo(servicePtr); 00823 KCModuleProxy *currentModuleProxy = new KCModuleProxy(moduleInfo, moduleProxyParentWidget); 00824 if (currentModuleProxy->realModule()) { 00825 moduleProxyList << currentModuleProxy; 00826 if (mainWidget && !newTabWidget) { 00827 // we already created one KCModuleProxy, so we need a tab widget. 00828 // Move the first proxy into the tab widget and ensure this and subsequent 00829 // proxies are in the tab widget 00830 newTabWidget = new KTabWidget(&configDialog); 00831 moduleProxyParentWidget = newTabWidget; 00832 mainWidget->setParent( newTabWidget ); 00833 KCModuleProxy *moduleProxy = qobject_cast<KCModuleProxy*>(mainWidget); 00834 if (moduleProxy) { 00835 newTabWidget->addTab(mainWidget, moduleProxy->moduleInfo().moduleName()); 00836 mainWidget = newTabWidget; 00837 } else { 00838 delete newTabWidget; 00839 newTabWidget = 0; 00840 moduleProxyParentWidget = &configDialog; 00841 mainWidget->setParent(0); 00842 } 00843 } 00844 00845 if (newTabWidget) { 00846 newTabWidget->addTab(currentModuleProxy, servicePtr->name()); 00847 } else { 00848 mainWidget = currentModuleProxy; 00849 } 00850 } else { 00851 delete currentModuleProxy; 00852 } 00853 } 00854 } 00855 00856 // it could happen that we had services to show, but none of them were real modules. 00857 if (moduleProxyList.count()) { 00858 configDialog.setButtons(KDialog::Ok | KDialog::Cancel | KDialog::Default); 00859 00860 QWidget *showWidget = new QWidget(&configDialog); 00861 QVBoxLayout *layout = new QVBoxLayout; 00862 showWidget->setLayout(layout); 00863 layout->addWidget(mainWidget); 00864 layout->insertSpacing(-1, KDialog::marginHint()); 00865 configDialog.setMainWidget(showWidget); 00866 00867 connect(&configDialog, SIGNAL(defaultClicked()), this, SLOT(slotDefaultClicked())); 00868 00869 if (configDialog.exec() == QDialog::Accepted) { 00870 foreach (KCModuleProxy *moduleProxy, moduleProxyList) { 00871 QStringList parentComponents = moduleProxy->moduleInfo().service()->property("X-KDE-ParentComponents").toStringList(); 00872 moduleProxy->save(); 00873 foreach (const QString &parentComponent, parentComponents) { 00874 emit configCommitted(parentComponent.toLatin1()); 00875 } 00876 } 00877 } else { 00878 foreach (KCModuleProxy *moduleProxy, moduleProxyList) { 00879 moduleProxy->load(); 00880 } 00881 } 00882 00883 qDeleteAll(moduleProxyList); 00884 moduleProxyList.clear(); 00885 } 00886 } 00887 00888 void KPluginSelector::Private::PluginDelegate::slotDefaultClicked() 00889 { 00890 foreach (KCModuleProxy *moduleProxy, moduleProxyList) { 00891 moduleProxy->defaults(); 00892 } 00893 } 00894 00895 QFont KPluginSelector::Private::PluginDelegate::titleFont(const QFont &baseFont) const 00896 { 00897 QFont retFont(baseFont); 00898 retFont.setBold(true); 00899 00900 return retFont; 00901 } 00902 00903 #include "kpluginselector_p.moc" 00904 #include "kpluginselector.moc"
KDE 4.7 API Reference