File indexing completed on 2024-12-22 05:01:13
0001 /* 0002 This file is part of KDE Kontact. 0003 0004 SPDX-FileCopyrightText: 2003 Sven Lüppken <sven@kde.org> 0005 SPDX-FileCopyrightText: 2003 Tobias König <tokoe@kde.org> 0006 SPDX-FileCopyrightText: 2003 Daniel Molkentin <molkentin@kde.org> 0007 SPDX-FileCopyrightText: 2008 Allen Winter <winter@kde.org> 0008 0009 SPDX-License-Identifier: LGPL-2.0-or-later 0010 */ 0011 0012 #include "summaryview_part.h" 0013 #include "dropwidget.h" 0014 #include <PimCommon/BroadcastStatus> 0015 using PimCommon::BroadcastStatus; 0016 0017 #include <KIdentityManagementCore/Identity> 0018 #include <KIdentityManagementCore/IdentityManager> 0019 0020 #include <KontactInterface/Core> 0021 #include <KontactInterface/Plugin> 0022 #include <KontactInterface/Summary> 0023 0024 #include <KActionCollection> 0025 #include <KCMultiDialog> 0026 #include <KConfig> 0027 #include <KConfigGroup> 0028 #include <KLocalizedString> 0029 #include <KParts/PartActivateEvent> 0030 #include <KPluginMetaData> 0031 #include <QAction> 0032 #include <QApplication> 0033 #include <QHBoxLayout> 0034 #include <QIcon> 0035 #include <QLabel> 0036 #include <QLocale> 0037 #include <QPointer> 0038 #include <QScrollArea> 0039 #include <QTimer> 0040 #include <QVBoxLayout> 0041 0042 SummaryViewPart::SummaryViewPart(KontactInterface::Core *core, const KAboutData &aboutData, QObject *parent) 0043 : KParts::Part(parent) 0044 , mCore(core) 0045 { 0046 Q_UNUSED(aboutData) 0047 setComponentName(QStringLiteral("kontactsummary"), i18n("Kontact Summary")); 0048 0049 loadLayout(); 0050 0051 initGUI(core); 0052 0053 setDate(QDate::currentDate()); 0054 connect(mCore, &KontactInterface::Core::dayChanged, this, &SummaryViewPart::setDate); 0055 0056 mConfigAction = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("&Configure Summary View..."), this); 0057 actionCollection()->addAction(QStringLiteral("summaryview_configure"), mConfigAction); 0058 connect(mConfigAction, &QAction::triggered, this, &SummaryViewPart::slotConfigure); 0059 const QString str = i18n("Configure the summary view"); 0060 mConfigAction->setStatusTip(str); 0061 mConfigAction->setToolTip(str); 0062 mConfigAction->setWhatsThis(i18nc("@info:whatsthis", 0063 "Choosing this will show a dialog where you can select which " 0064 "summaries you want to see and also allow you to configure " 0065 "the summaries to your liking.")); 0066 0067 setXMLFile(QStringLiteral("kontactsummary_part.rc")); 0068 0069 QTimer::singleShot(0, this, &SummaryViewPart::slotTextChanged); 0070 } 0071 0072 SummaryViewPart::~SummaryViewPart() 0073 { 0074 saveLayout(); 0075 } 0076 0077 void SummaryViewPart::partActivateEvent(KParts::PartActivateEvent *event) 0078 { 0079 // inform the plugins that the part has been activated so that they can 0080 // update the displayed information 0081 if (event->activated() && (event->part() == this)) { 0082 updateSummaries(); 0083 } 0084 0085 KParts::Part::partActivateEvent(event); 0086 } 0087 0088 void SummaryViewPart::updateSummaries() 0089 { 0090 QMap<QString, KontactInterface::Summary *>::ConstIterator it; 0091 QMap<QString, KontactInterface::Summary *>::ConstIterator end(mSummaries.constEnd()); 0092 for (it = mSummaries.constBegin(); it != end; ++it) { 0093 it.value()->updateSummary(false); 0094 } 0095 } 0096 0097 void SummaryViewPart::updateWidgets() 0098 { 0099 mMainWidget->setUpdatesEnabled(false); 0100 0101 delete mFrame; 0102 0103 const KIdentityManagementCore::Identity &id = KIdentityManagementCore::IdentityManager::self()->defaultIdentity(); 0104 0105 const QString currentUser = i18n("Summary for %1", id.fullName()); 0106 mUsernameLabel->setText(QStringLiteral("<b>%1</b>").arg(currentUser)); 0107 0108 mSummaries.clear(); 0109 0110 mFrame = new DropWidget(mMainWidget); 0111 connect(mFrame, &DropWidget::summaryWidgetDropped, this, &SummaryViewPart::summaryWidgetMoved); 0112 0113 mMainLayout->insertWidget(2, mFrame); 0114 0115 KConfig config(QStringLiteral("kontact_summaryrc")); 0116 KConfigGroup grp(&config, QString()); 0117 QStringList activeSummaries; 0118 if (grp.hasKey("ActiveSummaries")) { 0119 activeSummaries = grp.readEntry("ActiveSummaries", QStringList()); 0120 } else { 0121 activeSummaries << QStringLiteral("kontact_korganizerplugin"); 0122 activeSummaries << QStringLiteral("kontact_todoplugin"); 0123 activeSummaries << QStringLiteral("kontact_specialdatesplugin"); 0124 activeSummaries << QStringLiteral("kontact_kmailplugin"); 0125 activeSummaries << QStringLiteral("kontact_knotesplugin"); 0126 } 0127 // Collect all summary widgets with a summaryHeight > 0 0128 QStringList loadedSummaries; 0129 0130 QList<KontactInterface::Plugin *> plugins = mCore->pluginList(); 0131 const QList<KontactInterface::Plugin *>::ConstIterator end = plugins.constEnd(); 0132 QList<KontactInterface::Plugin *>::ConstIterator it = plugins.constBegin(); 0133 for (; it != end; ++it) { 0134 KontactInterface::Plugin *plugin = *it; 0135 const QString pluginIdentifier{plugin->identifier()}; 0136 if (!activeSummaries.contains(pluginIdentifier)) { 0137 continue; 0138 } 0139 KontactInterface::Summary *summary = plugin->createSummaryWidget(mFrame); 0140 if (summary) { 0141 if (summary->summaryHeight() > 0) { 0142 mSummaries.insert(pluginIdentifier, summary); 0143 0144 connect(summary, &KontactInterface::Summary::message, BroadcastStatus::instance(), &PimCommon::BroadcastStatus::setStatusMsg); 0145 connect(summary, &KontactInterface::Summary::summaryWidgetDropped, this, &SummaryViewPart::summaryWidgetMoved); 0146 0147 if (!mLeftColumnSummaries.contains(pluginIdentifier) && !mRightColumnSummaries.contains(pluginIdentifier)) { 0148 mLeftColumnSummaries.append(pluginIdentifier); 0149 } 0150 0151 loadedSummaries.append(pluginIdentifier); 0152 } else { 0153 summary->hide(); 0154 } 0155 } 0156 } 0157 0158 // Remove all unavailable summary widgets 0159 { 0160 QStringList::Iterator strIt; 0161 for (strIt = mLeftColumnSummaries.begin(); strIt != mLeftColumnSummaries.end(); ++strIt) { 0162 if (!loadedSummaries.contains(*strIt)) { 0163 strIt = mLeftColumnSummaries.erase(strIt); 0164 --strIt; 0165 } 0166 } 0167 for (strIt = mRightColumnSummaries.begin(); strIt != mRightColumnSummaries.end(); ++strIt) { 0168 if (!loadedSummaries.contains(*strIt)) { 0169 strIt = mRightColumnSummaries.erase(strIt); 0170 --strIt; 0171 } 0172 } 0173 } 0174 0175 // Add vertical line between the two rows of summary widgets. 0176 auto vline = new QFrame(mFrame); 0177 vline->setFrameStyle(QFrame::VLine | QFrame::Plain); 0178 0179 auto layout = new QHBoxLayout(mFrame); 0180 0181 int margin = 20; // margin width: insert margins so there is space to dnd a 0182 // summary when either column is empty. looks nicer too. 0183 0184 layout->insertSpacing(0, margin); 0185 mLeftColumn = new QVBoxLayout(); 0186 layout->addLayout(mLeftColumn); 0187 layout->addWidget(vline); 0188 mRightColumn = new QVBoxLayout(); 0189 layout->addLayout(mRightColumn); 0190 layout->insertSpacing(-1, margin); 0191 0192 QStringList::ConstIterator strIt; 0193 QStringList::ConstIterator strEnd(mLeftColumnSummaries.constEnd()); 0194 for (strIt = mLeftColumnSummaries.constBegin(); strIt != strEnd; ++strIt) { 0195 if (mSummaries.contains(*strIt)) { 0196 mLeftColumn->addWidget(mSummaries[*strIt]); 0197 } 0198 } 0199 strEnd = mRightColumnSummaries.constEnd(); 0200 for (strIt = mRightColumnSummaries.constBegin(); strIt != strEnd; ++strIt) { 0201 if (mSummaries.contains(*strIt)) { 0202 mRightColumn->addWidget(mSummaries[*strIt]); 0203 } 0204 } 0205 0206 auto lspacer = new QSpacerItem(1, 10, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); 0207 auto rspacer = new QSpacerItem(1, 10, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); 0208 mLeftColumn->addSpacerItem(lspacer); 0209 mRightColumn->addSpacerItem(rspacer); 0210 0211 mFrame->show(); 0212 0213 mMainWidget->setUpdatesEnabled(true); 0214 mMainWidget->update(); 0215 0216 mLeftColumn->addStretch(); 0217 mRightColumn->addStretch(); 0218 } 0219 0220 void SummaryViewPart::summaryWidgetMoved(QWidget *target, QObject *obj, int alignment) 0221 { 0222 QWidget *widget = qobject_cast<QWidget *>(obj); 0223 if (!widget || (target == widget)) { 0224 return; 0225 } 0226 0227 if (target == mFrame) { 0228 if (mLeftColumn->indexOf(widget) == -1 && mRightColumn->indexOf(widget) == -1) { 0229 return; 0230 } 0231 } else { 0232 if ((mLeftColumn->indexOf(target) == -1 && mRightColumn->indexOf(target) == -1) 0233 || (mLeftColumn->indexOf(widget) == -1 && mRightColumn->indexOf(widget) == -1)) { 0234 return; 0235 } 0236 } 0237 0238 if (!QApplication::isRightToLeft()) { 0239 drawLtoR(target, widget, alignment); 0240 } else { 0241 drawRtoL(target, widget, alignment); 0242 } 0243 } 0244 0245 void SummaryViewPart::drawLtoR(QWidget *target, QWidget *widget, int alignment) 0246 { 0247 if (mLeftColumn->indexOf(widget) != -1) { 0248 mLeftColumn->removeWidget(widget); 0249 mLeftColumnSummaries.removeAll(widgetName(widget)); 0250 } else if (mRightColumn->indexOf(widget) != -1) { 0251 mRightColumn->removeWidget(widget); 0252 mRightColumnSummaries.removeAll(widgetName(widget)); 0253 } 0254 0255 if (target == mFrame) { 0256 int pos = 0; 0257 0258 if (alignment & Qt::AlignTop) { 0259 pos = 0; 0260 } 0261 0262 if (alignment & Qt::AlignLeft) { 0263 if (alignment & Qt::AlignBottom) { 0264 pos = mLeftColumnSummaries.count(); 0265 } 0266 0267 mLeftColumn->insertWidget(pos, widget); 0268 mLeftColumnSummaries.insert(pos, widgetName(widget)); 0269 } else { 0270 if (alignment & Qt::AlignBottom) { 0271 pos = mRightColumnSummaries.count(); 0272 } 0273 0274 mRightColumn->insertWidget(pos, widget); 0275 mRightColumnSummaries.insert(pos, widgetName(widget)); 0276 } 0277 0278 mFrame->updateGeometry(); 0279 return; 0280 } 0281 0282 int targetPos = mLeftColumn->indexOf(target); 0283 if (targetPos != -1) { 0284 if (alignment == Qt::AlignBottom) { 0285 targetPos++; 0286 } 0287 0288 mLeftColumn->insertWidget(targetPos, widget); 0289 mLeftColumnSummaries.insert(targetPos, widgetName(widget)); 0290 } else { 0291 targetPos = mRightColumn->indexOf(target); 0292 0293 if (alignment == Qt::AlignBottom) { 0294 targetPos++; 0295 } 0296 0297 mRightColumn->insertWidget(targetPos, widget); 0298 mRightColumnSummaries.insert(targetPos, widgetName(widget)); 0299 } 0300 mFrame->updateGeometry(); 0301 } 0302 0303 void SummaryViewPart::drawRtoL(QWidget *target, QWidget *widget, int alignment) 0304 { 0305 if (mRightColumn->indexOf(widget) != -1) { 0306 mRightColumn->removeWidget(widget); 0307 mRightColumnSummaries.removeAll(widgetName(widget)); 0308 } else if (mLeftColumn->indexOf(widget) != -1) { 0309 mLeftColumn->removeWidget(widget); 0310 mLeftColumnSummaries.removeAll(widgetName(widget)); 0311 } 0312 0313 if (target == mFrame) { 0314 int pos = 0; 0315 0316 if (alignment & Qt::AlignTop) { 0317 pos = 0; 0318 } 0319 0320 if (alignment & Qt::AlignLeft) { 0321 if (alignment & Qt::AlignBottom) { 0322 pos = mRightColumnSummaries.count(); 0323 } 0324 0325 mRightColumn->insertWidget(pos, widget); 0326 mRightColumnSummaries.insert(pos, widgetName(widget)); 0327 } else { 0328 if (alignment & Qt::AlignBottom) { 0329 pos = mLeftColumnSummaries.count(); 0330 } 0331 0332 mLeftColumn->insertWidget(pos, widget); 0333 mLeftColumnSummaries.insert(pos, widgetName(widget)); 0334 } 0335 0336 mFrame->updateGeometry(); 0337 return; 0338 } 0339 0340 int targetPos = mRightColumn->indexOf(target); 0341 if (targetPos != -1) { 0342 if (alignment == Qt::AlignBottom) { 0343 targetPos++; 0344 } 0345 0346 mRightColumn->insertWidget(targetPos, widget); 0347 mRightColumnSummaries.insert(targetPos, widgetName(widget)); 0348 } else { 0349 targetPos = mLeftColumn->indexOf(target); 0350 0351 if (alignment == Qt::AlignBottom) { 0352 targetPos++; 0353 } 0354 0355 mLeftColumn->insertWidget(targetPos, widget); 0356 mLeftColumnSummaries.insert(targetPos, widgetName(widget)); 0357 } 0358 mFrame->updateGeometry(); 0359 } 0360 0361 void SummaryViewPart::slotTextChanged() 0362 { 0363 Q_EMIT textChanged(i18n("What's next?")); 0364 } 0365 0366 void SummaryViewPart::slotAdjustPalette() 0367 { 0368 if (!QApplication::isRightToLeft()) { 0369 mMainWidget->setStyleSheet( 0370 QStringLiteral("#mMainWidget { " 0371 " background: palette(base);" 0372 " color: palette(text);" 0373 " background-image: url(:/summaryview/kontact_bg.png);" 0374 " background-position: bottom right;" 0375 " background-repeat: no-repeat; }" 0376 "QLabel { " 0377 " color: palette(text); }" 0378 "KUrlLabel { " 0379 " color: palette(link); }")); 0380 } else { 0381 mMainWidget->setStyleSheet( 0382 QStringLiteral("#mMainWidget { " 0383 " background: palette(base);" 0384 " color: palette(text);" 0385 " background-image: url(:/summaryview/kontact_bg.png);" 0386 " background-position: bottom left;" 0387 " background-repeat: no-repeat; }" 0388 "QLabel { " 0389 " color: palette(text); }" 0390 "KUrlLabel { " 0391 " color: palette(link); }")); 0392 } 0393 } 0394 0395 void SummaryViewPart::setDate(QDate newDate) 0396 { 0397 const QString date = QStringLiteral("<b>%1</b>").arg(QLocale().toString(newDate)); 0398 mDateLabel->setText(date); 0399 } 0400 0401 void SummaryViewPart::slotConfigure() 0402 { 0403 QPointer<KCMultiDialog> dlg = new KCMultiDialog(mMainWidget); 0404 dlg->setObjectName(QLatin1StringView("ConfigDialog")); 0405 dlg->setModal(true); 0406 connect(dlg.data(), &KCMultiDialog::configCommitted, this, &SummaryViewPart::updateWidgets); 0407 const auto metaDataList = KPluginMetaData::findPlugins(QStringLiteral("pim6/kcms/summary/")); 0408 for (const auto &metaData : metaDataList) { 0409 dlg->addModule(metaData); 0410 } 0411 0412 dlg->exec(); 0413 delete dlg; 0414 } 0415 0416 void SummaryViewPart::initGUI(KontactInterface::Core *core) 0417 { 0418 auto sa = new QScrollArea(core); 0419 0420 sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0421 sa->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); 0422 sa->setWidgetResizable(true); 0423 0424 mMainWidget = new QFrame; 0425 mMainWidget->setObjectName(QLatin1StringView("mMainWidget")); 0426 sa->setWidget(mMainWidget); 0427 mMainWidget->setFocusPolicy(Qt::StrongFocus); 0428 setWidget(sa); 0429 0430 slotAdjustPalette(); 0431 0432 mMainLayout = new QVBoxLayout(mMainWidget); 0433 0434 auto hbl = new QHBoxLayout(); 0435 mMainLayout->addItem(hbl); 0436 mUsernameLabel = new QLabel(mMainWidget); 0437 mDateLabel = new QLabel(mMainWidget); 0438 if (!QApplication::isRightToLeft()) { 0439 mUsernameLabel->setAlignment(Qt::AlignLeft); 0440 hbl->addWidget(mUsernameLabel); 0441 mDateLabel->setAlignment(Qt::AlignRight); 0442 hbl->addWidget(mDateLabel); 0443 } else { 0444 mDateLabel->setAlignment(Qt::AlignRight); 0445 hbl->addWidget(mDateLabel); 0446 mUsernameLabel->setAlignment(Qt::AlignLeft); 0447 hbl->addWidget(mUsernameLabel); 0448 } 0449 0450 auto hline = new QFrame(mMainWidget); 0451 hline->setFrameStyle(QFrame::HLine | QFrame::Plain); 0452 mMainLayout->insertWidget(1, hline); 0453 0454 mFrame = new DropWidget(mMainWidget); 0455 mMainLayout->insertWidget(2, mFrame); 0456 0457 connect(mFrame, &DropWidget::summaryWidgetDropped, this, &SummaryViewPart::summaryWidgetMoved); 0458 0459 updateWidgets(); 0460 } 0461 0462 void SummaryViewPart::loadLayout() 0463 { 0464 KConfig config(QStringLiteral("kontact_summaryrc")); 0465 KConfigGroup grp(&config, QString()); 0466 0467 if (grp.hasKey("LeftColumnSummaries")) { 0468 mLeftColumnSummaries = grp.readEntry("LeftColumnSummaries", QStringList()); 0469 } else { 0470 mLeftColumnSummaries << QStringLiteral("kontact_korganizerplugin"); 0471 mLeftColumnSummaries << QStringLiteral("kontact_todoplugin"); 0472 mLeftColumnSummaries << QStringLiteral("kontact_specialdatesplugin"); 0473 } 0474 0475 if (grp.hasKey("RightColumnSummaries")) { 0476 mRightColumnSummaries = grp.readEntry("RightColumnSummaries", QStringList()); 0477 } else { 0478 mRightColumnSummaries << QStringLiteral("kontact_kmailplugin"); 0479 mRightColumnSummaries << QStringLiteral("kontact_knotesplugin"); 0480 } 0481 } 0482 0483 void SummaryViewPart::saveLayout() 0484 { 0485 KConfig config(QStringLiteral("kontact_summaryrc")); 0486 KConfigGroup grp(&config, QString()); 0487 0488 grp.writeEntry("LeftColumnSummaries", mLeftColumnSummaries); 0489 grp.writeEntry("RightColumnSummaries", mRightColumnSummaries); 0490 0491 config.sync(); 0492 } 0493 0494 QString SummaryViewPart::widgetName(QWidget *widget) const 0495 { 0496 QMap<QString, KontactInterface::Summary *>::ConstIterator it; 0497 const QMap<QString, KontactInterface::Summary *>::ConstIterator end(mSummaries.constEnd()); 0498 for (it = mSummaries.constBegin(); it != end; ++it) { 0499 if (it.value() == widget) { 0500 return it.key(); 0501 } 0502 } 0503 0504 return {}; 0505 } 0506 0507 bool SummaryViewPart::event(QEvent *e) 0508 { 0509 if (e->type() == QEvent::ApplicationPaletteChange) { 0510 slotAdjustPalette(); 0511 } 0512 return KParts::Part::event(e); 0513 } 0514 0515 #include "moc_summaryview_part.cpp"