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"