diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 66180df..6a27f2d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,19 +1,20 @@ set(workbench_srcs main.cpp mainwindow.cpp attributemodel.cpp dommodel.cpp + extractoreditorwidget.cpp uic9183ticketlayoutmodel.cpp ) add_executable(kitinerary-workbench ${workbench_srcs}) target_link_libraries(kitinerary-workbench KPim::Itinerary KPim::PkPass KF5::KIOWidgets KF5::TextEditor ) install(TARGETS kitinerary-workbench ${INSTALL_TARGETS_DEFAULT_ARGS}) install(PROGRAMS org.kde.kitinerary-workbench.desktop DESTINATION ${KDE_INSTALL_APPDIR}) install(FILES org.kde.kitinerary-workbench.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) diff --git a/src/extractoreditorwidget.cpp b/src/extractoreditorwidget.cpp new file mode 100644 index 0000000..043eb57 --- /dev/null +++ b/src/extractoreditorwidget.cpp @@ -0,0 +1,67 @@ +/* + Copyright (C) 2019 Volker Krause + + This program 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 program 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 General Public License + along with this program. If not, see . +*/ + +#include "extractoreditorwidget.h" +#include "ui_extractoreditorwidget.h" + +#include +#include + +#include +#include +#include + +#include + +using namespace KItinerary; + +ExtractorEditorWidget::ExtractorEditorWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::ExtractorEditorWidget) +{ + ui->setupUi(this); + + connect(ui->extractorCombobox, qOverload(&QComboBox::currentIndexChanged), this, [this]() { + ExtractorRepository repo; + const auto extId = ui->extractorCombobox->currentText(); + const auto extractor = repo.extractor(extId); + m_scriptDoc->openUrl(QUrl::fromLocalFile(extractor.scriptFileName())); + }); + connect(ui->reloadButton, &QPushButton::clicked, this, [this]() { + ExtractorRepository repo; + repo.reload(); + reloadExtractors(); + }); + + auto editor = KTextEditor::Editor::instance(); + m_scriptDoc = editor->createDocument(nullptr); + m_scriptDoc->setHighlightingMode(QStringLiteral("JavaScript")); + auto view = m_scriptDoc->createView(nullptr); + ui->topLayout->addWidget(view); + reloadExtractors(); +} + +ExtractorEditorWidget::~ExtractorEditorWidget() = default; + +void ExtractorEditorWidget::reloadExtractors() +{ + ui->extractorCombobox->clear(); + ExtractorRepository repo; + for (const auto &ext : repo.allExtractors()) { + ui->extractorCombobox->addItem(ext.name()); + } +} diff --git a/src/extractoreditorwidget.h b/src/extractoreditorwidget.h new file mode 100644 index 0000000..802c915 --- /dev/null +++ b/src/extractoreditorwidget.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2019 Volker Krause + + This program 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 program 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 General Public License + along with this program. If not, see . +*/ + +#ifndef EXTRACTOREDITORWIDGET_H +#define EXTRACTOREDITORWIDGET_H + +#include + +#include + +namespace KTextEditor { +class Document; +} + +class Ui_ExtractorEditorWidget; + +class ExtractorEditorWidget : public QWidget +{ + Q_OBJECT +public: + explicit ExtractorEditorWidget(QWidget *parent = nullptr); + ~ExtractorEditorWidget(); + +private: + void reloadExtractors(); + + std::unique_ptr ui; + + KTextEditor::Document *m_scriptDoc = nullptr; +}; + +#endif // EXTRACTOREDITORWIDGET_H diff --git a/src/extractoreditorwidget.ui b/src/extractoreditorwidget.ui new file mode 100644 index 0000000..d4f26bb --- /dev/null +++ b/src/extractoreditorwidget.ui @@ -0,0 +1,57 @@ + + + ExtractorEditorWidget + + + + 0 + 0 + 400 + 300 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Extractor: + + + extractorCombobox + + + + + + + + + + Reload + + + + + + + + + + diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 83e6481..38336a0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,470 +1,470 @@ /* Copyright (C) 2018 Volker Krause This program 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 program 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 General Public License along with this program. If not, see . */ #include "mainwindow.h" #include "ui_mainwindow.h" #include "attributemodel.h" #include "dommodel.h" #include "uic9183ticketlayoutmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_imageModel(new QStandardItemModel(this)) , m_domModel(new DOMModel(this)) , m_attrModel(new AttributeModel(this)) , m_uic9183BlockModel(new QStandardItemModel(this)) , m_ticketLayoutModel(new Uic9183TicketLayoutModel(this)) { ui->setupUi(this); ui->contextDate->setDateTime(QDateTime(QDate::currentDate(), QTime())); setCentralWidget(ui->mainSplitter); connect(ui->typeBox, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::typeChanged); connect(ui->typeBox, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::sourceChanged); connect(ui->senderBox, &QComboBox::currentTextChanged, this, &MainWindow::sourceChanged); connect(ui->contextDate, &QDateTimeEdit::dateTimeChanged, this, &MainWindow::sourceChanged); connect(ui->fileRequester, &KUrlRequester::textChanged, this, &MainWindow::urlChanged); auto editor = KTextEditor::Editor::instance(); m_sourceDoc = editor->createDocument(nullptr); connect(m_sourceDoc, &KTextEditor::Document::textChanged, this, &MainWindow::sourceChanged); m_sourceView = m_sourceDoc->createView(nullptr); ui->sourceTab->layout()->addWidget(m_sourceView); m_preprocDoc = editor->createDocument(nullptr); auto view = m_preprocDoc->createView(nullptr); auto layout = new QHBoxLayout(ui->preprocTab); layout->addWidget(view); m_imageModel->setHorizontalHeaderLabels({tr("Image")}); ui->imageView->setModel(m_imageModel); connect(ui->imageView, &QWidget::customContextMenuRequested, this, &MainWindow::imageContextMenu); ui->domView->setModel(m_domModel); ui->domView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); ui->attributeView->setModel(m_attrModel); ui->attributeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); connect(ui->domView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this](const QItemSelection &selection) { auto idx = selection.value(0).topLeft(); m_attrModel->setElement(idx.data(Qt::UserRole).value()); QString path; idx = idx.sibling(idx.row(), 0); while (idx.isValid()) { path.prepend(QLatin1Char('/') + idx.data(Qt::DisplayRole).toString()); idx = idx.parent(); } ui->domPath->setText(path); }); ui->domSplitter->setStretchFactor(0, 5); ui->domSplitter->setStretchFactor(1, 1); connect(ui->xpathEdit, &QLineEdit::editingFinished, this, [this]() { if (!m_htmlDoc) { return; } const auto res = m_htmlDoc->eval(ui->xpathEdit->text()); if (!res.canConvert()) { // TODO show this properly in the UI somehow qDebug() << "XPath result:" << res; } m_domModel->setHighlightNodeSet(res.value()); ui->domView->viewport()->update(); // dirty, but easier than triggering a proper full model update }); m_uic9183BlockModel->setHorizontalHeaderLabels({tr("Block"), tr("Version"), tr("Content")}); ui->uic9183BlockView->setModel(m_uic9183BlockModel); ui->uic9183BlockView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); connect(ui->uic9183BlockView, &QTreeView::customContextMenuRequested, this, [this](QPoint pos) { auto idx = ui->uic9183BlockView->currentIndex(); if (!idx.isValid()) return; idx = idx.sibling(idx.row(), 2); QMenu menu; const auto copyContent = menu.addAction(tr("Copy Content")); auto action = menu.exec(ui->uic9183BlockView->viewport()->mapToGlobal(pos)); if (action == copyContent) { auto md = new QMimeData; md->setData(QStringLiteral("application/octet-stream"), idx.data(Qt::EditRole).toByteArray()); QGuiApplication::clipboard()->setMimeData(md); } }); ui->ticketLayoutView->setModel(m_ticketLayoutModel); QFontMetrics fm(font()); const auto cellWidth = fm.boundingRect(QStringLiteral("m")).width() + 6; ui->ticketLayoutView->horizontalHeader()->setMinimumSectionSize(cellWidth); ui->ticketLayoutView->horizontalHeader()->setDefaultSectionSize(cellWidth); ui->ticketLayoutView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); ui->ticketLayoutView->verticalHeader()->setMinimumSectionSize(fm.height()); ui->ticketLayoutView->verticalHeader()->setMinimumSectionSize(fm.height()); ui->ticketLayoutView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); connect(ui->ticketLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this]() { const auto sel = ui->ticketLayoutView->selectionModel()->selection(); if (sel.isEmpty()) { ui->ticketLayoutSelection->clear(); } else { const auto range = sel.at(0); ui->ticketLayoutSelection->setText(i18n("Row: %1 Column: %2 Width: %3 Height: %4", range.top(), range.left(), range.right() - range.left() + 1, range.bottom() - range.top() + 1)); } }); m_outputDoc = editor->createDocument(nullptr); m_outputDoc->setMode(QStringLiteral("JSON")); view = m_outputDoc->createView(nullptr); layout = new QHBoxLayout(ui->outputTab); layout->addWidget(view); m_postprocDoc = editor->createDocument(nullptr); m_postprocDoc->setMode(QStringLiteral("JSON")); view = m_postprocDoc->createView(nullptr); layout = new QHBoxLayout(ui->postprocTab); layout->addWidget(view); m_icalDoc = editor->createDocument(nullptr); m_icalDoc->setMode(QStringLiteral("vCard, vCalendar, iCalendar")); view = m_icalDoc->createView(nullptr); layout = new QHBoxLayout(ui->icalTab); layout->addWidget(view); typeChanged(); QSettings settings; settings.beginGroup(QLatin1String("MainWindow")); restoreGeometry(settings.value(QLatin1String("Geometry")).toByteArray()); restoreState(settings.value(QLatin1String("State")).toByteArray()); settings.endGroup(); settings.beginGroup(QLatin1String("SenderHistory")); ui->senderBox->addItems(settings.value(QLatin1String("History")).toStringList()); ui->senderBox->setCurrentText(QString()); ui->actionReload->setShortcut(QKeySequence::Refresh); ui->actionQuit->setShortcut(QKeySequence::Quit); connect(ui->actionReload, &QAction::triggered, this, &MainWindow::sourceChanged); connect(ui->actionQuit, &QAction::triggered, QCoreApplication::instance(), &QCoreApplication::quit); } MainWindow::~MainWindow() { QSettings settings; settings.beginGroup(QLatin1String("SenderHistory")); QStringList history; history.reserve(ui->senderBox->count()); for (int i = 0; i < ui->senderBox->count(); ++i) history.push_back(ui->senderBox->itemText(i)); settings.setValue(QLatin1String("History"), history); settings.endGroup(); settings.beginGroup(QLatin1String("MainWindow")); settings.setValue(QLatin1String("Geometry"), saveGeometry()); settings.setValue(QLatin1String("State"), saveState()); } void MainWindow::openFile(const QString &file) { ui->fileRequester->setText(file); } void MainWindow::typeChanged() { - ui->inputTabWidget->setTabEnabled(1, false); - ui->inputTabWidget->setTabEnabled(2, false); - ui->inputTabWidget->setTabEnabled(3, false); - ui->inputTabWidget->setTabEnabled(4, false); - ui->inputTabWidget->setTabEnabled(5, false); + ui->inputTabWidget->setTabEnabled(TextTab, false); + ui->inputTabWidget->setTabEnabled(ImageTab, false); + ui->inputTabWidget->setTabEnabled(DomTab, false); + ui->inputTabWidget->setTabEnabled(Uic9183DataTab, false); + ui->inputTabWidget->setTabEnabled(Uic9183LayoutTab, false); ui->outputTabWidget->setTabEnabled(0, true); switch (ui->typeBox->currentIndex()) { case PlainText: case IataBcbp: m_sourceDoc->setMode(QStringLiteral("Normal")); m_sourceView->show(); break; case Uic9183: m_sourceDoc->setMode(QStringLiteral("Normal")); m_sourceView->show(); - ui->inputTabWidget->setTabEnabled(4, true); - ui->inputTabWidget->setTabEnabled(5, true); + ui->inputTabWidget->setTabEnabled(Uic9183DataTab, true); + ui->inputTabWidget->setTabEnabled(Uic9183LayoutTab, true); break; case Html: m_sourceDoc->setMode(QStringLiteral("HTML")); m_sourceView->show(); - ui->inputTabWidget->setTabEnabled(1, true); - ui->inputTabWidget->setTabEnabled(3, true); + ui->inputTabWidget->setTabEnabled(TextTab, true); + ui->inputTabWidget->setTabEnabled(DomTab, true); break; case Pdf: case Image: - ui->inputTabWidget->setTabEnabled(1, true); - ui->inputTabWidget->setTabEnabled(2, true); + ui->inputTabWidget->setTabEnabled(TextTab, true); + ui->inputTabWidget->setTabEnabled(ImageTab, true); m_sourceView->hide(); break; case PkPass: m_sourceView->hide(); break; case JsonLd: m_sourceDoc->setMode(QStringLiteral("JSON")); m_sourceView->show(); ui->outputTabWidget->setTabEnabled(0, false); break; case ICal: m_sourceDoc->setMode(QStringLiteral("vCard, vCalendar, iCalendar")); m_sourceView->show(); break; case Mime: m_sourceDoc->setMode(QStringLiteral("Email")); m_sourceView->show(); break; } } void MainWindow::sourceChanged() { m_imageModel->removeRows(0, m_imageModel->rowCount()); m_uic9183BlockModel->removeRows(0, m_uic9183BlockModel->rowCount()); using namespace KItinerary; QJsonArray data; if (ui->typeBox->currentIndex() == IataBcbp) { const auto bp = IataBcbpParser::parse(m_sourceDoc->text(), ui->contextDate->date()); data = JsonLdDocument::toJson({bp}); } else if (ui->typeBox->currentIndex() == Uic9183) { m_ticketParser.setContextDate(ui->contextDate->dateTime()); m_ticketParser.parse(m_sourceDoc->text().toLatin1()); data = {JsonLdDocument::toJson(QVariant::fromValue(m_ticketParser))}; m_ticketLayoutModel->setLayout(m_ticketParser.ticketLayout()); auto block = m_ticketParser.firstBlock(); while (!block.isNull()) { auto nameItem = new QStandardItem(QString::fromUtf8(block.name(), 6)); auto versionItem = new QStandardItem(QString::number(block.version())); auto contentItem = new QStandardItem; contentItem->setData(QByteArray(block.content(), block.contentSize()), Qt::EditRole); contentItem->setData(QString::fromUtf8(block.content(), block.contentSize()), Qt::DisplayRole); m_uic9183BlockModel->appendRow({nameItem, versionItem, contentItem}); block = block.nextBlock(); } } else if (ui->typeBox->currentIndex() == PkPass && m_pkpass) { ExtractorEngine engine; engine.setContextDate(ui->contextDate->dateTime()); engine.setPass(m_pkpass.get()); data = engine.extract(); } else if (ui->typeBox->currentIndex() == JsonLd) { const auto doc = QJsonDocument::fromJson(m_sourceDoc->text().toUtf8()); if (doc.isArray()) data = doc.array(); else if (doc.isObject()) data = {doc.object()}; } else if (ui->typeBox->currentIndex() == Image) { auto item = new QStandardItem; item->setData(m_image, Qt::DecorationRole); m_imageModel->appendRow(item); } else { ExtractorEngine engine; m_preprocDoc->setReadWrite(true); if (ui->typeBox->currentIndex() == PlainText) { engine.setText(m_sourceDoc->text()); m_preprocDoc->setText(m_sourceDoc->text()); } else if (ui->typeBox->currentIndex() == Html) { auto codec = QTextCodec::codecForName(m_sourceDoc->encoding().toUtf8()); if (!codec) { codec = QTextCodec::codecForLocale(); } m_htmlDoc.reset(HtmlDocument::fromData(codec->fromUnicode(m_sourceDoc->text()))); engine.setHtmlDocument(m_htmlDoc.get()); if (m_htmlDoc) m_preprocDoc->setText(m_htmlDoc->root().recursiveContent()); else m_preprocDoc->clear(); m_domModel->setDocument(m_htmlDoc.get()); ui->domView->expandAll(); } else if (ui->typeBox->currentIndex() == Pdf && m_pdfDoc) { engine.setPdfDocument(m_pdfDoc.get()); m_preprocDoc->setText(m_pdfDoc->text()); for (int i = 0; i < m_pdfDoc->pageCount(); ++i) { auto pageItem = new QStandardItem; pageItem->setText(i18n("Page %1", i + 1)); const auto page = m_pdfDoc->page(i); for (int j = 0; j < page.imageCount(); ++j) { auto imgItem = new QStandardItem; imgItem->setData(page.image(j).image(), Qt::DecorationRole); pageItem->appendRow(imgItem); } m_imageModel->appendRow(pageItem); } ui->imageView->expandAll(); } else if (ui->typeBox->currentIndex() == ICal) { m_calendar.reset(new KCalendarCore::MemoryCalendar(QTimeZone::systemTimeZone())); KCalendarCore::ICalFormat format; format.fromString(m_calendar, m_sourceDoc->text()); m_calendar->setProductId(format.loadedProductId()); engine.setCalendar(m_calendar); } else if (ui->typeBox->currentIndex() == Mime) { m_mimeMessage.reset(new KMime::Message); m_mimeMessage->setContent(m_sourceDoc->text().toUtf8()); m_mimeMessage->parse(); engine.setContent(m_mimeMessage.get()); } m_preprocDoc->setReadWrite(false); KMime::Message msg; if (ui->typeBox->currentIndex() != Mime) { msg.from()->fromUnicodeString(ui->senderBox->currentText(), "utf-8"); msg.date()->setDateTime(ui->contextDate->dateTime()); engine.setContext(&msg); } data = engine.extract(); } m_outputDoc->setReadWrite(true); m_outputDoc->setText(QJsonDocument(data).toJson()); m_outputDoc->setReadWrite(false); ExtractorPostprocessor postproc; postproc.setContextDate(ui->contextDate->dateTime()); postproc.process(JsonLdDocument::fromJson(data)); m_postprocDoc->setReadWrite(true); m_postprocDoc->setText(QJsonDocument(JsonLdDocument::toJson(postproc.result())).toJson()); m_postprocDoc->setReadWrite(false); KCalendarCore::Calendar::Ptr cal(new KCalendarCore::MemoryCalendar(QTimeZone::systemTimeZone())); for (const auto &res : postproc.result()) { KCalendarCore::Event::Ptr event(new KCalendarCore::Event); CalendarHandler::fillEvent({res}, event); // TODO this assumes multi-traveller batching to have already happened! cal->addEvent(event); } KCalendarCore::ICalFormat format; m_icalDoc->setText(format.toString(cal)); } void MainWindow::urlChanged() { const auto url = ui->fileRequester->url(); if (!url.isValid()) return; if (url.toString().endsWith(QLatin1String(".pkpass"))) { m_pkpass.reset(KPkPass::Pass::fromFile(url.toLocalFile())); ui->typeBox->setCurrentIndex(PkPass); sourceChanged(); } else if (url.toString().endsWith(QLatin1String(".pdf"))) { QFile f(url.toLocalFile()); f.open(QFile::ReadOnly); m_pdfDoc.reset(KItinerary::PdfDocument::fromData(f.readAll())); ui->typeBox->setCurrentIndex(Pdf); sourceChanged(); } else if (url.toString().endsWith(QLatin1String(".html"))) { QFile f(url.toLocalFile()); f.open(QFile::ReadOnly); m_htmlDoc.reset(KItinerary::HtmlDocument::fromData(f.readAll())); ui->typeBox->setCurrentIndex(Html); m_domModel->setDocument(m_htmlDoc.get()); ui->domView->expandAll(); m_sourceDoc->openUrl(url); } else if (url.toString().endsWith(QLatin1String(".png")) || url.toString().endsWith(QLatin1String(".jpg"))) { m_image.load(url.toLocalFile()); sourceChanged(); } else if (url.toString().endsWith(QLatin1String(".ics"))) { ui->typeBox->setCurrentIndex(ICal); m_sourceDoc->openUrl(url); } else if (url.toString().endsWith(QLatin1String(".eml")) || url.toString().endsWith(QLatin1String(".mbox"))) { ui->typeBox->setCurrentIndex(Mime); m_sourceDoc->openUrl(url); } else { m_sourceDoc->openUrl(url); } } void MainWindow::imageContextMenu(QPoint pos) { using namespace KItinerary; const auto idx = ui->imageView->currentIndex(); if (!idx.isValid()) return; QMenu menu; const auto barcode = menu.addAction(tr("Decode Barcode")); const auto barcodeBinary = menu.addAction(tr("Decode Barcode (Binary)")); menu.addSeparator(); const auto save = menu.addAction(tr("Save...")); if (auto action = menu.exec(ui->imageView->viewport()->mapToGlobal(pos))) { QString code; if (action == barcode) { BarcodeDecoder decoder; code = decoder.decodeString(idx.data(Qt::DecorationRole).value()); } else if (action == barcodeBinary) { BarcodeDecoder decoder; const auto b = decoder.decodeBinary(idx.data(Qt::DecorationRole).value()); code = QString::fromLatin1(b.constData(), b.size()); } else if (action == save) { const auto fileName = QFileDialog::getSaveFileName(this, tr("Save Image")); idx.data(Qt::DecorationRole).value().save(fileName); } m_sourceDoc->setText(code); if (IataBcbpParser::maybeIataBcbp(code)) { ui->typeBox->setCurrentIndex(IataBcbp); } else if (Uic9183Parser::maybeUic9183(code.toLatin1())) { ui->typeBox->setCurrentIndex(Uic9183); } } } diff --git a/src/mainwindow.h b/src/mainwindow.h index 099eba2..3af55dd 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1,113 +1,123 @@ /* Copyright (C) 2018 Volker Krause This program 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 program 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 General Public License along with this program. If not, see . */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include namespace KItinerary { class HtmlDocument; class PdfDocument; } namespace KPkPass { class Pass; } namespace KMime { class Message; } namespace KTextEditor { class Document; class View; } namespace Ui { class MainWindow; } class AttributeModel; class DOMModel; class Uic9183TicketLayoutModel; class QStandardItemModel; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); void openFile(const QString &file); private: enum Type { PlainText, Html, Pdf, PkPass, IataBcbp, JsonLd, Uic9183, Image, ICal, Mime }; + enum Tab { + ExtractorEditorTab = 0, + InputTab = 1, + TextTab = 2, + ImageTab = 3, + DomTab = 4, + Uic9183DataTab = 5, + Uic9183LayoutTab = 6 + }; + void typeChanged(); void sourceChanged(); void urlChanged(); void imageContextMenu(QPoint pos); private: std::unique_ptr ui; KTextEditor::Document *m_sourceDoc = nullptr; KTextEditor::Document *m_preprocDoc = nullptr; KTextEditor::Document *m_outputDoc = nullptr; KTextEditor::Document *m_postprocDoc = nullptr; KTextEditor::Document *m_icalDoc = nullptr; KTextEditor::View *m_sourceView = nullptr; QStandardItemModel *m_imageModel; DOMModel *m_domModel; AttributeModel *m_attrModel; QStandardItemModel *m_uic9183BlockModel; Uic9183TicketLayoutModel *m_ticketLayoutModel; std::unique_ptr m_pkpass; std::unique_ptr m_htmlDoc; std::unique_ptr m_pdfDoc; QImage m_image; KCalendarCore::Calendar::Ptr m_calendar; std::unique_ptr m_mimeMessage; KItinerary::Uic9183Parser m_ticketParser; KItinerary::Uic9183TicketLayout m_ticketLayout; }; #endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 56a9076..e4b4d23 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1,328 +1,344 @@ MainWindow 0 0 981 689 KItinerary Workbench Qt::Horizontal - 0 + 1 + + + Extractor + + + + + + + Input Source t&ype: typeBox Plain Text HTML PDF PkPass IATA BCBP JSON-LD UIC 918.3 Image iCalendar MIME File: Se&nder: senderBox 0 0 true QComboBox::InsertAlphabetically Conte&xt date: contextDate Text Images Qt::CustomContextMenu false DOM XPath Query true Qt::Vertical 8 false UIC 918-3 Data Qt::CustomContextMenu false false UIC 918-3 Layout QAbstractItemView::ContiguousSelection 1 Extractor Post-processed iCal 0 0 981 30 &File ../../ &Re-run Extractor ../../ &Quit KUrlRequester QWidget
KUrlRequester
1
+ + ExtractorEditorWidget + QWidget +
extractoreditorwidget.h
+ 1 +