9 #include "core/manager.h"
11 #include "core/aggregation.h"
12 #include "core/storagemodelbase.h"
13 #include "core/theme.h"
14 #include "core/view.h"
15 #include "core/widgetbase.h"
16 #include "messagelistsettings.h"
18 #include "MessageCore/MessageCoreSettings"
20 #include "messagelistutil_p.h"
22 #include <KMime/DateFormatter>
24 #include "messagelist_debug.h"
26 #include <KLocalizedString>
30 Manager *Manager::mInstance =
nullptr;
34 , mDateFormatter(new KMime::DateFormatter())
38 mCachedLocalizedUnknownText =
i18nc(
"Unknown date",
"Unknown");
41 connect(MessageListSettings::self(), &MessageListSettings::configChanged,
this, &Manager::reloadGlobalConfiguration);
42 connect(MessageCore::MessageCoreSettings::self(), &MessageCore::MessageCoreSettings::configChanged,
this, &Manager::reloadGlobalConfiguration);
47 disconnect(MessageListSettings::self(), &MessageListSettings::configChanged,
this, &Manager::reloadGlobalConfiguration);
48 disconnect(MessageCore::MessageCoreSettings::self(), &MessageCore::MessageCoreSettings::configChanged,
this, &Manager::reloadGlobalConfiguration);
51 removeAllAggregations();
54 delete mDateFormatter;
59 void Manager::registerWidget(
Widget *pWidget)
65 mInstance->mWidgetList.append(pWidget);
68 void Manager::unregisterWidget(
Widget *pWidget)
71 qCWarning(MESSAGELIST_LOG) << (
"ERROR: MessageList::Manager::unregisterWidget() called when Manager::mInstance is null");
75 mInstance->mWidgetList.removeAll(pWidget);
77 if (mInstance->mWidgetList.isEmpty()) {
90 return defaultAggregation();
95 KConfigGroup conf(MessageListSettings::self()->
config(), MessageList::Util::storageModelAggregationsGroup());
97 const QString aggregationId = conf.readEntry(QStringLiteral(
"DefaultSet"),
"");
101 if (!aggregationId.
isEmpty()) {
102 opt = mAggregations.value(aggregationId);
111 if (it != mAggregations.constEnd()) {
116 createDefaultAggregations();
118 return *(mAggregations.constBegin());
121 void Manager::saveAggregationForStorageModel(
const Akonadi::Collection &col,
const QString &
id,
bool storageUsesPrivateAggregation)
126 saveAggregationForStorageModel(
QString::number(col.
id()),
id, storageUsesPrivateAggregation);
129 void Manager::saveAggregationForStorageModel(
const StorageModel *storageModel,
const QString &
id,
bool storageUsesPrivateAggregation)
131 saveAggregationForStorageModel(storageModel->
id(),
id, storageUsesPrivateAggregation);
134 void Manager::saveAggregationForStorageModel(
const QString &modelId,
const QString &
id,
bool storageUsesPrivateAggregation)
136 KConfigGroup conf(MessageListSettings::self()->
config(), MessageList::Util::storageModelAggregationsGroup());
138 if (storageUsesPrivateAggregation) {
139 conf.writeEntry(MessageList::Util::setForStorageModelConfigName().arg(modelId),
id);
141 conf.deleteEntry(MessageList::Util::setForStorageModelConfigName().arg(modelId));
144 if (!storageUsesPrivateAggregation) {
145 conf.writeEntry(QStringLiteral(
"DefaultSet"),
id);
151 Q_ASSERT(storageUsesPrivateAggregation);
153 *storageUsesPrivateAggregation =
false;
156 return defaultAggregation();
158 return Manager::aggregationForStorageModel(
QString::number(col.
id()), storageUsesPrivateAggregation);
161 const Aggregation *Manager::aggregationForStorageModel(
const StorageModel *storageModel,
bool *storageUsesPrivateAggregation)
163 Q_ASSERT(storageUsesPrivateAggregation);
165 *storageUsesPrivateAggregation =
false;
168 return defaultAggregation();
170 return Manager::aggregationForStorageModel(storageModel->
id(), storageUsesPrivateAggregation);
173 const Aggregation *Manager::aggregationForStorageModel(
const QString &storageId,
bool *storageUsesPrivateAggregation)
175 KConfigGroup conf(MessageListSettings::self()->
config(), MessageList::Util::storageModelAggregationsGroup());
177 const QString aggregationId = conf.readEntry(MessageList::Util::setForStorageModelConfigName().arg(storageId),
"");
181 if (!aggregationId.
isEmpty()) {
183 opt = mAggregations.value(aggregationId);
184 *storageUsesPrivateAggregation = (opt !=
nullptr);
194 return defaultAggregation();
201 mAggregations.insert(set->
id(), set);
204 void Manager::createDefaultAggregations()
207 i18n(
"This view uses smart date range groups. "
208 "Messages are threaded. "
209 "So for example, in \"Today\" you will find all the messages arrived today "
210 "and all the threads that have been active today."),
211 Aggregation::GroupByDateRange,
212 Aggregation::ExpandRecentGroups,
213 Aggregation::PerfectReferencesAndSubject,
214 Aggregation::MostRecentMessage,
215 Aggregation::ExpandThreadsWithUnreadOrImportantMessages,
216 Aggregation::FavorInteractivity,
220 i18n(
"This view uses smart date range groups. "
221 "Messages are not threaded. "
222 "So for example, in \"Today\" you will simply find all the messages arrived today."),
223 Aggregation::GroupByDateRange,
224 Aggregation::ExpandRecentGroups,
225 Aggregation::NoThreading,
226 Aggregation::MostRecentMessage,
227 Aggregation::NeverExpandThreads,
228 Aggregation::FavorInteractivity,
232 i18n(
"This view uses day-by-day groups. "
233 "Messages are threaded. "
234 "So for example, in \"Today\" you will find all the messages arrived today "
235 "and all the threads that have been active today."),
236 Aggregation::GroupByDate,
237 Aggregation::ExpandRecentGroups,
238 Aggregation::PerfectReferencesAndSubject,
239 Aggregation::MostRecentMessage,
240 Aggregation::ExpandThreadsWithUnreadOrImportantMessages,
241 Aggregation::FavorInteractivity,
245 i18n(
"This view uses day-by-day groups. "
246 "Messages are not threaded. "
247 "So for example, in \"Today\" you will simply find all the messages arrived today."),
248 Aggregation::GroupByDate,
249 Aggregation::ExpandRecentGroups,
250 Aggregation::NoThreading,
251 Aggregation::MostRecentMessage,
252 Aggregation::NeverExpandThreads,
253 Aggregation::FavorInteractivity,
257 i18n(
"This is a plain and old mailing list view: no groups and heavy threading."),
258 Aggregation::NoGrouping,
259 Aggregation::NeverExpandGroups,
260 Aggregation::PerfectReferencesAndSubject,
261 Aggregation::TopmostMessage,
262 Aggregation::ExpandThreadsWithUnreadOrImportantMessages,
263 Aggregation::FavorInteractivity,
267 i18n(
"This is a plain and old list of messages sorted by date: no groups and no threading."),
268 Aggregation::NoGrouping,
269 Aggregation::NeverExpandGroups,
270 Aggregation::NoThreading,
271 Aggregation::TopmostMessage,
272 Aggregation::NeverExpandThreads,
273 Aggregation::FavorInteractivity,
279 i18n(
"This view groups the messages by senders or receivers (depending on the folder "
281 "Messages are not threaded."),
282 Aggregation::GroupBySenderOrReceiver,
283 Aggregation::NeverExpandGroups,
284 Aggregation::NoThreading,
285 Aggregation::TopmostMessage,
286 Aggregation::NeverExpandThreads,
287 Aggregation::FavorSpeed,
291 i18n(
"This view groups the messages in threads and then groups the threads by the starting user."),
292 Aggregation::GroupBySenderOrReceiver,
293 Aggregation::NeverExpandGroups,
294 Aggregation::PerfectReferencesAndSubject,
295 Aggregation::TopmostMessage,
296 Aggregation::NeverExpandThreads,
297 Aggregation::FavorSpeed,
320 void Manager::removeAllAggregations()
327 mAggregations.clear();
330 void Manager::aggregationsConfigurationCompleted()
332 if (mAggregations.isEmpty()) {
333 createDefaultAggregations();
339 Q_EMIT aggregationsChanged();
342 const SortOrder Manager::sortOrderForStorageModel(
const StorageModel *storageModel,
bool *storageUsesPrivateSortOrder)
344 Q_ASSERT(storageUsesPrivateSortOrder);
346 *storageUsesPrivateSortOrder =
false;
352 KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelSortOrderGroup());
354 ret.
readConfig(conf, storageModel->
id(), storageUsesPrivateSortOrder);
358 void Manager::saveSortOrderForStorageModel(
const StorageModel *storageModel,
SortOrder order,
bool storageUsesPrivateSortOrder)
360 KConfigGroup conf(MessageListSettings::self()->config(), MessageList::Util::storageModelSortOrderGroup());
361 order.
writeConfig(conf, storageModel->
id(), storageUsesPrivateSortOrder);
366 Theme *opt = mThemes.value(
id);
371 return defaultTheme();
374 const Theme *Manager::defaultTheme()
376 KConfigGroup conf(MessageListSettings::self()->
config(), MessageList::Util::storageModelThemesGroup());
378 const QString themeId = conf.readEntry(QStringLiteral(
"DefaultSet"),
"");
380 Theme *opt =
nullptr;
383 opt = mThemes.value(themeId);
392 if (it != mThemes.constEnd()) {
397 createDefaultThemes();
401 Q_ASSERT(it != mThemes.constEnd());
406 void Manager::saveThemeForStorageModel(
int index,
const QString &
id,
bool storageUsesPrivateTheme)
408 saveThemeForStorageModel(
QString::number(index),
id, storageUsesPrivateTheme);
411 void Manager::saveThemeForStorageModel(
const StorageModel *storageModel,
const QString &
id,
bool storageUsesPrivateTheme)
413 saveThemeForStorageModel(storageModel->
id(),
id, storageUsesPrivateTheme);
416 void Manager::saveThemeForStorageModel(
const QString &storageModelIndex,
const QString &
id,
bool storageUsesPrivateTheme)
418 KConfigGroup conf(MessageListSettings::self()->
config(), MessageList::Util::storageModelThemesGroup());
420 if (storageUsesPrivateTheme) {
421 conf.writeEntry(MessageList::Util::setForStorageModelConfigName().arg(storageModelIndex),
id);
423 conf.deleteEntry(MessageList::Util::setForStorageModelConfigName().arg(storageModelIndex));
426 if (!storageUsesPrivateTheme) {
427 conf.writeEntry(QStringLiteral(
"DefaultSet"),
id);
433 Q_ASSERT(storageUsesPrivateTheme);
435 *storageUsesPrivateTheme =
false;
438 return defaultTheme();
440 return Manager::themeForStorageModel(
QString::number(col.
id()), storageUsesPrivateTheme);
443 const Theme *Manager::themeForStorageModel(
const StorageModel *storageModel,
bool *storageUsesPrivateTheme)
445 Q_ASSERT(storageUsesPrivateTheme);
447 *storageUsesPrivateTheme =
false;
450 return defaultTheme();
452 return Manager::themeForStorageModel(storageModel->
id(), storageUsesPrivateTheme);
455 const Theme *Manager::themeForStorageModel(
const QString &
id,
bool *storageUsesPrivateTheme)
457 KConfigGroup conf(MessageListSettings::self()->
config(), MessageList::Util::storageModelThemesGroup());
458 const QString themeId = conf.readEntry(MessageList::Util::setForStorageModelConfigName().arg(
id),
"");
460 Theme *opt =
nullptr;
464 opt = mThemes.value(themeId);
465 *storageUsesPrivateTheme = (opt !=
nullptr);
477 return defaultTheme();
480 void Manager::addTheme(
Theme *set)
482 Theme *old = mThemes.value(set->
id());
484 mThemes.insert(set->
id(), set);
487 static Theme::Column *add_theme_simple_text_column(
Theme *s,
490 bool visibleByDefault,
493 bool addGroupHeaderItem)
495 auto c =
new Theme::Column();
497 c->setVisibleByDefault(visibleByDefault);
498 c->setMessageSorting(messageSorting);
500 auto r =
new Theme::Row();
502 auto i =
new Theme::ContentItem(type);
512 if (addGroupHeaderItem) {
513 auto row =
new Theme::Row();
515 auto iRow =
new Theme::ContentItem(type);
518 row->addRightItem(iRow);
520 row->addLeftItem(iRow);
523 c->addGroupHeaderRow(row);
531 static Theme::Column *add_theme_simple_icon_column(
Theme *s,
535 bool visibleByDefault,
538 auto c =
new Theme::Column();
540 c->setPixmapName(pixmapName);
541 c->setVisibleByDefault(visibleByDefault);
542 c->setMessageSorting(messageSorting);
544 auto r =
new Theme::Row();
546 auto i =
new Theme::ContentItem(type);
547 i->setSoftenByBlendingWhenDisabled(
true);
558 void Manager::createDefaultThemes()
563 Theme::ContentItem *i;
567 s =
new Theme(
i18nc(
"Default theme name",
"Classic"),
i18n(
"A simple, backward compatible, single row theme"),
true
570 c =
new Theme::Column();
571 c->setLabel(
i18nc(
"@title:column Subject of messages",
"Subject"));
572 c->setMessageSorting(SortOrder::SortMessagesBySubject);
574 r =
new Theme::Row();
575 i =
new Theme::ContentItem(Theme::ContentItem::ExpandedStateIcon);
577 i =
new Theme::ContentItem(Theme::ContentItem::GroupHeaderLabel);
580 c->addGroupHeaderRow(r);
582 r =
new Theme::Row();
583 i =
new Theme::ContentItem(Theme::ContentItem::CombinedReadRepliedStateIcon);
585 i =
new Theme::ContentItem(Theme::ContentItem::AttachmentStateIcon);
586 i->setHideWhenDisabled(
true);
588 i =
new Theme::ContentItem(Theme::ContentItem::AnnotationIcon);
589 i->setHideWhenDisabled(
true);
591 i =
new Theme::ContentItem(Theme::ContentItem::InvitationIcon);
592 i->setHideWhenDisabled(
true);
594 i =
new Theme::ContentItem(Theme::ContentItem::SignatureStateIcon);
595 i->setHideWhenDisabled(
true);
597 i =
new Theme::ContentItem(Theme::ContentItem::EncryptionStateIcon);
598 i->setHideWhenDisabled(
true);
600 i =
new Theme::ContentItem(Theme::ContentItem::Subject);
606 c = add_theme_simple_text_column(s,
607 i18n(
"Sender/Receiver"),
608 Theme::ContentItem::SenderOrReceiver,
610 SortOrder::SortMessagesBySenderOrReceiver,
613 c->setIsSenderOrReceiver(
true);
614 add_theme_simple_text_column(s,
i18nc(
"Sender of a message",
"Sender"), Theme::ContentItem::Sender,
false, SortOrder::SortMessagesBySender,
false,
false);
615 add_theme_simple_text_column(s,
616 i18nc(
"Receiver of a message",
"Receiver"),
617 Theme::ContentItem::Receiver,
619 SortOrder::SortMessagesByReceiver,
622 add_theme_simple_text_column(s,
i18nc(
"Date of a message",
"Date"), Theme::ContentItem::Date,
true, SortOrder::SortMessagesByDateTime,
false,
false);
623 add_theme_simple_text_column(s,
624 i18n(
"Most Recent Date"),
625 Theme::ContentItem::MostRecentDate,
627 SortOrder::SortMessagesByDateTimeOfMostRecent,
630 add_theme_simple_text_column(s,
i18nc(
"Size of a message",
"Size"), Theme::ContentItem::Size,
false, SortOrder::SortMessagesBySize,
false,
false);
631 add_theme_simple_icon_column(s,
632 i18nc(
"Attachment indication",
"Attachment"),
633 QStringLiteral(
"mail-attachment"),
634 Theme::ContentItem::AttachmentStateIcon,
636 SortOrder::SortMessagesByAttachmentStatus);
637 add_theme_simple_icon_column(s,
639 QStringLiteral(
"mail-mark-unread-new"),
640 Theme::ContentItem::ReadStateIcon,
642 SortOrder::SortMessagesByUnreadStatus);
643 add_theme_simple_icon_column(s,
i18n(
"Replied"), QStringLiteral(
"mail-replied"), Theme::ContentItem::RepliedStateIcon,
false, SortOrder::NoMessageSorting);
644 add_theme_simple_icon_column(s,
645 i18nc(
"Message importance indication",
"Important"),
646 QStringLiteral(
"mail-mark-important"),
647 Theme::ContentItem::ImportantStateIcon,
649 SortOrder::SortMessagesByImportantStatus);
650 add_theme_simple_icon_column(s,
652 QStringLiteral(
"mail-task"),
653 Theme::ContentItem::ActionItemStateIcon,
655 SortOrder::SortMessagesByActionItemStatus);
656 add_theme_simple_icon_column(s,
658 QStringLiteral(
"mail-mark-junk"),
659 Theme::ContentItem::SpamHamStateIcon,
661 SortOrder::NoMessageSorting);
662 add_theme_simple_icon_column(s,
663 i18n(
"Watched/Ignored"),
664 QStringLiteral(
"mail-thread-watch"),
665 Theme::ContentItem::WatchedIgnoredStateIcon,
667 SortOrder::NoMessageSorting);
668 add_theme_simple_icon_column(s,
670 QStringLiteral(
"mail-encrypted-full"),
671 Theme::ContentItem::EncryptionStateIcon,
673 SortOrder::NoMessageSorting);
674 add_theme_simple_icon_column(s,
676 QStringLiteral(
"mail-signed-verified"),
677 Theme::ContentItem::SignatureStateIcon,
679 SortOrder::NoMessageSorting);
680 add_theme_simple_icon_column(s,
i18n(
"Tag List"), QStringLiteral(
"feed-subscribe"), Theme::ContentItem::TagList,
false, SortOrder::NoMessageSorting);
688 s =
new Theme(
i18n(
"Smart"),
i18n(
"A smart multiline and multi item theme"),
true
691 c =
new Theme::Column();
692 c->setLabel(
i18n(
"Message"));
694 r =
new Theme::Row();
695 i =
new Theme::ContentItem(Theme::ContentItem::ExpandedStateIcon);
697 i =
new Theme::ContentItem(Theme::ContentItem::GroupHeaderLabel);
700 c->addGroupHeaderRow(r);
702 r =
new Theme::Row();
703 i =
new Theme::ContentItem(Theme::ContentItem::Subject);
705 i =
new Theme::ContentItem(Theme::ContentItem::ReadStateIcon);
707 i =
new Theme::ContentItem(Theme::ContentItem::RepliedStateIcon);
708 i->setHideWhenDisabled(
true);
710 i =
new Theme::ContentItem(Theme::ContentItem::AttachmentStateIcon);
711 i->setHideWhenDisabled(
true);
713 i =
new Theme::ContentItem(Theme::ContentItem::AnnotationIcon);
714 i->setHideWhenDisabled(
true);
716 i =
new Theme::ContentItem(Theme::ContentItem::InvitationIcon);
717 i->setHideWhenDisabled(
true);
719 i =
new Theme::ContentItem(Theme::ContentItem::EncryptionStateIcon);
720 i->setHideWhenDisabled(
true);
722 i =
new Theme::ContentItem(Theme::ContentItem::SignatureStateIcon);
723 i->setHideWhenDisabled(
true);
725 i =
new Theme::ContentItem(Theme::ContentItem::TagList);
726 i->setHideWhenDisabled(
true);
730 Theme::Row *firstFancyRow = r;
732 r =
new Theme::Row();
733 i =
new Theme::ContentItem(Theme::ContentItem::SenderOrReceiver);
734 i->setSoftenByBlending(
true);
737 i =
new Theme::ContentItem(Theme::ContentItem::Date);
738 i->setSoftenByBlending(
true);
746 auto fancyWithClickableStatus =
new Theme(*s);
747 fancyWithClickableStatus->detach();
748 fancyWithClickableStatus->generateUniqueId();
753 i =
new Theme::ContentItem(Theme::ContentItem::ActionItemStateIcon);
754 i->setHideWhenDisabled(
true);
756 i =
new Theme::ContentItem(Theme::ContentItem::ImportantStateIcon);
757 i->setHideWhenDisabled(
true);
759 i =
new Theme::ContentItem(Theme::ContentItem::SpamHamStateIcon);
760 i->setHideWhenDisabled(
true);
762 i =
new Theme::ContentItem(Theme::ContentItem::WatchedIgnoredStateIcon);
763 i->setHideWhenDisabled(
true);
774 s = fancyWithClickableStatus;
777 s->
setDescription(
i18n(
"A smart multiline and multi item theme with a clickable status column"));
778 s->setReadOnly(
true);
780 c =
new Theme::Column();
781 c->setLabel(
i18n(
"Status"));
782 c->setVisibleByDefault(
true);
784 r =
new Theme::Row();
785 i =
new Theme::ContentItem(Theme::ContentItem::ActionItemStateIcon);
786 i->setSoftenByBlendingWhenDisabled(
true);
788 i =
new Theme::ContentItem(Theme::ContentItem::ImportantStateIcon);
789 i->setSoftenByBlendingWhenDisabled(
true);
793 r =
new Theme::Row();
794 i =
new Theme::ContentItem(Theme::ContentItem::SpamHamStateIcon);
795 i->setSoftenByBlendingWhenDisabled(
true);
797 i =
new Theme::ContentItem(Theme::ContentItem::WatchedIgnoredStateIcon);
798 i->setSoftenByBlendingWhenDisabled(
true);
809 void Manager::removeAllThemes()
819 void Manager::themesConfigurationCompleted()
821 if (mThemes.isEmpty()) {
822 createDefaultThemes();
828 Q_EMIT themesChanged();
831 void Manager::reloadAllWidgets()
836 (*it)->view()->reload();
841 void Manager::reloadGlobalConfiguration()
844 const int oldDateFormat = (int)mDateFormatter->format();
845 const QString oldDateCustomFormat = mDateFormatter->customFormat();
847 loadGlobalConfiguration();
849 if ((oldDateFormat != (
int)mDateFormatter->format()) || (oldDateCustomFormat != mDateFormatter->customFormat())) {
854 void Manager::loadGlobalConfiguration()
858 mDateFormatter->setCustomFormat(MessageCore::MessageCoreSettings::self()->customDateFormat());
859 mDateFormatter->setFormat(type);
862 void Manager::loadConfiguration()
864 loadGlobalConfiguration();
869 KConfigGroup conf(MessageListSettings::self()->config(),
"MessageListView::Aggregations");
871 mAggregations.clear();
873 const int cnt = conf.readEntry(
"Count", 0);
877 const QString data = conf.readEntry(QStringLiteral(
"Set%1").arg(idx),
QString());
884 mAggregations.insert(set->
id(), set);
892 if (mAggregations.isEmpty()) {
894 createDefaultAggregations();
905 const int cnt = conf.readEntry(
"Count", 0);
909 const QString data = conf.readEntry(QStringLiteral(
"Set%1").arg(idx),
QString());
911 auto set =
new Theme();
913 if (
Theme *old = mThemes.value(set->
id())) {
916 mThemes.insert(set->
id(), set);
918 qCWarning(MESSAGELIST_LOG) <<
"Saved theme loading failed";
925 if (mThemes.isEmpty()) {
927 createDefaultThemes();
932 void Manager::saveGlobalConfiguration()
934 MessageListSettings::self()->save();
937 void Manager::saveConfiguration()
939 saveGlobalConfiguration();
944 KConfigGroup conf(MessageListSettings::self()->
config(),
"MessageListView::Aggregations");
947 conf.writeEntry(
"Count", mAggregations.count());
952 conf.writeEntry(QStringLiteral(
"Set%1").arg(idx), (*it)->saveToString());
963 conf.writeEntry(
"Count", mThemes.count());
968 conf.writeEntry(QStringLiteral(
"Set%1").arg(idx), (*it)->saveToString());
973 MessageListSettings::self()->config()->sync();