• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

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"

KUtils

Skip menu "KUtils"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal