/**
* Relational pipes
* Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* 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 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 <http://www.gnu.org/licenses/>.
*/
#include <sys/prctl.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <QApplication>
#include <QThread>
#include <relpipe/cli/CLI.h>
#include <relpipe/cli/RelpipeCLIException.h>
#include <relpipe/reader/Factory.h>
#include <relpipe/reader/RelationalReader.h>
#include <relpipe/reader/RelpipeReaderException.h>
#include "RelpipeChartMainWindow.h"
#include "QtRelationalReaderStringHandler.h"
using namespace relpipe::cli;
using namespace relpipe::reader;
// signal/slot parameters must be declared here and registered with qRegisterMetaType()
Q_DECLARE_METATYPE(string_t)
Q_DECLARE_METATYPE(std::vector<AttributeMetadata>)
class RelationalReaderThread : public QThread {
private:
std::shared_ptr<RelationalReader> reader;
public:
// TODO: better background thread; lambda?
RelationalReaderThread(std::shared_ptr<RelationalReader> reader) :
reader(reader) {
setTerminationEnabled(true);
}
void run() {
try {
reader->process();
} catch (RelpipeReaderException& e) {
// TODO: handle exception, show error dialog
std::wcerr << L"RelpipeReaderException: " << e.getMessage() << std::endl;
}
}
};
int main(int argc, char**argv) {
setlocale(LC_ALL, "");
CLI::untieStdIO();
CLI cli(argc, argv);
// TODO: argument name collisions? Filter arguments? Use prefix for Qt? Qt: -title, -style, -geometry
QApplication app(argc, argv);
std::shared_ptr<RelationalReader> reader(Factory::create(std::cin));
int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR;
RelpipeChartMainWindow window;
window.show();
RelationalReaderThread t(reader);
// Proxy that passes calls from the background thread to the GUI thread using signal-slot mechanism:
QtRelationalReaderStringHandler handler(&t); // &t instead of handler.moveToThread(&t); // QObject::moveToThread: Cannot move objects with a parent
// see Q_DECLARE_METATYPE above
qRegisterMetaType<string_t>();
qRegisterMetaType<std::vector < AttributeMetadata >> ();
QObject::connect(&handler, &QtRelationalReaderStringHandler::startRelationReceived, &window, &RelpipeChartMainWindow::startRelation, Qt::ConnectionType::QueuedConnection);
QObject::connect(&handler, &QtRelationalReaderStringHandler::attributeReceived, &window, &RelpipeChartMainWindow::attribute, Qt::ConnectionType::QueuedConnection);
QObject::connect(&handler, &QtRelationalReaderStringHandler::endOfPipeReceived, &window, &RelpipeChartMainWindow::endOfPipe, Qt::ConnectionType::QueuedConnection);
reader->addHandler(&handler);
// Start background thread
t.start();
int qtResultCode = app.exec();
if (qtResultCode == 0) {
resultCode = CLI::EXIT_CODE_SUCCESS;
} else {
// TODO: report and log Qt errors if any
}
if (t.isRunning()) {
std::wcerr << L"Background RelationalReader thread is still running → terminate()" << std::endl;
t.terminate();
std::wcerr << L"Background RelationalReader thread was terminated → wait()" << std::endl;
t.wait();
std::wcerr << L"Background RelationalReader thread wait() finished" << std::endl;
}
return resultCode;
}