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"