diff --git a/plugins/messageviewer/bodypartformatter/semantic/semanticrenderer.cpp b/plugins/messageviewer/bodypartformatter/semantic/semanticrenderer.cpp index 9a2f596b..26a9e2d4 100644 --- a/plugins/messageviewer/bodypartformatter/semantic/semanticrenderer.cpp +++ b/plugins/messageviewer/bodypartformatter/semantic/semanticrenderer.cpp @@ -1,194 +1,201 @@ /* Copyright (c) 2017 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "semanticrenderer.h" #include "semanticmemento.h" #include "semantic_debug.h" #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KItinerary; // Grantlee has no Q_GADGET support yet #define GRANTLEE_MAKE_GADGET(Class) \ GRANTLEE_BEGIN_LOOKUP(Class) \ const auto idx = Class::staticMetaObject.indexOfProperty(property.toUtf8().constData()); \ if (idx < 0) { \ return {};} \ const auto mp = Class::staticMetaObject.property(idx); \ return mp.readOnGadget(&object); \ GRANTLEE_END_LOOKUP GRANTLEE_MAKE_GADGET(Airport) GRANTLEE_MAKE_GADGET(Airline) +GRANTLEE_MAKE_GADGET(Event) +GRANTLEE_MAKE_GADGET(EventReservation) GRANTLEE_MAKE_GADGET(Flight) GRANTLEE_MAKE_GADGET(FlightReservation) GRANTLEE_MAKE_GADGET(LodgingBusiness) GRANTLEE_MAKE_GADGET(LodgingReservation) GRANTLEE_MAKE_GADGET(Person) +GRANTLEE_MAKE_GADGET(Place) GRANTLEE_MAKE_GADGET(PostalAddress) GRANTLEE_MAKE_GADGET(Seat) GRANTLEE_MAKE_GADGET(Ticket) GRANTLEE_MAKE_GADGET(TrainStation) GRANTLEE_MAKE_GADGET(TrainTrip) GRANTLEE_MAKE_GADGET(TrainReservation) GRANTLEE_MAKE_GADGET(BusStation) GRANTLEE_MAKE_GADGET(BusTrip) GRANTLEE_MAKE_GADGET(BusReservation) GRANTLEE_MAKE_GADGET(CancelAction) GRANTLEE_MAKE_GADGET(CheckInAction) GRANTLEE_MAKE_GADGET(DownloadAction) GRANTLEE_MAKE_GADGET(UpdateAction) GRANTLEE_MAKE_GADGET(ViewAction) SemanticRenderer::SemanticRenderer() { Grantlee::registerMetaType(); Grantlee::registerMetaType(); + Grantlee::registerMetaType(); + Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); + Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); } bool SemanticRenderer::render(const MimeTreeParser::MessagePartPtr &msgPart, MessageViewer::HtmlWriter *htmlWriter, MessageViewer::RenderContext *context) const { Q_UNUSED(context); const auto mpList = msgPart.dynamicCast(); if (!msgPart->isRoot() || !mpList->hasSubParts()) { return false; } const auto node = mpList->subParts().at(0)->content(); const auto nodeHelper = msgPart->nodeHelper(); if (!nodeHelper || !node) { return false; } auto memento = dynamic_cast(nodeHelper->bodyPartMemento(node->topLevel(), "org.kde.messageviewer.semanticData")); if (!memento || !memento->hasData()) { return false; } const auto extractedData = memento->data(); if (extractedData.isEmpty()) { // hasData() will not be correct for filtered structured data on the first pass through here... return false; } const auto dir = nodeHelper->createTempDir(QStringLiteral("semantic")); auto c = MessageViewer::MessagePartRendererManager::self()->createContext(); const auto pal = qGuiApp->palette(); QVariantMap style; style.insert(QStringLiteral("frameColor"), pal.link().color().name()); style.insert(QStringLiteral("expandIcon"), QLatin1String("file://") + MessageViewer::IconNameCache::instance()->iconPathFromLocal(QStringLiteral("quoteexpand.png"))); style.insert(QStringLiteral("collapseIcon"), QLatin1String("file://") + MessageViewer::IconNameCache::instance()->iconPathFromLocal(QStringLiteral("quotecollapse.png"))); c.insert(QStringLiteral("style"), style); // Grantlee can't do indexed map/array lookups, so we need to interleave this here already QVariantList elems; elems.reserve(extractedData.size()); for (int i = 0; i < extractedData.size(); ++i) { QVariantMap data; QVariantMap state; const auto d = extractedData.at(i); state.insert(QStringLiteral("expanded"), d.expanded); data.insert(QStringLiteral("state"), state); data.insert(QStringLiteral("groupId"), i); QVector reservations; for (const auto &r : d.reservations) { QVariantMap m; m.insert(QStringLiteral("reservation"), r); // generate ticket barcodes const auto ticket = JsonLd::convert(r).reservedTicket().value(); std::unique_ptr barcode; switch (ticket.ticketTokenType()) { case Ticket::AztecCode: barcode.reset(Prison::createBarcode(Prison::Aztec)); barcode->setData(ticket.ticketTokenData()); break; case Ticket::QRCode: barcode.reset(Prison::createBarcode(Prison::QRCode)); barcode->setData(ticket.ticketTokenData()); break; default: break; } if (barcode) { barcode->toImage(barcode->minimumSize()); // minimumSize is only available after we rendered once... const auto img = barcode->toImage(barcode->minimumSize()); const auto fileName = dir + QStringLiteral("/ticketToken") + QString::number(i) + QStringLiteral(".png"); img.save(fileName); m.insert(QStringLiteral("ticketToken"), fileName); nodeHelper->addTempFile(fileName); } reservations.push_back(m); } data.insert(QStringLiteral("reservations"), QVariant::fromValue(reservations)); elems.push_back(data); } c.insert(QStringLiteral("data"), elems); auto t = MessageViewer::MessagePartRendererManager::self()->loadByName(QStringLiteral(":/org.kde.messageviewer/semantic/semantic.html")); const_cast(t->engine())->addDefaultLibrary(QStringLiteral("kitinerary_grantlee_extension")); Grantlee::OutputStream s(htmlWriter->stream()); t->render(&s, &c); return false; // yes, false, we want the rest of the email rendered normally after this } diff --git a/plugins/messageviewer/bodypartformatter/semantic/templates.qrc b/plugins/messageviewer/bodypartformatter/semantic/templates.qrc index 401cc41c..a5f3e851 100644 --- a/plugins/messageviewer/bodypartformatter/semantic/templates.qrc +++ b/plugins/messageviewer/bodypartformatter/semantic/templates.qrc @@ -1,10 +1,11 @@ templates/semantic.html templates/flightreservation.html templates/lodgingreservation.html templates/trainreservation.html templates/busreservation.html + templates/event.html templates/actions.html diff --git a/plugins/messageviewer/bodypartformatter/semantic/templates/event.html b/plugins/messageviewer/bodypartformatter/semantic/templates/event.html new file mode 100644 index 00000000..8ae39f25 --- /dev/null +++ b/plugins/messageviewer/bodypartformatter/semantic/templates/event.html @@ -0,0 +1,8 @@ +
{{ trip.name }}
+
+ {{ trip.startDate|formatDateTime }}
+ {{ trip.location.name }}
+ {{ trip.location.address|formatAddress|safe }} +
+{% include ":/org.kde.messageviewer/semantic/actions.html" %} +
diff --git a/plugins/messageviewer/bodypartformatter/semantic/templates/semantic.html b/plugins/messageviewer/bodypartformatter/semantic/templates/semantic.html index 09f8e4f5..e145aa99 100644 --- a/plugins/messageviewer/bodypartformatter/semantic/templates/semantic.html +++ b/plugins/messageviewer/bodypartformatter/semantic/templates/semantic.html @@ -1,24 +1,26 @@
{% for elem in data %} {% with elem.reservations.0.reservation as res %} {% with elem.reservations.0.reservation.reservationFor as trip %} {% if res.className == "FlightReservation" %} {% include ":/org.kde.messageviewer/semantic/flightreservation.html" %} {% elif res.className == "LodgingReservation" %} {% include ":/org.kde.messageviewer/semantic/lodgingreservation.html" %} {% elif res.className == "TrainReservation" %} {% include ":/org.kde.messageviewer/semantic/trainreservation.html" %} {% elif res.className == "BusReservation" %} {% include ":/org.kde.messageviewer/semantic/busreservation.html" %} + {% elif res.className == "EventReservation" %} + {% include ":/org.kde.messageviewer/semantic/event.html" %} {% endif %} {% if not forloop.last %}
{% endif %} {% endwith %} {% endwith %} {% endfor %}