Ical: add some kind of better parsing when date/time of event is in specified timezone, it sucks before the iCal SPEC is huge and i just cannot implement it all correctly for purpose in rssguard
This commit is contained in:
parent
0308e3dc0b
commit
9abb5d1bb5
@ -265,13 +265,15 @@ void FormDiscoverFeeds::loadDiscoveredFeeds(const QList<StandardFeed*>& feeds) {
|
|||||||
RootItem* root = new RootItem();
|
RootItem* root = new RootItem();
|
||||||
|
|
||||||
for (Feed* feed : feeds) {
|
for (Feed* feed : feeds) {
|
||||||
|
if (feed->title().isEmpty()) {
|
||||||
|
feed->setTitle(tr("No title"));
|
||||||
|
}
|
||||||
|
|
||||||
root->appendChild(feed);
|
root->appendChild(feed);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui.m_pbDiscovery->setVisible(false);
|
m_ui.m_pbDiscovery->setVisible(false);
|
||||||
m_discoveredModel->setRootItem(root);
|
m_discoveredModel->setRootItem(root);
|
||||||
|
|
||||||
qDebugNN << "finish";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscoveredFeedsModel::DiscoveredFeedsModel(QObject* parent) : AccountCheckModel(parent) {}
|
DiscoveredFeedsModel::DiscoveredFeedsModel(QObject* parent) : AccountCheckModel(parent) {}
|
||||||
|
@ -109,7 +109,19 @@ QString IcalParser::objMessageDescription(const QVariant& msg_element) const {
|
|||||||
const IcalendarComponent& comp_base = msg_element.value<IcalendarComponent>();
|
const IcalendarComponent& comp_base = msg_element.value<IcalendarComponent>();
|
||||||
const EventComponent& comp = static_cast<const EventComponent&>(comp_base);
|
const EventComponent& comp = static_cast<const EventComponent&>(comp_base);
|
||||||
|
|
||||||
return comp.description();
|
QString body = QSL("Start date/time: %2<br/>"
|
||||||
|
"End date/time: %3<br/>"
|
||||||
|
"Location: %4<br/>"
|
||||||
|
"UID: %5<br/>"
|
||||||
|
"<br/>"
|
||||||
|
"%1")
|
||||||
|
.arg(comp.description(),
|
||||||
|
QLocale().toString(comp.startsOn(m_iCalendar.m_tzs)),
|
||||||
|
QLocale().toString(comp.endsOn(m_iCalendar.m_tzs)),
|
||||||
|
comp.location(),
|
||||||
|
comp.uid());
|
||||||
|
|
||||||
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString IcalParser::objMessageAuthor(const QVariant& msg_element) const {
|
QString IcalParser::objMessageAuthor(const QVariant& msg_element) const {
|
||||||
@ -123,7 +135,9 @@ QDateTime IcalParser::objMessageDateCreated(const QVariant& msg_element) const {
|
|||||||
const IcalendarComponent& comp_base = msg_element.value<IcalendarComponent>();
|
const IcalendarComponent& comp_base = msg_element.value<IcalendarComponent>();
|
||||||
const EventComponent& comp = static_cast<const EventComponent&>(comp_base);
|
const EventComponent& comp = static_cast<const EventComponent&>(comp_base);
|
||||||
|
|
||||||
return comp.startsOn();
|
QDateTime dat = comp.startsOn(m_iCalendar.m_tzs);
|
||||||
|
|
||||||
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString IcalParser::objMessageId(const QVariant& msg_element) const {
|
QString IcalParser::objMessageId(const QVariant& msg_element) const {
|
||||||
@ -162,9 +176,9 @@ void Icalendar::setTitle(const QString& title) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Icalendar::processLines(const QString& data) {
|
void Icalendar::processLines(const QString& data) {
|
||||||
QRegularExpression regex("^BEGIN:(\\w+)\\r$(.+?)(?=^BEGIN|^END)",
|
static QRegularExpression regex("^BEGIN:(\\w+)\\r$(.+?)(?=^BEGIN|^END)",
|
||||||
QRegularExpression::PatternOption::MultilineOption |
|
QRegularExpression::PatternOption::MultilineOption |
|
||||||
QRegularExpression::PatternOption::DotMatchesEverythingOption);
|
QRegularExpression::PatternOption::DotMatchesEverythingOption);
|
||||||
|
|
||||||
auto all_matches = regex.globalMatch(data);
|
auto all_matches = regex.globalMatch(data);
|
||||||
|
|
||||||
@ -173,10 +187,16 @@ void Icalendar::processLines(const QString& data) {
|
|||||||
QString component = match.captured(1);
|
QString component = match.captured(1);
|
||||||
QString body = match.captured(2);
|
QString body = match.captured(2);
|
||||||
|
|
||||||
|
// Root calendar component.
|
||||||
if (component == QSL("VCALENDAR")) {
|
if (component == QSL("VCALENDAR")) {
|
||||||
processComponentCalendar(body);
|
processComponentCalendar(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component == QSL("VTIMEZONE")) {
|
||||||
|
processComponentTimezone(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event component.
|
||||||
if (component == QSL("VEVENT")) {
|
if (component == QSL("VEVENT")) {
|
||||||
processComponentEvent(body);
|
processComponentEvent(body);
|
||||||
}
|
}
|
||||||
@ -199,8 +219,20 @@ void Icalendar::processComponentEvent(const QString& body) {
|
|||||||
m_components.append(event);
|
m_components.append(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Icalendar::processComponentTimezone(const QString& body) {
|
||||||
|
auto tokenized = tokenizeBody(body);
|
||||||
|
|
||||||
|
QString tz_id = tokenized.value(QSL("TZID")).toString();
|
||||||
|
|
||||||
|
if (!tz_id.isEmpty()) {
|
||||||
|
m_tzs.insert(tz_id, QTimeZone(tz_id.toLocal8Bit()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap Icalendar::tokenizeBody(const QString& body) const {
|
QVariantMap Icalendar::tokenizeBody(const QString& body) const {
|
||||||
QRegularExpression regex("^(?=[A-Z-]+(?:;[A-Z]+=[A-Z]+)?:)", QRegularExpression::PatternOption::MultilineOption);
|
static QRegularExpression regex("^(?=[A-Z-]+(?:;[A-Z-]+=[A-Z-\\/]+)?:)",
|
||||||
|
QRegularExpression::PatternOption::MultilineOption |
|
||||||
|
QRegularExpression::PatternOption::CaseInsensitiveOption);
|
||||||
auto all_matches = body.split(regex);
|
auto all_matches = body.split(regex);
|
||||||
QVariantMap res;
|
QVariantMap res;
|
||||||
|
|
||||||
@ -215,7 +247,9 @@ QVariantMap Icalendar::tokenizeBody(const QString& body) const {
|
|||||||
QString value = match.mid(sep + 1);
|
QString value = match.mid(sep + 1);
|
||||||
|
|
||||||
value = value.replace(QRegularExpression("\\r\\n\\s?"), QString());
|
value = value.replace(QRegularExpression("\\r\\n\\s?"), QString());
|
||||||
value = value.replace(QRegularExpression("\\\\n"), QSL("<br/>"));
|
value = value.replace(QSL("\\n"), QSL("<br/>"));
|
||||||
|
value = value.replace(QSL("\\,"), QSL(","));
|
||||||
|
value = value.replace(QSL("\\;"), QSL(";"));
|
||||||
|
|
||||||
res.insert(property, value);
|
res.insert(property, value);
|
||||||
}
|
}
|
||||||
@ -236,6 +270,12 @@ void IcalendarComponent::setProperties(const QVariantMap& properties) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QVariant IcalendarComponent::getPropertyValue(const QString& property_name) const {
|
QVariant IcalendarComponent::getPropertyValue(const QString& property_name) const {
|
||||||
|
QString modifier;
|
||||||
|
|
||||||
|
return getPropertyValue(property_name, modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant IcalendarComponent::getPropertyValue(const QString& property_name, QString& property_modifier) const {
|
||||||
if (m_properties.contains(property_name)) {
|
if (m_properties.contains(property_name)) {
|
||||||
return m_properties.value(property_name);
|
return m_properties.value(property_name);
|
||||||
}
|
}
|
||||||
@ -244,45 +284,90 @@ QVariant IcalendarComponent::getPropertyValue(const QString& property_name) cons
|
|||||||
auto linq = boolinq::from(keys.begin(), keys.end());
|
auto linq = boolinq::from(keys.begin(), keys.end());
|
||||||
QString found_key = linq.firstOrDefault([&](const QString& ky) {
|
QString found_key = linq.firstOrDefault([&](const QString& ky) {
|
||||||
int index_sep = ky.indexOf(';');
|
int index_sep = ky.indexOf(';');
|
||||||
|
bool res = ky.startsWith(property_name) && index_sep == property_name.size();
|
||||||
|
|
||||||
return ky.startsWith(property_name) && index_sep == property_name.size();
|
if (res) {
|
||||||
|
property_modifier = ky.mid(index_sep + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
});
|
});
|
||||||
|
|
||||||
return m_properties.value(found_key);
|
return m_properties.value(found_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime EventComponent::startsOn() const {
|
QDateTime IcalendarComponent::fixupDate(QDateTime dat,
|
||||||
return TextFactory::parseDateTime(getPropertyValue(QSL("DTSTART")).toString());
|
const QMap<QString, QTimeZone>& time_zones,
|
||||||
|
const QString& modifiers) const {
|
||||||
|
// dat.setTimeSpec(Qt::TimeSpec::LocalTime);
|
||||||
|
|
||||||
|
// auto xx = dat.toUTC().toString();
|
||||||
|
|
||||||
|
QStringList spl = modifiers.split('=');
|
||||||
|
|
||||||
|
if ((dat.time().hour() > 0 || dat.time().minute() > 0 || dat.time().second() > 0) && spl.size() == 2 &&
|
||||||
|
time_zones.contains(spl.at(1))) {
|
||||||
|
QTimeZone tz = time_zones.value(spl.at(1));
|
||||||
|
|
||||||
|
dat.setTimeSpec(Qt::TimeSpec::TimeZone);
|
||||||
|
dat.setTimeZone(tz);
|
||||||
|
|
||||||
|
/*
|
||||||
|
auto yy = dat.toString();
|
||||||
|
auto aa = dat.timeZone().id();
|
||||||
|
auto zz = dat.toUTC().toString();
|
||||||
|
*/
|
||||||
|
return dat.toUTC();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime EventComponent::endsOn() const {
|
QDateTime EventComponent::startsOn(const QMap<QString, QTimeZone>& time_zones) const {
|
||||||
return TextFactory::parseDateTime(m_properties.value(QSL("DTEND")).toString());
|
QString modifiers;
|
||||||
|
QDateTime dat = TextFactory::parseDateTime(getPropertyValue(QSL("DTSTART"), modifiers).toString());
|
||||||
|
|
||||||
|
return fixupDate(dat, time_zones, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime EventComponent::endsOn(const QMap<QString, QTimeZone>& time_zones) const {
|
||||||
|
QString modifiers;
|
||||||
|
QDateTime dat = TextFactory::parseDateTime(getPropertyValue(QSL("DTEND"), modifiers).toString());
|
||||||
|
|
||||||
|
return fixupDate(dat, time_zones, modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventComponent::title() const {
|
QString EventComponent::title() const {
|
||||||
return m_properties.value(QSL("SUMMARY")).toString();
|
return getPropertyValue(QSL("SUMMARY")).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventComponent::url() const {
|
QString EventComponent::url() const {
|
||||||
return m_properties.value(QSL("URL")).toString();
|
return getPropertyValue(QSL("URL")).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventComponent::organizer() const {
|
QString EventComponent::organizer() const {
|
||||||
return m_properties.value(QSL("ORGANIZER")).toString();
|
return getPropertyValue(QSL("ORGANIZER")).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventComponent::location() const {
|
QString EventComponent::location() const {
|
||||||
return m_properties.value(QSL("LOCATION")).toString();
|
return getPropertyValue(QSL("LOCATION")).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventComponent::description() const {
|
QString EventComponent::description() const {
|
||||||
return m_properties.value(QSL("DESCRIPTION")).toString();
|
return getPropertyValue(QSL("DESCRIPTION")).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime EventComponent::created() const {
|
QDateTime EventComponent::created(const QMap<QString, QTimeZone>& time_zones) const {
|
||||||
return TextFactory::parseDateTime(m_properties.value(QSL("CREATED")).toString());
|
QString modifiers;
|
||||||
|
QDateTime dat = TextFactory::parseDateTime(getPropertyValue(QSL("CREATED"), modifiers).toString());
|
||||||
|
|
||||||
|
return fixupDate(dat, time_zones, modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime EventComponent::lastModified() const {
|
QDateTime EventComponent::lastModified(const QMap<QString, QTimeZone>& time_zones) const {
|
||||||
return TextFactory::parseDateTime(m_properties.value(QSL("LAST-MODIFIED")).toString());
|
QString modifiers;
|
||||||
|
QDateTime dat = TextFactory::parseDateTime(getPropertyValue(QSL("LAST-MODIFIED"), modifiers).toString());
|
||||||
|
|
||||||
|
return fixupDate(dat, time_zones, modifiers);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "services/standard/parsers/feedparser.h"
|
#include "services/standard/parsers/feedparser.h"
|
||||||
|
|
||||||
|
#include <QTimeZone>
|
||||||
|
|
||||||
class IcalendarComponent {
|
class IcalendarComponent {
|
||||||
public:
|
public:
|
||||||
QString uid() const;
|
QString uid() const;
|
||||||
@ -14,6 +16,9 @@ class IcalendarComponent {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
QVariant getPropertyValue(const QString& property_name) const;
|
QVariant getPropertyValue(const QString& property_name) const;
|
||||||
|
QVariant getPropertyValue(const QString& property_name, QString& property_modifier) const;
|
||||||
|
|
||||||
|
QDateTime fixupDate(QDateTime dat, const QMap<QString, QTimeZone>& time_zones, const QString& modifiers) const;
|
||||||
|
|
||||||
QVariantMap m_properties;
|
QVariantMap m_properties;
|
||||||
};
|
};
|
||||||
@ -22,15 +27,15 @@ Q_DECLARE_METATYPE(IcalendarComponent)
|
|||||||
|
|
||||||
class EventComponent : public IcalendarComponent {
|
class EventComponent : public IcalendarComponent {
|
||||||
public:
|
public:
|
||||||
QDateTime startsOn() const;
|
QDateTime startsOn(const QMap<QString, QTimeZone>& time_zones = {}) const;
|
||||||
QDateTime endsOn() const;
|
QDateTime endsOn(const QMap<QString, QTimeZone>& time_zones = {}) const;
|
||||||
QString title() const;
|
QString title() const;
|
||||||
QString url() const;
|
QString url() const;
|
||||||
QString organizer() const;
|
QString organizer() const;
|
||||||
QString location() const;
|
QString location() const;
|
||||||
QString description() const;
|
QString description() const;
|
||||||
QDateTime created() const;
|
QDateTime created(const QMap<QString, QTimeZone>& time_zones = {}) const;
|
||||||
QDateTime lastModified() const;
|
QDateTime lastModified(const QMap<QString, QTimeZone>& time_zones = {}) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(EventComponent)
|
Q_DECLARE_METATYPE(EventComponent)
|
||||||
@ -48,12 +53,14 @@ class Icalendar : public FeedParser {
|
|||||||
void processLines(const QString& data);
|
void processLines(const QString& data);
|
||||||
void processComponentCalendar(const QString& body);
|
void processComponentCalendar(const QString& body);
|
||||||
void processComponentEvent(const QString& body);
|
void processComponentEvent(const QString& body);
|
||||||
|
void processComponentTimezone(const QString& body);
|
||||||
|
|
||||||
QDateTime parseDateTime(const QString& date_time) const;
|
QDateTime parseDateTime(const QString& date_time) const;
|
||||||
QVariantMap tokenizeBody(const QString& body) const;
|
QVariantMap tokenizeBody(const QString& body) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_title;
|
QString m_title;
|
||||||
|
QMap<QString, QTimeZone> m_tzs;
|
||||||
QList<IcalendarComponent> m_components;
|
QList<IcalendarComponent> m_components;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user