diff --git a/src/librssguard/core/messagesmodel.cpp b/src/librssguard/core/messagesmodel.cpp index c44144729..b387e461b 100644 --- a/src/librssguard/core/messagesmodel.cpp +++ b/src/librssguard/core/messagesmodel.cpp @@ -27,8 +27,8 @@ MessagesModel::MessagesModel(QObject* parent) : QSqlQueryModel(parent), m_view(nullptr), m_cache(new MessagesModelCache(this)), m_messageHighlighter(MessageHighlighter::NoHighlighting), m_customDateFormat(QString()), - m_customTimeFormat(QString()), m_newerArticlesRelativeTime(-1), m_selectedItem(nullptr), - m_unreadIconType(MessageUnreadIcon::Dot), + m_customTimeFormat(QString()), m_customFormatForDatesOnly(QString()), m_newerArticlesRelativeTime(-1), + m_selectedItem(nullptr), m_unreadIconType(MessageUnreadIcon::Dot), m_multilineListItems(qApp->settings()->value(GROUP(Messages), SETTING(Messages::MultilineArticleList)).toBool()) { updateFeedIconsDisplay(); updateDateFormat(); @@ -257,6 +257,14 @@ void MessagesModel::updateDateFormat() { m_customTimeFormat = QString(); } + if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomFormatForDatesOnly)).toBool()) { + m_customFormatForDatesOnly = + qApp->settings()->value(GROUP(Messages), SETTING(Messages::CustomFormatForDatesOnly)).toString(); + } + else { + m_customFormatForDatesOnly = QString(); + } + m_newerArticlesRelativeTime = qApp->settings()->value(GROUP(Messages), SETTING(Messages::RelativeTimeForNewerArticles)).toInt(); } @@ -339,12 +347,17 @@ QVariant MessagesModel::data(const QModelIndex& idx, int role) const { int index_column = idx.column(); if (index_column == MSG_DB_DCREATED_INDEX) { - QDateTime dt = TextFactory::parseDateTime(QSqlQueryModel::data(idx, Qt::ItemDataRole::EditRole).value()) - .toLocalTime(); + QDateTime utc_dt = + TextFactory::parseDateTime(QSqlQueryModel::data(idx, Qt::ItemDataRole::EditRole).value()); + QDateTime dt = utc_dt.toLocalTime(); if (dt.date() == QDate::currentDate() && !m_customTimeFormat.isEmpty()) { return dt.toString(m_customTimeFormat); } + else if (!m_customFormatForDatesOnly.isEmpty() && utc_dt.time().hour() == 0 && utc_dt.time().minute() == 0 && + utc_dt.time().second() == 0) { + return dt.toString(m_customFormatForDatesOnly); + } else if (m_newerArticlesRelativeTime > 0 && dt.daysTo(QDateTime::currentDateTime()) <= m_newerArticlesRelativeTime) { auto secs_difference = dt.secsTo(QDateTime::currentDateTime()); diff --git a/src/librssguard/core/messagesmodel.h b/src/librssguard/core/messagesmodel.h index c1e72de02..e42d783a6 100644 --- a/src/librssguard/core/messagesmodel.h +++ b/src/librssguard/core/messagesmodel.h @@ -105,6 +105,7 @@ class MessagesModel : public QSqlQueryModel, public MessagesModelSqlLayer { MessageHighlighter m_messageHighlighter; QString m_customDateFormat; QString m_customTimeFormat; + QString m_customFormatForDatesOnly; int m_newerArticlesRelativeTime; RootItem* m_selectedItem; QList m_headerData; diff --git a/src/librssguard/gui/settings/settingsfeedsmessages.cpp b/src/librssguard/gui/settings/settingsfeedsmessages.cpp index 626fc2b0a..88382ea20 100644 --- a/src/librssguard/gui/settings/settingsfeedsmessages.cpp +++ b/src/librssguard/gui/settings/settingsfeedsmessages.cpp @@ -95,10 +95,20 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent m_ui->m_cmbMessagesDateTimeFormat, &QComboBox::setEnabled); - connect(m_ui->m_checkMessagesTimeFormat, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_cmbFastAutoUpdate, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); + + connect(m_ui->m_checkMessagesTimeFormat, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkMessagesTimeFormat, &QCheckBox::toggled, m_ui->m_cmbMessagesTimeFormat, &QComboBox::setEnabled); + connect(m_ui->m_checkMessagesDateTimeFormatForDatesOnly, + &QCheckBox::toggled, + this, + &SettingsFeedsMessages::dirtifySettings); + connect(m_ui->m_checkMessagesDateTimeFormatForDatesOnly, + &QCheckBox::toggled, + m_ui->m_cmbMessagesDateTimeFormatForDatesOnly, + &QComboBox::setEnabled); + connect(m_ui->m_checkRemoveReadMessagesOnExit, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_checkBringToForegroundAfterMsgOpened, &QCheckBox::toggled, @@ -161,7 +171,12 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent &QComboBox::currentTextChanged, this, &SettingsFeedsMessages::dirtifySettings); + connect(m_ui->m_cmbMessagesTimeFormat, &QComboBox::currentTextChanged, this, &SettingsFeedsMessages::dirtifySettings); + connect(m_ui->m_cmbMessagesDateTimeFormatForDatesOnly, + &QComboBox::currentTextChanged, + this, + &SettingsFeedsMessages::dirtifySettings); connect(m_ui->m_cbFixupArticleDatetime, &QCheckBox::toggled, this, &SettingsFeedsMessages::dirtifySettings); @@ -185,6 +200,7 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent emit m_ui->m_cmbMessagesDateTimeFormat->currentTextChanged({}); emit m_ui->m_cmbMessagesTimeFormat->currentTextChanged({}); + emit m_ui->m_cmbMessagesDateTimeFormatForDatesOnly->currentTextChanged({}); connect(m_ui->m_btnChangeMessagesFont, &QPushButton::clicked, this, [&]() { changeFont(*m_ui->m_lblMessagesFont); @@ -220,6 +236,7 @@ void SettingsFeedsMessages::initializeMessageDateFormats() { m_ui->m_cmbMessagesDateTimeFormat->addItems(patterns); m_ui->m_cmbMessagesTimeFormat->addItems(patterns); + m_ui->m_cmbMessagesDateTimeFormatForDatesOnly->addItems(patterns); for (int i = 0; i < patterns.size(); i++) { m_ui->m_cmbMessagesDateTimeFormat->setItemData(i, @@ -228,6 +245,9 @@ void SettingsFeedsMessages::initializeMessageDateFormats() { m_ui->m_cmbMessagesTimeFormat->setItemData(i, QDateTime::currentDateTime().toString(patterns.at(i)), Qt::ItemDataRole::ToolTipRole); + m_ui->m_cmbMessagesDateTimeFormatForDatesOnly->setItemData(i, + QDateTime::currentDateTime().toString(patterns.at(i)), + Qt::ItemDataRole::ToolTipRole); } } @@ -322,6 +342,11 @@ void SettingsFeedsMessages::loadSettings() { m_ui->m_cmbMessagesTimeFormat ->setCurrentText(settings()->value(GROUP(Messages), SETTING(Messages::CustomTimeFormat)).toString()); + m_ui->m_checkMessagesDateTimeFormatForDatesOnly + ->setChecked(settings()->value(GROUP(Messages), SETTING(Messages::UseCustomFormatForDatesOnly)).toBool()); + m_ui->m_cmbMessagesDateTimeFormatForDatesOnly + ->setCurrentText(settings()->value(GROUP(Messages), SETTING(Messages::CustomFormatForDatesOnly)).toString()); + QFont fon; fon.fromString(settings()->value(GROUP(Messages), SETTING(Messages::PreviewerFontStandard)).toString()); @@ -434,12 +459,20 @@ void SettingsFeedsMessages::saveSettings() { settings()->setValue(GROUP(Messages), Messages::AlwaysDisplayItemPreview, m_ui->m_cbArticleViewerAlwaysVisible->isChecked()); + settings()->setValue(GROUP(Messages), Messages::UseCustomDate, m_ui->m_checkMessagesDateTimeFormat->isChecked()); settings()->setValue(GROUP(Messages), Messages::UseCustomTime, m_ui->m_checkMessagesTimeFormat->isChecked()); settings()->setValue(GROUP(Messages), Messages::CustomDateFormat, m_ui->m_cmbMessagesDateTimeFormat->currentText()); settings()->setValue(GROUP(Messages), Messages::CustomTimeFormat, m_ui->m_cmbMessagesTimeFormat->currentText()); + settings()->setValue(GROUP(Messages), + Messages::UseCustomFormatForDatesOnly, + m_ui->m_checkMessagesDateTimeFormatForDatesOnly->isChecked()); + settings()->setValue(GROUP(Messages), + Messages::CustomFormatForDatesOnly, + m_ui->m_cmbMessagesDateTimeFormatForDatesOnly->currentText()); + // Save fonts. settings()->setValue(GROUP(Messages), Messages::PreviewerFontStandard, m_ui->m_lblMessagesFont->font().toString()); settings()->setValue(GROUP(Messages), Messages::ListFont, m_ui->m_lblMessageListFont->font().toString()); diff --git a/src/librssguard/gui/settings/settingsfeedsmessages.ui b/src/librssguard/gui/settings/settingsfeedsmessages.ui index 8f364d5b1..69655a65d 100644 --- a/src/librssguard/gui/settings/settingsfeedsmessages.ui +++ b/src/librssguard/gui/settings/settingsfeedsmessages.ui @@ -14,7 +14,7 @@ - 0 + 3 @@ -428,6 +428,19 @@ Articles list + + + + Unread article icon type + + + m_cmbUnreadIconType + + + + + + @@ -536,7 +549,7 @@ - + Custom date/time format for today's articles @@ -549,7 +562,7 @@ - + @@ -562,14 +575,14 @@ - + Show relative time for articles not older than - + -1 @@ -579,7 +592,7 @@ - + Article list font @@ -611,16 +624,29 @@ - - - - - - - Unread article icon type + + + + + 150 + 0 + - - m_cmbUnreadIconType + + true + + + + + + + Use custom date/time format for dates-only + + + true + + + true diff --git a/src/librssguard/miscellaneous/settings.cpp b/src/librssguard/miscellaneous/settings.cpp index 7b0844827..afa5a4436 100644 --- a/src/librssguard/miscellaneous/settings.cpp +++ b/src/librssguard/miscellaneous/settings.cpp @@ -191,6 +191,12 @@ DVALUE(bool) Messages::UseCustomDateDef = false; DKEY Messages::CustomDateFormat = "custom_date_format"; DVALUE(char*) Messages::CustomDateFormatDef = ""; +DKEY Messages::CustomFormatForDatesOnly = "custom_date_format_for_dates_only"; +DVALUE(char*) Messages::CustomFormatForDatesOnlyDef = ""; + +DKEY Messages::UseCustomFormatForDatesOnly = "use_custom_date_for_dates_only"; +DVALUE(bool) Messages::UseCustomFormatForDatesOnlyDef = false; + DKEY Messages::RelativeTimeForNewerArticles = "relative_time_for_new_articles"; DVALUE(int) Messages::RelativeTimeForNewerArticlesDef = -1; diff --git a/src/librssguard/miscellaneous/settings.h b/src/librssguard/miscellaneous/settings.h index cb46d5844..506f9646c 100644 --- a/src/librssguard/miscellaneous/settings.h +++ b/src/librssguard/miscellaneous/settings.h @@ -191,6 +191,12 @@ namespace Messages { KEY UseCustomTime; VALUE(bool) UseCustomTimeDef; + KEY CustomFormatForDatesOnly; + VALUE(char*) CustomFormatForDatesOnlyDef; + + KEY UseCustomFormatForDatesOnly; + VALUE(bool) UseCustomFormatForDatesOnlyDef; + KEY RelativeTimeForNewerArticles; VALUE(int) RelativeTimeForNewerArticlesDef; diff --git a/src/librssguard/miscellaneous/textfactory.cpp b/src/librssguard/miscellaneous/textfactory.cpp index c939b902d..f8a00c784 100644 --- a/src/librssguard/miscellaneous/textfactory.cpp +++ b/src/librssguard/miscellaneous/textfactory.cpp @@ -81,6 +81,11 @@ bool TextFactory::couldBeHtml(const QString& string) { QDateTime TextFactory::parseDateTime(const QString& date_time) { const QString input_date = date_time.simplified(); + + if (input_date.isEmpty()) { + return QDateTime(); + } + QDateTime dt; QTime time_zone_offset; const QLocale locale(QLocale::Language::C); diff --git a/src/librssguard/services/standard/parsers/icalparser.cpp b/src/librssguard/services/standard/parsers/icalparser.cpp index 79c101c69..75e5a625e 100644 --- a/src/librssguard/services/standard/parsers/icalparser.cpp +++ b/src/librssguard/services/standard/parsers/icalparser.cpp @@ -2,6 +2,7 @@ #include "services/standard/parsers/icalparser.h" +#include "3rd-party/boolinq/boolinq.h" #include "definitions/definitions.h" #include "exceptions/applicationexception.h" #include "exceptions/feedrecognizedbutfailedexception.h" @@ -122,7 +123,7 @@ QDateTime IcalParser::objMessageDateCreated(const QVariant& msg_element) const { const IcalendarComponent& comp_base = msg_element.value(); const EventComponent& comp = static_cast(comp_base); - return comp.created(); + return comp.startsOn(); } QString IcalParser::objMessageId(const QVariant& msg_element) const { @@ -161,7 +162,7 @@ void Icalendar::setTitle(const QString& title) { } void Icalendar::processLines(const QString& data) { - QRegularExpression regex("^BEGIN:(\\w+)\\r$(.+?)^(BEGIN|END):\\w+", + QRegularExpression regex("^BEGIN:(\\w+)\\r$(.+?)(?=^BEGIN|^END)", QRegularExpression::PatternOption::MultilineOption | QRegularExpression::PatternOption::DotMatchesEverythingOption); @@ -199,7 +200,7 @@ void Icalendar::processComponentEvent(const QString& body) { } QVariantMap Icalendar::tokenizeBody(const QString& body) const { - QRegularExpression regex("^(?=[A-Z-]+:)", QRegularExpression::PatternOption::MultilineOption); + QRegularExpression regex("^(?=[A-Z-]+(?:;[A-Z]+=[A-Z]+)?:)", QRegularExpression::PatternOption::MultilineOption); auto all_matches = body.split(regex); QVariantMap res; @@ -234,6 +235,30 @@ void IcalendarComponent::setProperties(const QVariantMap& properties) { m_properties = properties; } +QVariant IcalendarComponent::getPropertyValue(const QString& property_name) const { + if (m_properties.contains(property_name)) { + return m_properties.value(property_name); + } + + QStringList keys = m_properties.keys(); + auto linq = boolinq::from(keys); + QString found_key = linq.firstOrDefault([&](const QString& ky) { + int index_sep = ky.indexOf(';'); + + return ky.startsWith(property_name) && index_sep == property_name.size(); + }); + + return m_properties.value(found_key); +} + +QDateTime EventComponent::startsOn() const { + return TextFactory::parseDateTime(getPropertyValue(QSL("DTSTART")).toString()); +} + +QDateTime EventComponent::endsOn() const { + return TextFactory::parseDateTime(m_properties.value(QSL("DTEND")).toString()); +} + QString EventComponent::title() const { return m_properties.value(QSL("SUMMARY")).toString(); } @@ -246,6 +271,10 @@ QString EventComponent::organizer() const { return m_properties.value(QSL("ORGANIZER")).toString(); } +QString EventComponent::location() const { + return m_properties.value(QSL("LOCATION")).toString(); +} + QString EventComponent::description() const { return m_properties.value(QSL("DESCRIPTION")).toString(); } @@ -253,3 +282,7 @@ QString EventComponent::description() const { QDateTime EventComponent::created() const { return TextFactory::parseDateTime(m_properties.value(QSL("CREATED")).toString()); } + +QDateTime EventComponent::lastModified() const { + return TextFactory::parseDateTime(m_properties.value(QSL("LAST-MODIFIED")).toString()); +} diff --git a/src/librssguard/services/standard/parsers/icalparser.h b/src/librssguard/services/standard/parsers/icalparser.h index 898f49d0a..08122f305 100644 --- a/src/librssguard/services/standard/parsers/icalparser.h +++ b/src/librssguard/services/standard/parsers/icalparser.h @@ -13,6 +13,8 @@ class IcalendarComponent { void setProperties(const QVariantMap& properties); protected: + QVariant getPropertyValue(const QString& property_name) const; + QVariantMap m_properties; }; @@ -20,11 +22,15 @@ Q_DECLARE_METATYPE(IcalendarComponent) class EventComponent : public IcalendarComponent { public: + QDateTime startsOn() const; + QDateTime endsOn() const; QString title() const; QString url() const; QString organizer() const; + QString location() const; QString description() const; QDateTime created() const; + QDateTime lastModified() const; }; Q_DECLARE_METATYPE(EventComponent)