File indexing completed on 2024-12-15 04:54:38

0001 /******************************************************************************
0002  *
0003  *  SPDX-FileCopyrightText: 2008 Szymon Tomasz Stefanek <pragma@kvirc.net>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  *
0007  *******************************************************************************/
0008 
0009 #include "core/manager.h"
0010 
0011 #include "core/aggregation.h"
0012 #include "core/storagemodelbase.h"
0013 #include "core/theme.h"
0014 #include "core/view.h"
0015 #include "core/widgetbase.h"
0016 #include "messagelistsettings.h"
0017 
0018 #include "MessageCore/MessageCoreSettings"
0019 
0020 #include "messagelistutil_p.h"
0021 
0022 #include <KMime/DateFormatter> // kdepimlibs
0023 
0024 #include "messagelist_debug.h"
0025 #include <KConfig>
0026 #include <KLocalizedString>
0027 
0028 using namespace MessageList::Core;
0029 
0030 Manager *Manager::mInstance = nullptr;
0031 
0032 Manager::Manager()
0033     : QObject()
0034     , mDateFormatter(new KMime::DateFormatter())
0035     , mCachedLocalizedUnknownText(i18nc("Unknown date", "Unknown"))
0036 {
0037     mInstance = this;
0038 
0039     loadConfiguration();
0040     connect(MessageListSettings::self(), &MessageListSettings::configChanged, this, &Manager::reloadGlobalConfiguration);
0041     connect(MessageCore::MessageCoreSettings::self(), &MessageCore::MessageCoreSettings::configChanged, this, &Manager::reloadGlobalConfiguration);
0042 }
0043 
0044 Manager::~Manager()
0045 {
0046     disconnect(MessageListSettings::self(), &MessageListSettings::configChanged, this, &Manager::reloadGlobalConfiguration);
0047     disconnect(MessageCore::MessageCoreSettings::self(), &MessageCore::MessageCoreSettings::configChanged, this, &Manager::reloadGlobalConfiguration);
0048 
0049     saveConfiguration();
0050     removeAllAggregations();
0051     removeAllThemes();
0052 
0053     delete mDateFormatter;
0054 
0055     mInstance = nullptr;
0056 }
0057 
0058 void Manager::registerWidget(Widget *pWidget)
0059 {
0060     if (!mInstance) {
0061         mInstance = new Manager();
0062     }
0063 
0064     mInstance->mWidgetList.append(pWidget);
0065 }
0066 
0067 void Manager::unregisterWidget(Widget *pWidget)
0068 {
0069     if (!mInstance) {
0070         qCWarning(MESSAGELIST_LOG) << ("ERROR: MessageList::Manager::unregisterWidget() called when Manager::mInstance is null");
0071         return;
0072     }
0073 
0074     mInstance->mWidgetList.removeAll(pWidget);
0075 
0076     if (mInstance->mWidgetList.isEmpty()) {
0077         delete mInstance;
0078         mInstance = nullptr;
0079     }
0080 }
0081 
0082 const Aggregation *Manager::aggregation(const QString &id)
0083 {
0084     Aggregation *opt = mAggregations.value(id);
0085     if (opt) {
0086         return opt;
0087     }
0088 
0089     return defaultAggregation();
0090 }
0091 
0092 const Aggregation *Manager::defaultAggregation()
0093 {
0094     KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelAggregationsGroup());
0095 
0096     const QString aggregationId = conf.readEntry(QStringLiteral("DefaultSet"), "");
0097 
0098     Aggregation *opt = nullptr;
0099 
0100     if (!aggregationId.isEmpty()) {
0101         opt = mAggregations.value(aggregationId);
0102     }
0103 
0104     if (opt) {
0105         return opt;
0106     }
0107 
0108     // try just the first one
0109     QMap<QString, Aggregation *>::ConstIterator it = mAggregations.constBegin();
0110     if (it != mAggregations.constEnd()) {
0111         return *it;
0112     }
0113 
0114     // aargh
0115     createDefaultAggregations();
0116 
0117     return *(mAggregations.constBegin());
0118 }
0119 
0120 void Manager::saveAggregationForStorageModel(const Akonadi::Collection &col, const QString &id, bool storageUsesPrivateAggregation)
0121 {
0122     if (!col.isValid()) {
0123         return;
0124     }
0125     saveAggregationForStorageModel(QString::number(col.id()), id, storageUsesPrivateAggregation);
0126 }
0127 
0128 void Manager::saveAggregationForStorageModel(const StorageModel *storageModel, const QString &id, bool storageUsesPrivateAggregation)
0129 {
0130     saveAggregationForStorageModel(storageModel->id(), id, storageUsesPrivateAggregation);
0131 }
0132 
0133 void Manager::saveAggregationForStorageModel(const QString &modelId, const QString &id, bool storageUsesPrivateAggregation)
0134 {
0135     KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelAggregationsGroup());
0136 
0137     if (storageUsesPrivateAggregation) {
0138         conf.writeEntry(MessageList::Util::setForStorageModelConfigName().arg(modelId), id);
0139     } else {
0140         conf.deleteEntry(MessageList::Util::setForStorageModelConfigName().arg(modelId));
0141     }
0142 
0143     if (!storageUsesPrivateAggregation) {
0144         conf.writeEntry(QStringLiteral("DefaultSet"), id);
0145     }
0146     conf.sync();
0147 }
0148 
0149 const Aggregation *Manager::aggregationForStorageModel(const Akonadi::Collection &col, bool *storageUsesPrivateAggregation)
0150 {
0151     Q_ASSERT(storageUsesPrivateAggregation);
0152 
0153     *storageUsesPrivateAggregation = false; // this is by default
0154 
0155     if (!col.isValid()) {
0156         return defaultAggregation();
0157     }
0158     return Manager::aggregationForStorageModel(QString::number(col.id()), storageUsesPrivateAggregation);
0159 }
0160 
0161 const Aggregation *Manager::aggregationForStorageModel(const StorageModel *storageModel, bool *storageUsesPrivateAggregation)
0162 {
0163     Q_ASSERT(storageUsesPrivateAggregation);
0164 
0165     *storageUsesPrivateAggregation = false; // this is by default
0166 
0167     if (!storageModel) {
0168         return defaultAggregation();
0169     }
0170     return Manager::aggregationForStorageModel(storageModel->id(), storageUsesPrivateAggregation);
0171 }
0172 
0173 const Aggregation *Manager::aggregationForStorageModel(const QString &storageId, bool *storageUsesPrivateAggregation)
0174 {
0175     KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelAggregationsGroup());
0176 
0177     const QString aggregationId = conf.readEntry(MessageList::Util::setForStorageModelConfigName().arg(storageId), "");
0178 
0179     Aggregation *opt = nullptr;
0180 
0181     if (!aggregationId.isEmpty()) {
0182         // a private aggregation was stored
0183         opt = mAggregations.value(aggregationId);
0184         *storageUsesPrivateAggregation = (opt != nullptr);
0185     }
0186 
0187     if (opt) {
0188         return opt;
0189     }
0190 
0191     // FIXME: If the storageModel is a mailing list, maybe suggest a mailing-list like preset...
0192     //        We could even try to guess if the storageModel is a mailing list
0193 
0194     return defaultAggregation();
0195 }
0196 
0197 void Manager::addAggregation(Aggregation *set)
0198 {
0199     Aggregation *old = mAggregations.value(set->id());
0200     delete old;
0201     mAggregations.insert(set->id(), set);
0202 }
0203 
0204 void Manager::createDefaultAggregations()
0205 {
0206     addAggregation(new Aggregation(i18n("Current Activity, Threaded"),
0207                                    i18n("This view uses smart date range groups. "
0208                                         "Messages are threaded. "
0209                                         "So for example, in \"Today\" you will find all the messages arrived today "
0210                                         "and all the threads that have been active today."),
0211                                    Aggregation::GroupByDateRange,
0212                                    Aggregation::ExpandRecentGroups,
0213                                    Aggregation::PerfectReferencesAndSubject,
0214                                    Aggregation::MostRecentMessage,
0215                                    Aggregation::ExpandThreadsWithUnreadOrImportantMessages,
0216                                    Aggregation::FavorInteractivity,
0217                                    true));
0218 
0219     addAggregation(new Aggregation(i18n("Current Activity, Flat"),
0220                                    i18n("This view uses smart date range groups. "
0221                                         "Messages are not threaded. "
0222                                         "So for example, in \"Today\" you will simply find all the messages arrived today."),
0223                                    Aggregation::GroupByDateRange,
0224                                    Aggregation::ExpandRecentGroups,
0225                                    Aggregation::NoThreading,
0226                                    Aggregation::MostRecentMessage,
0227                                    Aggregation::NeverExpandThreads,
0228                                    Aggregation::FavorInteractivity,
0229                                    true));
0230 
0231     addAggregation(new Aggregation(i18n("Activity by Date, Threaded"),
0232                                    i18n("This view uses day-by-day groups. "
0233                                         "Messages are threaded. "
0234                                         "So for example, in \"Today\" you will find all the messages arrived today "
0235                                         "and all the threads that have been active today."),
0236                                    Aggregation::GroupByDate,
0237                                    Aggregation::ExpandRecentGroups,
0238                                    Aggregation::PerfectReferencesAndSubject,
0239                                    Aggregation::MostRecentMessage,
0240                                    Aggregation::ExpandThreadsWithUnreadOrImportantMessages,
0241                                    Aggregation::FavorInteractivity,
0242                                    true));
0243 
0244     addAggregation(new Aggregation(i18n("Activity by Date, Flat"),
0245                                    i18n("This view uses day-by-day groups. "
0246                                         "Messages are not threaded. "
0247                                         "So for example, in \"Today\" you will simply find all the messages arrived today."),
0248                                    Aggregation::GroupByDate,
0249                                    Aggregation::ExpandRecentGroups,
0250                                    Aggregation::NoThreading,
0251                                    Aggregation::MostRecentMessage,
0252                                    Aggregation::NeverExpandThreads,
0253                                    Aggregation::FavorInteractivity,
0254                                    true));
0255 
0256     addAggregation(new Aggregation(i18n("Standard Mailing List"),
0257                                    i18n("This is a plain and old mailing list view: no groups and heavy threading."),
0258                                    Aggregation::NoGrouping,
0259                                    Aggregation::NeverExpandGroups,
0260                                    Aggregation::PerfectReferencesAndSubject,
0261                                    Aggregation::TopmostMessage,
0262                                    Aggregation::ExpandThreadsWithUnreadOrImportantMessages,
0263                                    Aggregation::FavorInteractivity,
0264                                    true));
0265 
0266     addAggregation(new Aggregation(i18n("Flat Date View"),
0267                                    i18n("This is a plain and old list of messages sorted by date: no groups and no threading."),
0268                                    Aggregation::NoGrouping,
0269                                    Aggregation::NeverExpandGroups,
0270                                    Aggregation::NoThreading,
0271                                    Aggregation::TopmostMessage,
0272                                    Aggregation::NeverExpandThreads,
0273                                    Aggregation::FavorInteractivity,
0274                                    true
0275 
0276                                    ));
0277 
0278     addAggregation(new Aggregation(i18n("Senders/Receivers, Flat"),
0279                                    i18n("This view groups the messages by senders or receivers (depending on the folder "
0280                                         "type). "
0281                                         "Messages are not threaded."),
0282                                    Aggregation::GroupBySenderOrReceiver,
0283                                    Aggregation::NeverExpandGroups,
0284                                    Aggregation::NoThreading,
0285                                    Aggregation::TopmostMessage,
0286                                    Aggregation::NeverExpandThreads,
0287                                    Aggregation::FavorSpeed,
0288                                    true));
0289 
0290     addAggregation(new Aggregation(i18n("Thread Starters"),
0291                                    i18n("This view groups the messages in threads and then groups the threads by the starting user."),
0292                                    Aggregation::GroupBySenderOrReceiver,
0293                                    Aggregation::NeverExpandGroups,
0294                                    Aggregation::PerfectReferencesAndSubject,
0295                                    Aggregation::TopmostMessage,
0296                                    Aggregation::NeverExpandThreads,
0297                                    Aggregation::FavorSpeed,
0298                                    true));
0299 
0300     /*
0301     FIX THIS
0302     addAggregation(
0303       new Aggregation(
0304           i18n( "Recent Thread Starters" ),
0305           i18n( "This view groups the messages in threads and then groups the threads by the starting user. " \
0306                 "Groups are sorted by the date of the first thread start. "
0307             ),
0308           Aggregation::GroupBySenderOrReceiver,
0309           Aggregation::SortGroupsByDateTimeOfMostRecent,
0310           Aggregation::Descending,
0311           Aggregation::PerfectReferencesAndSubject,
0312           Aggregation::TopmostMessage,
0313           Aggregation::SortMessagesByDateTime,
0314           Aggregation::Descending
0315         )
0316     );
0317     */
0318 }
0319 
0320 void Manager::removeAllAggregations()
0321 {
0322     QMap<QString, Aggregation *>::ConstIterator end(mAggregations.constEnd());
0323     for (QMap<QString, Aggregation *>::ConstIterator it = mAggregations.constBegin(); it != end; ++it) {
0324         delete (*it);
0325     }
0326 
0327     mAggregations.clear();
0328 }
0329 
0330 void Manager::aggregationsConfigurationCompleted()
0331 {
0332     if (mAggregations.isEmpty()) {
0333         createDefaultAggregations(); // panic
0334     }
0335 
0336     saveConfiguration(); // just to be sure :)
0337 
0338     // notify all the widgets that they should reload the option set combos
0339     Q_EMIT aggregationsChanged();
0340 }
0341 
0342 const SortOrder Manager::sortOrderForStorageModel(const StorageModel *storageModel, bool *storageUsesPrivateSortOrder)
0343 {
0344     Q_ASSERT(storageUsesPrivateSortOrder);
0345 
0346     *storageUsesPrivateSortOrder = false; // this is by default
0347 
0348     if (!storageModel) {
0349         return SortOrder();
0350     }
0351 
0352     KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelSortOrderGroup());
0353     SortOrder ret;
0354     ret.readConfig(conf, storageModel->id(), storageUsesPrivateSortOrder);
0355     return ret;
0356 }
0357 
0358 void Manager::saveSortOrderForStorageModel(const StorageModel *storageModel, SortOrder order, bool storageUsesPrivateSortOrder)
0359 {
0360     KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelSortOrderGroup());
0361     order.writeConfig(conf, storageModel->id(), storageUsesPrivateSortOrder);
0362 }
0363 
0364 const Theme *Manager::theme(const QString &id)
0365 {
0366     Theme *opt = mThemes.value(id);
0367     if (opt) {
0368         return opt;
0369     }
0370 
0371     return defaultTheme();
0372 }
0373 
0374 const Theme *Manager::defaultTheme()
0375 {
0376     KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelThemesGroup());
0377 
0378     const QString themeId = conf.readEntry(QStringLiteral("DefaultSet"), "");
0379 
0380     Theme *opt = nullptr;
0381 
0382     if (!themeId.isEmpty()) {
0383         opt = mThemes.value(themeId);
0384     }
0385 
0386     if (opt) {
0387         return opt;
0388     }
0389 
0390     // try just the first one
0391     QMap<QString, Theme *>::ConstIterator it = mThemes.constBegin();
0392     if (it != mThemes.constEnd()) {
0393         return *it;
0394     }
0395 
0396     // aargh
0397     createDefaultThemes();
0398 
0399     it = mThemes.constBegin();
0400 
0401     Q_ASSERT(it != mThemes.constEnd());
0402 
0403     return *it;
0404 }
0405 
0406 void Manager::saveThemeForStorageModel(int index, const QString &id, bool storageUsesPrivateTheme)
0407 {
0408     saveThemeForStorageModel(QString::number(index), id, storageUsesPrivateTheme);
0409 }
0410 
0411 void Manager::saveThemeForStorageModel(const StorageModel *storageModel, const QString &id, bool storageUsesPrivateTheme)
0412 {
0413     saveThemeForStorageModel(storageModel->id(), id, storageUsesPrivateTheme);
0414 }
0415 
0416 void Manager::saveThemeForStorageModel(const QString &storageModelIndex, const QString &id, bool storageUsesPrivateTheme)
0417 {
0418     KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelThemesGroup());
0419 
0420     if (storageUsesPrivateTheme) {
0421         conf.writeEntry(MessageList::Util::setForStorageModelConfigName().arg(storageModelIndex), id);
0422     } else {
0423         conf.deleteEntry(MessageList::Util::setForStorageModelConfigName().arg(storageModelIndex));
0424     }
0425 
0426     if (!storageUsesPrivateTheme) {
0427         conf.writeEntry(QStringLiteral("DefaultSet"), id);
0428     }
0429     conf.sync();
0430 }
0431 
0432 const Theme *Manager::themeForStorageModel(const Akonadi::Collection &col, bool *storageUsesPrivateTheme)
0433 {
0434     Q_ASSERT(storageUsesPrivateTheme);
0435 
0436     *storageUsesPrivateTheme = false; // this is by default
0437 
0438     if (!col.isValid()) {
0439         return defaultTheme();
0440     }
0441     return Manager::themeForStorageModel(QString::number(col.id()), storageUsesPrivateTheme);
0442 }
0443 
0444 const Theme *Manager::themeForStorageModel(const StorageModel *storageModel, bool *storageUsesPrivateTheme)
0445 {
0446     Q_ASSERT(storageUsesPrivateTheme);
0447 
0448     *storageUsesPrivateTheme = false; // this is by default
0449 
0450     if (!storageModel) {
0451         return defaultTheme();
0452     }
0453     return Manager::themeForStorageModel(storageModel->id(), storageUsesPrivateTheme);
0454 }
0455 
0456 const Theme *Manager::themeForStorageModel(const QString &id, bool *storageUsesPrivateTheme)
0457 {
0458     KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelThemesGroup());
0459     const QString themeId = conf.readEntry(MessageList::Util::setForStorageModelConfigName().arg(id), "");
0460 
0461     Theme *opt = nullptr;
0462 
0463     if (!themeId.isEmpty()) {
0464         // a private theme was stored
0465         opt = mThemes.value(themeId);
0466         *storageUsesPrivateTheme = (opt != nullptr);
0467     }
0468 
0469     if (opt) {
0470         return opt;
0471     }
0472 
0473     // FIXME: If the storageModel is a mailing list, maybe suggest a mailing-list like preset...
0474     //        We could even try to guess if the storageModel is a mailing list
0475 
0476     // FIXME: Prefer right-to-left themes when application layout is RTL.
0477 
0478     return defaultTheme();
0479 }
0480 
0481 void Manager::addTheme(Theme *set)
0482 {
0483     Theme *old = mThemes.value(set->id());
0484     delete old;
0485     mThemes.insert(set->id(), set);
0486 }
0487 
0488 static Theme::Column *add_theme_simple_text_column(Theme *s,
0489                                                    const QString &name,
0490                                                    Theme::ContentItem::Type type,
0491                                                    bool visibleByDefault,
0492                                                    SortOrder::MessageSorting messageSorting,
0493                                                    bool alignRight,
0494                                                    bool addGroupHeaderItem)
0495 {
0496     auto c = new Theme::Column();
0497     c->setLabel(name);
0498     c->setVisibleByDefault(visibleByDefault);
0499     c->setMessageSorting(messageSorting);
0500 
0501     auto r = new Theme::Row();
0502 
0503     auto i = new Theme::ContentItem(type);
0504 
0505     if (alignRight) {
0506         r->addRightItem(i);
0507     } else {
0508         r->addLeftItem(i);
0509     }
0510 
0511     c->addMessageRow(r);
0512 
0513     if (addGroupHeaderItem) {
0514         auto row = new Theme::Row();
0515 
0516         auto iRow = new Theme::ContentItem(type);
0517 
0518         if (alignRight) {
0519             row->addRightItem(iRow);
0520         } else {
0521             row->addLeftItem(iRow);
0522         }
0523 
0524         c->addGroupHeaderRow(row);
0525     }
0526 
0527     s->addColumn(c);
0528 
0529     return c;
0530 }
0531 
0532 static Theme::Column *add_theme_simple_icon_column(Theme *s,
0533                                                    const QString &name,
0534                                                    const QString &pixmapName,
0535                                                    Theme::ContentItem::Type type,
0536                                                    bool visibleByDefault,
0537                                                    SortOrder::MessageSorting messageSorting)
0538 {
0539     auto c = new Theme::Column();
0540     c->setLabel(name);
0541     c->setPixmapName(pixmapName);
0542     c->setVisibleByDefault(visibleByDefault);
0543     c->setMessageSorting(messageSorting);
0544 
0545     auto r = new Theme::Row();
0546 
0547     auto i = new Theme::ContentItem(type);
0548     i->setSoftenByBlendingWhenDisabled(true);
0549 
0550     r->addLeftItem(i);
0551 
0552     c->addMessageRow(r);
0553 
0554     s->addColumn(c);
0555 
0556     return c;
0557 }
0558 
0559 void Manager::createDefaultThemes()
0560 {
0561     Theme *s;
0562     Theme::Column *c;
0563     Theme::Row *r;
0564     Theme::ContentItem *i;
0565 
0566     // The "Classic" backward compatible theme
0567 
0568     s = new Theme(i18nc("Default theme name", "Classic"), i18n("A simple, backward compatible, single row theme"), true /*readOnly*/
0569     );
0570 
0571     c = new Theme::Column();
0572     c->setLabel(i18nc("@title:column Subject of messages", "Subject"));
0573     c->setMessageSorting(SortOrder::SortMessagesBySubject);
0574 
0575     r = new Theme::Row();
0576     i = new Theme::ContentItem(Theme::ContentItem::ExpandedStateIcon);
0577     r->addLeftItem(i);
0578     i = new Theme::ContentItem(Theme::ContentItem::GroupHeaderLabel);
0579     i->setBold(true);
0580     r->addLeftItem(i);
0581     c->addGroupHeaderRow(r);
0582 
0583     r = new Theme::Row();
0584     i = new Theme::ContentItem(Theme::ContentItem::CombinedReadRepliedStateIcon);
0585     r->addLeftItem(i);
0586     i = new Theme::ContentItem(Theme::ContentItem::AttachmentStateIcon);
0587     i->setHideWhenDisabled(true);
0588     r->addLeftItem(i);
0589     i = new Theme::ContentItem(Theme::ContentItem::AnnotationIcon);
0590     i->setHideWhenDisabled(true);
0591     r->addLeftItem(i);
0592     i = new Theme::ContentItem(Theme::ContentItem::InvitationIcon);
0593     i->setHideWhenDisabled(true);
0594     r->addLeftItem(i);
0595     i = new Theme::ContentItem(Theme::ContentItem::SignatureStateIcon);
0596     i->setHideWhenDisabled(true);
0597     r->addLeftItem(i);
0598     i = new Theme::ContentItem(Theme::ContentItem::EncryptionStateIcon);
0599     i->setHideWhenDisabled(true);
0600     r->addLeftItem(i);
0601     i = new Theme::ContentItem(Theme::ContentItem::Subject);
0602     r->addLeftItem(i);
0603     c->addMessageRow(r);
0604 
0605     s->addColumn(c);
0606 
0607     c = add_theme_simple_text_column(s,
0608                                      i18n("Sender/Receiver"),
0609                                      Theme::ContentItem::SenderOrReceiver,
0610                                      true,
0611                                      SortOrder::SortMessagesBySenderOrReceiver,
0612                                      false,
0613                                      false);
0614     c->setIsSenderOrReceiver(true);
0615     add_theme_simple_text_column(s, i18nc("Sender of a message", "Sender"), Theme::ContentItem::Sender, false, SortOrder::SortMessagesBySender, false, false);
0616     add_theme_simple_text_column(s,
0617                                  i18nc("Receiver of a message", "Receiver"),
0618                                  Theme::ContentItem::Receiver,
0619                                  false,
0620                                  SortOrder::SortMessagesByReceiver,
0621                                  false,
0622                                  false);
0623     add_theme_simple_text_column(s, i18nc("Date of a message", "Date"), Theme::ContentItem::Date, true, SortOrder::SortMessagesByDateTime, false, false);
0624     add_theme_simple_text_column(s,
0625                                  i18n("Most Recent Date"),
0626                                  Theme::ContentItem::MostRecentDate,
0627                                  false,
0628                                  SortOrder::SortMessagesByDateTimeOfMostRecent,
0629                                  false,
0630                                  true);
0631     add_theme_simple_text_column(s, i18nc("Size of a message", "Size"), Theme::ContentItem::Size, false, SortOrder::SortMessagesBySize, false, false);
0632     add_theme_simple_icon_column(s,
0633                                  i18nc("Attachment indication", "Attachment"),
0634                                  QStringLiteral("mail-attachment"),
0635                                  Theme::ContentItem::AttachmentStateIcon,
0636                                  false,
0637                                  SortOrder::SortMessagesByAttachmentStatus);
0638     add_theme_simple_icon_column(s,
0639                                  i18n("Read/Unread"),
0640                                  QStringLiteral("mail-mark-unread-new"),
0641                                  Theme::ContentItem::ReadStateIcon,
0642                                  false,
0643                                  SortOrder::SortMessagesByUnreadStatus);
0644     add_theme_simple_icon_column(s, i18n("Replied"), QStringLiteral("mail-replied"), Theme::ContentItem::RepliedStateIcon, false, SortOrder::NoMessageSorting);
0645     add_theme_simple_icon_column(s,
0646                                  i18nc("Message importance indication", "Important"),
0647                                  QStringLiteral("mail-mark-important"),
0648                                  Theme::ContentItem::ImportantStateIcon,
0649                                  false,
0650                                  SortOrder::SortMessagesByImportantStatus);
0651     add_theme_simple_icon_column(s,
0652                                  i18n("Action Item"),
0653                                  QStringLiteral("mail-task"),
0654                                  Theme::ContentItem::ActionItemStateIcon,
0655                                  false,
0656                                  SortOrder::SortMessagesByActionItemStatus);
0657     add_theme_simple_icon_column(s,
0658                                  i18n("Spam/Ham"),
0659                                  QStringLiteral("mail-mark-junk"),
0660                                  Theme::ContentItem::SpamHamStateIcon,
0661                                  false,
0662                                  SortOrder::NoMessageSorting);
0663     add_theme_simple_icon_column(s,
0664                                  i18n("Watched/Ignored"),
0665                                  QStringLiteral("mail-thread-watch"),
0666                                  Theme::ContentItem::WatchedIgnoredStateIcon,
0667                                  false,
0668                                  SortOrder::NoMessageSorting);
0669     add_theme_simple_icon_column(s,
0670                                  i18n("Encryption"),
0671                                  QStringLiteral("mail-encrypted-full"),
0672                                  Theme::ContentItem::EncryptionStateIcon,
0673                                  false,
0674                                  SortOrder::NoMessageSorting);
0675     add_theme_simple_icon_column(s,
0676                                  i18n("Signature"),
0677                                  QStringLiteral("mail-signed-verified"),
0678                                  Theme::ContentItem::SignatureStateIcon,
0679                                  false,
0680                                  SortOrder::NoMessageSorting);
0681     add_theme_simple_icon_column(s, i18n("Tag List"), QStringLiteral("feed-subscribe"), Theme::ContentItem::TagList, false, SortOrder::NoMessageSorting);
0682 
0683     s->resetColumnState(); // so it's initially set from defaults
0684 
0685     addTheme(s);
0686 
0687     // The Fancy theme
0688 
0689     s = new Theme(i18n("Smart"), i18n("A smart multiline and multi item theme"), true /*readOnly*/
0690     );
0691 
0692     c = new Theme::Column();
0693     c->setLabel(i18n("Message"));
0694 
0695     r = new Theme::Row();
0696     i = new Theme::ContentItem(Theme::ContentItem::ExpandedStateIcon);
0697     r->addLeftItem(i);
0698     i = new Theme::ContentItem(Theme::ContentItem::GroupHeaderLabel);
0699     i->setBold(true);
0700     r->addLeftItem(i);
0701     c->addGroupHeaderRow(r);
0702 
0703     r = new Theme::Row();
0704     i = new Theme::ContentItem(Theme::ContentItem::Subject);
0705     r->addLeftItem(i);
0706     i = new Theme::ContentItem(Theme::ContentItem::ReadStateIcon);
0707     r->addRightItem(i);
0708     i = new Theme::ContentItem(Theme::ContentItem::RepliedStateIcon);
0709     i->setHideWhenDisabled(true);
0710     r->addRightItem(i);
0711     i = new Theme::ContentItem(Theme::ContentItem::AttachmentStateIcon);
0712     i->setHideWhenDisabled(true);
0713     r->addRightItem(i);
0714     i = new Theme::ContentItem(Theme::ContentItem::AnnotationIcon);
0715     i->setHideWhenDisabled(true);
0716     r->addRightItem(i);
0717     i = new Theme::ContentItem(Theme::ContentItem::InvitationIcon);
0718     i->setHideWhenDisabled(true);
0719     r->addRightItem(i);
0720     i = new Theme::ContentItem(Theme::ContentItem::EncryptionStateIcon);
0721     i->setHideWhenDisabled(true);
0722     r->addRightItem(i);
0723     i = new Theme::ContentItem(Theme::ContentItem::SignatureStateIcon);
0724     i->setHideWhenDisabled(true);
0725     r->addRightItem(i);
0726     i = new Theme::ContentItem(Theme::ContentItem::TagList);
0727     i->setHideWhenDisabled(true);
0728     r->addRightItem(i);
0729     c->addMessageRow(r);
0730 
0731     Theme::Row *firstFancyRow = r; // save it so we can continue adding stuff below (after cloning the theme)
0732 
0733     r = new Theme::Row();
0734     i = new Theme::ContentItem(Theme::ContentItem::SenderOrReceiver);
0735     i->setSoftenByBlending(true);
0736     i->setItalic(true);
0737     r->addLeftItem(i);
0738     i = new Theme::ContentItem(Theme::ContentItem::Date);
0739     i->setSoftenByBlending(true);
0740     i->setItalic(true);
0741     r->addRightItem(i);
0742     c->addMessageRow(r);
0743 
0744     s->addColumn(c);
0745 
0746     // clone the "Fancy theme" here so we'll use it as starting point for the "Fancy with clickable status"
0747     auto fancyWithClickableStatus = new Theme(*s);
0748     fancyWithClickableStatus->detach();
0749     fancyWithClickableStatus->generateUniqueId();
0750 
0751     // and continue the "Fancy" specific settings
0752     r = firstFancyRow;
0753 
0754     i = new Theme::ContentItem(Theme::ContentItem::ActionItemStateIcon);
0755     i->setHideWhenDisabled(true);
0756     r->addRightItem(i);
0757     i = new Theme::ContentItem(Theme::ContentItem::ImportantStateIcon);
0758     i->setHideWhenDisabled(true);
0759     r->addRightItem(i);
0760     i = new Theme::ContentItem(Theme::ContentItem::SpamHamStateIcon);
0761     i->setHideWhenDisabled(true);
0762     r->addRightItem(i);
0763     i = new Theme::ContentItem(Theme::ContentItem::WatchedIgnoredStateIcon);
0764     i->setHideWhenDisabled(true);
0765     r->addRightItem(i);
0766 
0767     s->setViewHeaderPolicy(Theme::NeverShowHeader);
0768 
0769     s->resetColumnState(); // so it's initially set from defaults
0770 
0771     addTheme(s);
0772 
0773     // The "Fancy with Clickable Status" theme
0774 
0775     s = fancyWithClickableStatus;
0776 
0777     s->setName(i18n("Smart with Clickable Status"));
0778     s->setDescription(i18n("A smart multiline and multi item theme with a clickable status column"));
0779     s->setReadOnly(true);
0780 
0781     c = new Theme::Column();
0782     c->setLabel(i18n("Status"));
0783     c->setVisibleByDefault(true);
0784 
0785     r = new Theme::Row();
0786     i = new Theme::ContentItem(Theme::ContentItem::ActionItemStateIcon);
0787     i->setSoftenByBlendingWhenDisabled(true);
0788     r->addLeftItem(i);
0789     i = new Theme::ContentItem(Theme::ContentItem::ImportantStateIcon);
0790     i->setSoftenByBlendingWhenDisabled(true);
0791     r->addLeftItem(i);
0792     c->addMessageRow(r);
0793 
0794     r = new Theme::Row();
0795     i = new Theme::ContentItem(Theme::ContentItem::SpamHamStateIcon);
0796     i->setSoftenByBlendingWhenDisabled(true);
0797     r->addLeftItem(i);
0798     i = new Theme::ContentItem(Theme::ContentItem::WatchedIgnoredStateIcon);
0799     i->setSoftenByBlendingWhenDisabled(true);
0800     r->addLeftItem(i);
0801     c->addMessageRow(r);
0802 
0803     s->addColumn(c);
0804 
0805     s->resetColumnState(); // so it's initially set from defaults
0806 
0807     addTheme(s);
0808 }
0809 
0810 void Manager::removeAllThemes()
0811 {
0812     QMap<QString, Theme *>::ConstIterator end(mThemes.constEnd());
0813     for (QMap<QString, Theme *>::ConstIterator it = mThemes.constBegin(); it != end; ++it) {
0814         delete (*it);
0815     }
0816 
0817     mThemes.clear();
0818 }
0819 
0820 void Manager::themesConfigurationCompleted()
0821 {
0822     if (mThemes.isEmpty()) {
0823         createDefaultThemes(); // panic
0824     }
0825 
0826     saveConfiguration(); // just to be sure :)
0827 
0828     // notify all the widgets that they should reload the option set combos
0829     Q_EMIT themesChanged();
0830 }
0831 
0832 void Manager::reloadAllWidgets()
0833 {
0834     QList<Widget *>::ConstIterator end(mWidgetList.constEnd());
0835     for (QList<Widget *>::ConstIterator it = mWidgetList.constBegin(); it != end; ++it) {
0836         if ((*it)->view()) {
0837             (*it)->view()->reload();
0838         }
0839     }
0840 }
0841 
0842 void Manager::reloadGlobalConfiguration()
0843 {
0844     // This is called when configuration changes (probably edited by the options dialog)
0845     const int oldDateFormat = (int)mDateFormatter->format();
0846     const QString oldDateCustomFormat = mDateFormatter->customFormat();
0847 
0848     loadGlobalConfiguration();
0849 
0850     if ((oldDateFormat != (int)mDateFormatter->format()) || (oldDateCustomFormat != mDateFormatter->customFormat())) {
0851         reloadAllWidgets();
0852     }
0853 }
0854 
0855 void Manager::loadGlobalConfiguration()
0856 {
0857     // Load the date format
0858     const auto type = static_cast<KMime::DateFormatter::FormatType>(MessageCore::MessageCoreSettings::self()->dateFormat());
0859     mDateFormatter->setCustomFormat(MessageCore::MessageCoreSettings::self()->customDateFormat());
0860     mDateFormatter->setFormat(type);
0861 }
0862 
0863 void Manager::loadConfiguration()
0864 {
0865     loadGlobalConfiguration();
0866 
0867     {
0868         // load Aggregations
0869 
0870         KConfigGroup conf(MessageListSettings::self()->config(), QStringLiteral("MessageListView::Aggregations"));
0871 
0872         mAggregations.clear();
0873 
0874         const int cnt = conf.readEntry("Count", 0);
0875 
0876         int idx = 0;
0877         while (idx < cnt) {
0878             const QString data = conf.readEntry(QStringLiteral("Set%1").arg(idx), QString());
0879             if (!data.isEmpty()) {
0880                 auto set = new Aggregation();
0881                 if (set->loadFromString(data)) {
0882                     if (Aggregation *old = mAggregations.value(set->id())) {
0883                         delete old;
0884                     }
0885                     mAggregations.insert(set->id(), set);
0886                 } else {
0887                     delete set; // b0rken
0888                 }
0889             }
0890             idx++;
0891         }
0892 
0893         if (mAggregations.isEmpty()) {
0894             // don't allow zero configuration, create some presets
0895             createDefaultAggregations();
0896         }
0897     }
0898 
0899     {
0900         // load Themes
0901 
0902         KConfigGroup conf(MessageListSettings::self()->config(), QStringLiteral("MessageListView::Themes"));
0903 
0904         mThemes.clear();
0905 
0906         const int cnt = conf.readEntry("Count", 0);
0907 
0908         int idx = 0;
0909         while (idx < cnt) {
0910             const QString data = conf.readEntry(QStringLiteral("Set%1").arg(idx), QString());
0911             if (!data.isEmpty()) {
0912                 auto set = new Theme();
0913                 if (set->loadFromString(data)) {
0914                     if (Theme *old = mThemes.value(set->id())) {
0915                         delete old;
0916                     }
0917                     mThemes.insert(set->id(), set);
0918                 } else {
0919                     qCWarning(MESSAGELIST_LOG) << "Saved theme loading failed";
0920                     delete set; // b0rken
0921                 }
0922             }
0923             ++idx;
0924         }
0925 
0926         if (mThemes.isEmpty()) {
0927             // don't allow zero configuration, create some presets
0928             createDefaultThemes();
0929         }
0930     }
0931 }
0932 
0933 void Manager::saveGlobalConfiguration()
0934 {
0935     MessageListSettings::self()->save();
0936 }
0937 
0938 void Manager::saveConfiguration()
0939 {
0940     saveGlobalConfiguration();
0941 
0942     {
0943         // store aggregations
0944 
0945         KConfigGroup conf(MessageListSettings::self()->config(), QStringLiteral("MessageListView::Aggregations"));
0946         // conf.clear();
0947 
0948         conf.writeEntry("Count", mAggregations.count());
0949 
0950         int idx = 0;
0951         QMap<QString, Aggregation *>::ConstIterator end(mAggregations.end());
0952         for (QMap<QString, Aggregation *>::ConstIterator it = mAggregations.constBegin(); it != end; ++it) {
0953             conf.writeEntry(QStringLiteral("Set%1").arg(idx), (*it)->saveToString());
0954             ++idx;
0955         }
0956     }
0957 
0958     {
0959         // store themes
0960 
0961         KConfigGroup conf(MessageListSettings::self()->config(), QStringLiteral("MessageListView::Themes"));
0962         // conf.clear();
0963 
0964         conf.writeEntry("Count", mThemes.count());
0965 
0966         int idx = 0;
0967         QMap<QString, Theme *>::ConstIterator end(mThemes.constEnd());
0968         for (QMap<QString, Theme *>::ConstIterator it = mThemes.constBegin(); it != end; ++it) {
0969             conf.writeEntry(QStringLiteral("Set%1").arg(idx), (*it)->saveToString());
0970             ++idx;
0971         }
0972     }
0973 
0974     MessageListSettings::self()->config()->sync();
0975 }
0976 
0977 #include "moc_manager.cpp"