parent
42c486f5cf
commit
9f14ee1c64
|
@ -0,0 +1,55 @@
|
||||||
|
---
|
||||||
|
BasedOnStyle: Microsoft
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
IndentWidth: 4
|
||||||
|
|
||||||
|
ColumnLimit: 100
|
||||||
|
|
||||||
|
# We want a space between the type and the star for pointer types.
|
||||||
|
PointerBindsToType: false
|
||||||
|
|
||||||
|
# We want to break before the operators, but not before a '='.
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
|
||||||
|
# Braces are usually attached, but not after functions or class declarations.
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: true
|
||||||
|
AfterCaseLabel: true
|
||||||
|
AfterControlStatement: true
|
||||||
|
AfterEnum: true
|
||||||
|
AfterFunction: true
|
||||||
|
BeforeLambdaBody: true
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: true
|
||||||
|
BeforeElse: true
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
|
||||||
|
# Indent width for line continuations.
|
||||||
|
ContinuationIndentWidth: 2
|
||||||
|
|
||||||
|
# Allow indentation for preprocessing directives (if/ifdef/endif). https://reviews.llvm.org/rL312125
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
|
||||||
|
# Do not indent public/private/protected
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
|
||||||
|
# This is needed because IndentAccessModifiers doesn't seem to work
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
PackConstructorInitializers: Never
|
||||||
|
|
||||||
|
# Horizontally align arguments after an open bracket.
|
||||||
|
AlignAfterOpenBracket: true
|
||||||
|
|
||||||
|
SortIncludes: false
|
||||||
|
|
||||||
|
InsertNewlineAtEOF: true
|
||||||
|
|
||||||
|
AlignConsecutiveMacros: AcrossEmptyLines
|
||||||
|
AlignConsecutiveAssignments: AcrossEmptyLines
|
152
src/app/main.cpp
152
src/app/main.cpp
|
@ -46,23 +46,29 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
|
||||||
QMutexLocker lock(&logMutex);
|
QMutexLocker lock(&logMutex);
|
||||||
|
|
||||||
QString str;
|
QString str;
|
||||||
//const QString fmt = QStringLiteral("%1: %2 (%3:%4, %5)\n");
|
// const QString fmt = QStringLiteral("%1: %2 (%3:%4, %5)\n");
|
||||||
static const QString fmt = QStringLiteral("%1: %2\n");
|
static const QString fmt = QStringLiteral("%1: %2\n");
|
||||||
switch (type) {
|
switch (type)
|
||||||
|
{
|
||||||
case QtDebugMsg:
|
case QtDebugMsg:
|
||||||
str = fmt.arg(QStringLiteral("Debug"), msg); //.arg(context.file).arg(context.line).arg(context.function);
|
str = fmt.arg(QStringLiteral("Debug"),
|
||||||
|
msg); //.arg(context.file).arg(context.line).arg(context.function);
|
||||||
break;
|
break;
|
||||||
case QtInfoMsg:
|
case QtInfoMsg:
|
||||||
str = fmt.arg(QStringLiteral("Info"), msg); //.arg(context.file).arg(context.line).arg(context.function);
|
str = fmt.arg(QStringLiteral("Info"),
|
||||||
|
msg); //.arg(context.file).arg(context.line).arg(context.function);
|
||||||
break;
|
break;
|
||||||
case QtWarningMsg:
|
case QtWarningMsg:
|
||||||
str = fmt.arg(QStringLiteral("Warning"), msg); //.arg(context.file).arg(context.line).arg(context.function);
|
str = fmt.arg(QStringLiteral("Warning"),
|
||||||
|
msg); //.arg(context.file).arg(context.line).arg(context.function);
|
||||||
break;
|
break;
|
||||||
case QtCriticalMsg:
|
case QtCriticalMsg:
|
||||||
str = fmt.arg(QStringLiteral("Critical"), msg); //.arg(context.file).arg(context.line).arg(context.function);
|
str = fmt.arg(QStringLiteral("Critical"),
|
||||||
|
msg); //.arg(context.file).arg(context.line).arg(context.function);
|
||||||
break;
|
break;
|
||||||
case QtFatalMsg:
|
case QtFatalMsg:
|
||||||
str = fmt.arg(QStringLiteral("Fatal"), msg); //.arg(context.file).arg(context.line).arg(context.function);
|
str = fmt.arg(QStringLiteral("Fatal"),
|
||||||
|
msg); //.arg(context.file).arg(context.line).arg(context.function);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextStream s(gLogFile());
|
QTextStream s(gLogFile());
|
||||||
|
@ -73,114 +79,124 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
|
||||||
|
|
||||||
void setupLogger()
|
void setupLogger()
|
||||||
{
|
{
|
||||||
//const QString path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
// const QString path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
QString path = MeetingSession::appDataPath;
|
QString path = MeetingSession::appDataPath;
|
||||||
if(qApp->arguments().contains("--test"))
|
if (qApp->arguments().contains("--test"))
|
||||||
path = qApp->applicationDirPath(); //If testing use exe folder instead of AppData: see MeetingSession
|
path = qApp->applicationDirPath(); // If testing use exe folder instead of AppData:
|
||||||
|
// see MeetingSession
|
||||||
|
|
||||||
QFile *logFile = gLogFile();
|
QFile *logFile = gLogFile();
|
||||||
|
|
||||||
logFile->setFileName(path + QStringLiteral("/logs/mrtp_log.log"));
|
logFile->setFileName(path + QStringLiteral("/logs/mrtp_log.log"));
|
||||||
logFile->open(QFile::WriteOnly | QFile::Append | QFile::Text);
|
logFile->open(QFile::WriteOnly | QFile::Append | QFile::Text);
|
||||||
if(!logFile->isOpen()) //FIXME: if logFile gets too big, ask user to truncate it
|
if (!logFile->isOpen()) // FIXME: if logFile gets too big, ask user to truncate it
|
||||||
{
|
{
|
||||||
QDir dir(path);
|
QDir dir(path);
|
||||||
dir.mkdir("logs");
|
dir.mkdir("logs");
|
||||||
logFile->open(QFile::WriteOnly | QFile::Append | QFile::Text);
|
logFile->open(QFile::WriteOnly | QFile::Append | QFile::Text);
|
||||||
}
|
}
|
||||||
if(logFile->isOpen())
|
if (logFile->isOpen())
|
||||||
{
|
{
|
||||||
defaultHandler = qInstallMessageHandler(myMessageOutput);
|
defaultHandler = qInstallMessageHandler(myMessageOutput);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
qDebug() << "Cannot open Log file:" << logFile->fileName() << "Error:" << logFile->errorString();
|
{
|
||||||
|
qDebug() << "Cannot open Log file:" << logFile->fileName()
|
||||||
|
<< "Error:" << logFile->errorString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
#ifdef GLOBAL_TRY_CATCH
|
#ifdef GLOBAL_TRY_CATCH
|
||||||
try{
|
try
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
QApplication::setOrganizationName(AppCompany);
|
QApplication::setOrganizationName(AppCompany);
|
||||||
//QApplication::setApplicationName(AppProduct);
|
// QApplication::setApplicationName(AppProduct);
|
||||||
QApplication::setApplicationDisplayName(AppDisplayName);
|
QApplication::setApplicationDisplayName(AppDisplayName);
|
||||||
QApplication::setApplicationVersion(AppVersion);
|
QApplication::setApplicationVersion(AppVersion);
|
||||||
|
|
||||||
MeetingSession::locateAppdata();
|
MeetingSession::locateAppdata();
|
||||||
|
|
||||||
setupLogger();
|
setupLogger();
|
||||||
|
|
||||||
qDebug() << QApplication::applicationDisplayName()
|
qDebug() << QApplication::applicationDisplayName()
|
||||||
<< "Version:" << QApplication::applicationVersion()
|
<< "Version:" << QApplication::applicationVersion() << "Built:" << AppBuildDate
|
||||||
<< "Built:" << AppBuildDate
|
<< "Website: " << AppProjectWebSite;
|
||||||
<< "Website: " << AppProjectWebSite;
|
qDebug() << "Qt:" << QT_VERSION_STR;
|
||||||
qDebug() << "Qt:" << QT_VERSION_STR;
|
qDebug() << "Sqlite:" << sqlite3_libversion() << " DB Format: V" << FormatVersion;
|
||||||
qDebug() << "Sqlite:" << sqlite3_libversion() << " DB Format: V" << FormatVersion;
|
qDebug() << QDateTime::currentDateTime().toString("dd/MM/yyyy HH:mm");
|
||||||
qDebug() << QDateTime::currentDateTime().toString("dd/MM/yyyy HH:mm");
|
|
||||||
|
|
||||||
//Check SQLite thread safety
|
// Check SQLite thread safety
|
||||||
int val = sqlite3_threadsafe();
|
int val = sqlite3_threadsafe();
|
||||||
if(val != 1)
|
if (val != 1)
|
||||||
{
|
|
||||||
//Not thread safe
|
|
||||||
qWarning() << "SQLite Library was not compiled with SQLITE_THREADSAFE=1. This may cause crashes of this application.";
|
|
||||||
}
|
|
||||||
|
|
||||||
MeetingSession meetingSession;
|
|
||||||
utils::language::loadTranslationsFromSettings();
|
|
||||||
|
|
||||||
MainWindow w;
|
|
||||||
w.showNormal();
|
|
||||||
w.resize(800, 600);
|
|
||||||
w.showMaximized();
|
|
||||||
|
|
||||||
if(argc > 1) //FIXME: better handling if there are extra arguments
|
|
||||||
{
|
|
||||||
QString fileName = app.arguments().at(1);
|
|
||||||
qDebug() << "Trying to load:" << fileName;
|
|
||||||
if(QFile(fileName).exists())
|
|
||||||
{
|
{
|
||||||
w.loadFile(app.arguments().at(1));
|
// Not thread safe
|
||||||
|
qWarning() << "SQLite Library was not compiled with SQLITE_THREADSAFE=1. This may "
|
||||||
|
"cause crashes of this application.";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Running...";
|
MeetingSession meetingSession;
|
||||||
|
utils::language::loadTranslationsFromSettings();
|
||||||
|
|
||||||
int ret = app.exec();
|
MainWindow w;
|
||||||
QThreadPool::globalInstance()->waitForDone(1000);
|
w.showNormal();
|
||||||
DB_Error err = Session->closeDB();
|
w.resize(800, 600);
|
||||||
|
w.showMaximized();
|
||||||
|
|
||||||
if(err == DB_Error::DbBusyWhenClosing || QThreadPool::globalInstance()->activeThreadCount() > 0)
|
if (argc > 1) // FIXME: better handling if there are extra arguments
|
||||||
{
|
{
|
||||||
qWarning() << "Error: Application closing while threadpool still running or database busy!";
|
QString fileName = app.arguments().at(1);
|
||||||
QThreadPool::globalInstance()->waitForDone(10000);
|
qDebug() << "Trying to load:" << fileName;
|
||||||
Session->closeDB();
|
if (QFile(fileName).exists())
|
||||||
}
|
{
|
||||||
|
w.loadFile(app.arguments().at(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
qDebug() << "Running...";
|
||||||
|
|
||||||
|
int ret = app.exec();
|
||||||
|
QThreadPool::globalInstance()->waitForDone(1000);
|
||||||
|
DB_Error err = Session->closeDB();
|
||||||
|
|
||||||
|
if (err == DB_Error::DbBusyWhenClosing
|
||||||
|
|| QThreadPool::globalInstance()->activeThreadCount() > 0)
|
||||||
|
{
|
||||||
|
qWarning()
|
||||||
|
<< "Error: Application closing while threadpool still running or database busy!";
|
||||||
|
QThreadPool::globalInstance()->waitForDone(10000);
|
||||||
|
Session->closeDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
#ifdef GLOBAL_TRY_CATCH
|
#ifdef GLOBAL_TRY_CATCH
|
||||||
}catch(const char* str)
|
}
|
||||||
|
catch (const char *str)
|
||||||
{
|
{
|
||||||
qDebug() << "Exception:" << str;
|
qDebug() << "Exception:" << str;
|
||||||
throw;
|
throw;
|
||||||
}catch(const std::string& str)
|
}
|
||||||
|
catch (const std::string &str)
|
||||||
{
|
{
|
||||||
qDebug() << "Exception:" << str.c_str();
|
qDebug() << "Exception:" << str.c_str();
|
||||||
throw;
|
throw;
|
||||||
}catch(sqlite3pp::database_error& e)
|
}
|
||||||
|
catch (sqlite3pp::database_error &e)
|
||||||
{
|
{
|
||||||
qDebug() << "Exception:" << e.what();
|
qDebug() << "Exception:" << e.what();
|
||||||
throw;
|
throw;
|
||||||
}catch(std::exception& e)
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
{
|
{
|
||||||
qDebug() << "Exception:" << e.what();
|
qDebug() << "Exception:" << e.what();
|
||||||
throw;
|
throw;
|
||||||
}catch(...)
|
}
|
||||||
|
catch (...)
|
||||||
{
|
{
|
||||||
qDebug() << "Caught generic exception";
|
qDebug() << "Caught generic exception";
|
||||||
throw;
|
throw;
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
#include "viewmanager/viewmanager.h"
|
#include "viewmanager/viewmanager.h"
|
||||||
|
|
||||||
|
|
||||||
#include "jobs/jobeditor/jobpatheditor.h"
|
#include "jobs/jobeditor/jobpatheditor.h"
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@
|
||||||
#include "printing/wizard/printwizard.h"
|
#include "printing/wizard/printwizard.h"
|
||||||
|
|
||||||
#ifdef ENABLE_USER_QUERY
|
#ifdef ENABLE_USER_QUERY
|
||||||
#include "sqlconsole/sqlconsole.h"
|
# include "sqlconsole/sqlconsole.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
|
@ -61,10 +60,10 @@
|
||||||
#include "searchbox/searchresultmodel.h"
|
#include "searchbox/searchresultmodel.h"
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
#include "backgroundmanager/backgroundmanager.h"
|
# include "backgroundmanager/backgroundmanager.h"
|
||||||
#include "backgroundmanager/backgroundresultpanel.h"
|
# include "backgroundmanager/backgroundresultpanel.h"
|
||||||
#include "jobs/jobs_checker/crossing/jobcrossingchecker.h"
|
# include "jobs/jobs_checker/crossing/jobcrossingchecker.h"
|
||||||
#include "rollingstock/rs_checker/rscheckermanager.h"
|
# include "rollingstock/rs_checker/rscheckermanager.h"
|
||||||
#endif // ENABLE_BACKGROUND_MANAGER
|
#endif // ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include "propertiesdialog.h"
|
#include "propertiesdialog.h"
|
||||||
|
@ -100,47 +99,47 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->actionAbout->setText(tr("About %1").arg(qApp->applicationDisplayName()));
|
ui->actionAbout->setText(tr("About %1").arg(qApp->applicationDisplayName()));
|
||||||
|
|
||||||
auto viewMgr = Session->getViewManager();
|
auto viewMgr = Session->getViewManager();
|
||||||
viewMgr->m_mainWidget = this;
|
viewMgr->m_mainWidget = this;
|
||||||
|
|
||||||
auto graphMgr = viewMgr->getLineGraphMgr();
|
auto graphMgr = viewMgr->getLineGraphMgr();
|
||||||
connect(graphMgr, &LineGraphManager::jobSelected, this, &MainWindow::onJobSelected);
|
connect(graphMgr, &LineGraphManager::jobSelected, this, &MainWindow::onJobSelected);
|
||||||
|
|
||||||
//view = graphMgr->getView();
|
// view = graphMgr->getView();
|
||||||
view = new LineGraphWidget(this);
|
view = new LineGraphWidget(this);
|
||||||
|
|
||||||
//Welcome label
|
// Welcome label
|
||||||
welcomeLabel = new QLabel(this);
|
welcomeLabel = new QLabel(this);
|
||||||
welcomeLabel->setTextFormat(Qt::RichText);
|
welcomeLabel->setTextFormat(Qt::RichText);
|
||||||
welcomeLabel->setAlignment(Qt::AlignCenter);
|
welcomeLabel->setAlignment(Qt::AlignCenter);
|
||||||
welcomeLabel->setFont(QFont("Arial", 15));
|
welcomeLabel->setFont(QFont("Arial", 15));
|
||||||
welcomeLabel->setObjectName("WelcomeLabel");
|
welcomeLabel->setObjectName("WelcomeLabel");
|
||||||
|
|
||||||
//JobPathEditor dock
|
// JobPathEditor dock
|
||||||
jobEditor = new JobPathEditor(this);
|
jobEditor = new JobPathEditor(this);
|
||||||
viewMgr->jobEditor = jobEditor;
|
viewMgr->jobEditor = jobEditor;
|
||||||
jobDock = new QDockWidget(tr("Job Editor"), this);
|
jobDock = new QDockWidget(tr("Job Editor"), this);
|
||||||
jobDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
jobDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||||
jobDock->setWidget(jobEditor);
|
jobDock->setWidget(jobEditor);
|
||||||
jobDock->installEventFilter(this); //NOTE: see MainWindow::eventFilter() below
|
jobDock->installEventFilter(this); // NOTE: see MainWindow::eventFilter() below
|
||||||
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, jobDock);
|
addDockWidget(Qt::RightDockWidgetArea, jobDock);
|
||||||
ui->menuView->addAction(jobDock->toggleViewAction());
|
ui->menuView->addAction(jobDock->toggleViewAction());
|
||||||
connect(jobDock->toggleViewAction(), &QAction::triggered, jobEditor, &JobPathEditor::show);
|
connect(jobDock->toggleViewAction(), &QAction::triggered, jobEditor, &JobPathEditor::show);
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
//Background Errors dock
|
// Background Errors dock
|
||||||
BackgroundResultPanel *resPanel = new BackgroundResultPanel(this);
|
BackgroundResultPanel *resPanel = new BackgroundResultPanel(this);
|
||||||
resPanelDock = new QDockWidget(tr("Errors"), this);
|
resPanelDock = new QDockWidget(tr("Errors"), this);
|
||||||
resPanelDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
|
resPanelDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
|
||||||
resPanelDock->setWidget(resPanel);
|
resPanelDock->setWidget(resPanel);
|
||||||
resPanelDock->installEventFilter(this); //NOTE: see eventFilter() below
|
resPanelDock->installEventFilter(this); // NOTE: see eventFilter() below
|
||||||
|
|
||||||
addDockWidget(Qt::BottomDockWidgetArea, resPanelDock);
|
addDockWidget(Qt::BottomDockWidgetArea, resPanelDock);
|
||||||
ui->menuView->addAction(resPanelDock->toggleViewAction());
|
ui->menuView->addAction(resPanelDock->toggleViewAction());
|
||||||
ui->mainToolBar->addAction(resPanelDock->toggleViewAction());
|
ui->mainToolBar->addAction(resPanelDock->toggleViewAction());
|
||||||
|
|
||||||
//Add checkers FIXME: move to session?
|
// Add checkers FIXME: move to session?
|
||||||
JobCrossingChecker *jobCrossingChecker = new JobCrossingChecker(Session->m_Db, this);
|
JobCrossingChecker *jobCrossingChecker = new JobCrossingChecker(Session->m_Db, this);
|
||||||
Session->getBackgroundManager()->addChecker(jobCrossingChecker);
|
Session->getBackgroundManager()->addChecker(jobCrossingChecker);
|
||||||
|
|
||||||
|
@ -148,22 +147,24 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
Session->getBackgroundManager()->addChecker(rsChecker);
|
Session->getBackgroundManager()->addChecker(rsChecker);
|
||||||
#endif // ENABLE_BACKGROUND_MANAGER
|
#endif // ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
//Allow JobPathEditor to use all vertical space when RsErrorWidget dock is at bottom
|
// Allow JobPathEditor to use all vertical space when RsErrorWidget dock is at bottom
|
||||||
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
|
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
|
||||||
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
|
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
|
||||||
|
|
||||||
//Search Box
|
// Search Box
|
||||||
SearchResultModel *searchModel = new SearchResultModel(Session->m_Db, this);
|
SearchResultModel *searchModel = new SearchResultModel(Session->m_Db, this);
|
||||||
searchEdit = new CustomCompletionLineEdit(searchModel, this);
|
searchEdit = new CustomCompletionLineEdit(searchModel, this);
|
||||||
searchEdit->setMinimumWidth(300);
|
searchEdit->setMinimumWidth(300);
|
||||||
searchEdit->setMinimumHeight(25);
|
searchEdit->setMinimumHeight(25);
|
||||||
searchEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
searchEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
searchEdit->setPlaceholderText(tr("Find"));
|
searchEdit->setPlaceholderText(tr("Find"));
|
||||||
searchEdit->setClearButtonEnabled(true);
|
searchEdit->setClearButtonEnabled(true);
|
||||||
connect(searchEdit, &CustomCompletionLineEdit::completionDone, this, &MainWindow::onJobSearchItemSelected);
|
connect(searchEdit, &CustomCompletionLineEdit::completionDone, this,
|
||||||
connect(searchModel, &SearchResultModel::resultsReady, this, &MainWindow::onJobSearchResultsReady);
|
&MainWindow::onJobSearchItemSelected);
|
||||||
|
connect(searchModel, &SearchResultModel::resultsReady, this,
|
||||||
|
&MainWindow::onJobSearchResultsReady);
|
||||||
|
|
||||||
QWidget* spacer = new QWidget();
|
QWidget *spacer = new QWidget();
|
||||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
ui->mainToolBar->addWidget(spacer);
|
ui->mainToolBar->addWidget(spacer);
|
||||||
ui->mainToolBar->addWidget(searchEdit);
|
ui->mainToolBar->addWidget(searchEdit);
|
||||||
|
@ -172,12 +173,11 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
setCentralWidgetMode(CentralWidgetMode::StartPageMode);
|
setCentralWidgetMode(CentralWidgetMode::StartPageMode);
|
||||||
|
|
||||||
QMenu *recentFilesMenu = new QMenu(this);
|
QMenu *recentFilesMenu = new QMenu(this);
|
||||||
for(int i = 0; i < MaxRecentFiles; i++)
|
for (int i = 0; i < MaxRecentFiles; i++)
|
||||||
{
|
{
|
||||||
recentFileActs[i] = new QAction(this);
|
recentFileActs[i] = new QAction(this);
|
||||||
recentFileActs[i]->setVisible(false);
|
recentFileActs[i]->setVisible(false);
|
||||||
connect(recentFileActs[i], &QAction::triggered,
|
connect(recentFileActs[i], &QAction::triggered, this, &MainWindow::onOpenRecent);
|
||||||
this, &MainWindow::onOpenRecent);
|
|
||||||
|
|
||||||
recentFilesMenu->addAction(recentFileActs[i]);
|
recentFilesMenu->addAction(recentFileActs[i]);
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
|
||||||
ui->actionOpen_Recent->setMenu(recentFilesMenu);
|
ui->actionOpen_Recent->setMenu(recentFilesMenu);
|
||||||
|
|
||||||
//Listen to changes to display welcomeLabel or view
|
// Listen to changes to display welcomeLabel or view
|
||||||
connect(Session, &MeetingSession::segmentAdded, this, &MainWindow::checkLineNumber);
|
connect(Session, &MeetingSession::segmentAdded, this, &MainWindow::checkLineNumber);
|
||||||
connect(Session, &MeetingSession::segmentRemoved, this, &MainWindow::checkLineNumber);
|
connect(Session, &MeetingSession::segmentRemoved, this, &MainWindow::checkLineNumber);
|
||||||
connect(Session, &MeetingSession::lineAdded, this, &MainWindow::checkLineNumber);
|
connect(Session, &MeetingSession::lineAdded, this, &MainWindow::checkLineNumber);
|
||||||
|
@ -240,11 +240,13 @@ void MainWindow::setup_actions()
|
||||||
connect(ui->actionProperties, &QAction::triggered, this, &MainWindow::onProperties);
|
connect(ui->actionProperties, &QAction::triggered, this, &MainWindow::onProperties);
|
||||||
|
|
||||||
connect(ui->actionStations, &QAction::triggered, this, &MainWindow::onStationManager);
|
connect(ui->actionStations, &QAction::triggered, this, &MainWindow::onStationManager);
|
||||||
connect(ui->actionRollingstockManager, &QAction::triggered, this, &MainWindow::onRollingStockManager);
|
connect(ui->actionRollingstockManager, &QAction::triggered, this,
|
||||||
|
&MainWindow::onRollingStockManager);
|
||||||
connect(ui->actionJob_Shifts, &QAction::triggered, this, &MainWindow::onShiftManager);
|
connect(ui->actionJob_Shifts, &QAction::triggered, this, &MainWindow::onShiftManager);
|
||||||
connect(ui->action_JobsMgr, &QAction::triggered, this, &MainWindow::onJobsManager);
|
connect(ui->action_JobsMgr, &QAction::triggered, this, &MainWindow::onJobsManager);
|
||||||
connect(ui->actionRS_Session_Viewer, &QAction::triggered, this, &MainWindow::onSessionRSViewer);
|
connect(ui->actionRS_Session_Viewer, &QAction::triggered, this, &MainWindow::onSessionRSViewer);
|
||||||
connect(ui->actionMeeting_Information, &QAction::triggered, this, &MainWindow::onMeetingInformation);
|
connect(ui->actionMeeting_Information, &QAction::triggered, this,
|
||||||
|
&MainWindow::onMeetingInformation);
|
||||||
|
|
||||||
connect(ui->actionAddJob, &QAction::triggered, this, &MainWindow::onAddJob);
|
connect(ui->actionAddJob, &QAction::triggered, this, &MainWindow::onAddJob);
|
||||||
connect(ui->actionRemoveJob, &QAction::triggered, this, &MainWindow::onRemoveJob);
|
connect(ui->actionRemoveJob, &QAction::triggered, this, &MainWindow::onRemoveJob);
|
||||||
|
@ -263,16 +265,22 @@ void MainWindow::setup_actions()
|
||||||
|
|
||||||
connect(ui->actionExit, &QAction::triggered, this, &MainWindow::close);
|
connect(ui->actionExit, &QAction::triggered, this, &MainWindow::close);
|
||||||
|
|
||||||
ui->actionNext_Job_Segment->setToolTip(tr("Hold shift and click to go to <b>last</b> job stop."));
|
ui->actionNext_Job_Segment->setToolTip(
|
||||||
ui->actionPrev_Job_Segment->setToolTip(tr("Hold shift and click to go to <b>first</b> job stop."));
|
tr("Hold shift and click to go to <b>last</b> job stop."));
|
||||||
connect(ui->actionNext_Job_Segment, &QAction::triggered, this, []()
|
ui->actionPrev_Job_Segment->setToolTip(
|
||||||
|
tr("Hold shift and click to go to <b>first</b> job stop."));
|
||||||
|
connect(ui->actionNext_Job_Segment, &QAction::triggered, this,
|
||||||
|
[]()
|
||||||
{
|
{
|
||||||
bool shiftPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
bool shiftPressed =
|
||||||
|
QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||||
Session->getViewManager()->requestJobShowPrevNextSegment(false, shiftPressed);
|
Session->getViewManager()->requestJobShowPrevNextSegment(false, shiftPressed);
|
||||||
});
|
});
|
||||||
connect(ui->actionPrev_Job_Segment, &QAction::triggered, this, []()
|
connect(ui->actionPrev_Job_Segment, &QAction::triggered, this,
|
||||||
|
[]()
|
||||||
{
|
{
|
||||||
bool shiftPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
bool shiftPressed =
|
||||||
|
QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||||
Session->getViewManager()->requestJobShowPrevNextSegment(true, shiftPressed);
|
Session->getViewManager()->requestJobShowPrevNextSegment(true, shiftPressed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -284,15 +292,14 @@ void MainWindow::about()
|
||||||
msgBox->setWindowTitle(tr("About %1").arg(qApp->applicationDisplayName()));
|
msgBox->setWindowTitle(tr("About %1").arg(qApp->applicationDisplayName()));
|
||||||
|
|
||||||
const QString translatedText =
|
const QString translatedText =
|
||||||
tr(
|
tr("<h3>%1</h3>"
|
||||||
"<h3>%1</h3>"
|
"<p>This program makes it easier to deal with timetables and trains.</p>"
|
||||||
"<p>This program makes it easier to deal with timetables and trains.</p>"
|
"<p>Version: <b>%2</b></p>"
|
||||||
"<p>Version: <b>%2</b></p>"
|
"<p>Built: %3</p>"
|
||||||
"<p>Built: %3</p>"
|
"<p>Website: <a href='%4'>%4</a></p>")
|
||||||
"<p>Website: <a href='%4'>%4</a></p>")
|
.arg(qApp->applicationDisplayName(), qApp->applicationVersion(),
|
||||||
.arg(qApp->applicationDisplayName(), qApp->applicationVersion(),
|
QDate::fromString(AppBuildDate, QLatin1String("MMM dd yyyy")).toString("dd/MM/yyyy"),
|
||||||
QDate::fromString(AppBuildDate, QLatin1String("MMM dd yyyy")).toString("dd/MM/yyyy"),
|
AppProjectWebSite);
|
||||||
AppProjectWebSite);
|
|
||||||
|
|
||||||
msgBox->setTextFormat(Qt::RichText);
|
msgBox->setTextFormat(Qt::RichText);
|
||||||
msgBox->setText(translatedText);
|
msgBox->setText(translatedText);
|
||||||
|
@ -309,15 +316,14 @@ void MainWindow::onOpen()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
if(Session->getBackgroundManager()->isRunning())
|
if (Session->getBackgroundManager()->isRunning())
|
||||||
{
|
{
|
||||||
int ret = QMessageBox::warning(this,
|
int ret = QMessageBox::warning(
|
||||||
tr("Backgroung Task"),
|
this, tr("Backgroung Task"),
|
||||||
tr("Background task for checking rollingstock errors is still running.\n"
|
tr("Background task for checking rollingstock errors is still running.\n"
|
||||||
"Do you want to cancel it?"),
|
"Do you want to cancel it?"),
|
||||||
QMessageBox::Yes, QMessageBox::No,
|
QMessageBox::Yes, QMessageBox::No, QMessageBox::Yes);
|
||||||
QMessageBox::Yes);
|
if (ret == QMessageBox::Yes)
|
||||||
if(ret == QMessageBox::Yes)
|
|
||||||
Session->getBackgroundManager()->abortAllTasks();
|
Session->getBackgroundManager()->abortAllTasks();
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
@ -335,22 +341,21 @@ void MainWindow::onOpen()
|
||||||
filters << FileFormats::tr(FileFormats::allFiles);
|
filters << FileFormats::tr(FileFormats::allFiles);
|
||||||
dlg->setNameFilters(filters);
|
dlg->setNameFilters(filters);
|
||||||
|
|
||||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||||
|
|
||||||
if(fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RecentDirStore::setPath(directory_key::session, fileName);
|
RecentDirStore::setPath(directory_key::session, fileName);
|
||||||
|
|
||||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||||
|
|
||||||
if(!QThreadPool::globalInstance()->waitForDone(2000))
|
if (!QThreadPool::globalInstance()->waitForDone(2000))
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this,
|
QMessageBox::warning(this, tr("Background Tasks"),
|
||||||
tr("Background Tasks"),
|
|
||||||
tr("Some background tasks are still running.\n"
|
tr("Some background tasks are still running.\n"
|
||||||
"The file was not opened. Try again."));
|
"The file was not opened. Try again."));
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
|
@ -362,10 +367,10 @@ void MainWindow::onOpen()
|
||||||
loadFile(fileName);
|
loadFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::loadFile(const QString& fileName)
|
void MainWindow::loadFile(const QString &fileName)
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
if(fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qDebug() << "Loading:" << fileName;
|
qDebug() << "Loading:" << fileName;
|
||||||
|
@ -376,86 +381,91 @@ void MainWindow::loadFile(const QString& fileName)
|
||||||
|
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
|
|
||||||
if(err == DB_Error::FormatTooOld)
|
if (err == DB_Error::FormatTooOld)
|
||||||
{
|
{
|
||||||
int but = QMessageBox::warning(this, tr("Version is old"),
|
int but = QMessageBox::warning(
|
||||||
tr("This file was created by an older version of %1.\n"
|
this, tr("Version is old"),
|
||||||
"Opening it without conversion might not work and even crash the application.\n"
|
tr("This file was created by an older version of %1.\n"
|
||||||
"Do you want to open it anyway?").arg(qApp->applicationDisplayName()),
|
"Opening it without conversion might not work and even crash the application.\n"
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
"Do you want to open it anyway?")
|
||||||
if(but == QMessageBox::Yes)
|
.arg(qApp->applicationDisplayName()),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||||
|
if (but == QMessageBox::Yes)
|
||||||
err = Session->openDB(fileName, true);
|
err = Session->openDB(fileName, true);
|
||||||
}
|
}
|
||||||
else if(err == DB_Error::FormatTooNew)
|
else if (err == DB_Error::FormatTooNew)
|
||||||
{
|
{
|
||||||
if(err == DB_Error::FormatTooOld)
|
if (err == DB_Error::FormatTooOld)
|
||||||
{
|
{
|
||||||
int but = QMessageBox::warning(this, tr("Version is too new"),
|
int but = QMessageBox::warning(this, tr("Version is too new"),
|
||||||
tr("This file was created by a newer version of %1.\n"
|
tr("This file was created by a newer version of %1.\n"
|
||||||
"You should update the application first. Opening this file might not work or even crash.\n"
|
"You should update the application first. Opening "
|
||||||
"Do you want to open it anyway?").arg(qApp->applicationDisplayName()),
|
"this file might not work or even crash.\n"
|
||||||
|
"Do you want to open it anyway?")
|
||||||
|
.arg(qApp->applicationDisplayName()),
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||||
if(but == QMessageBox::Yes)
|
if (but == QMessageBox::Yes)
|
||||||
err = Session->openDB(fileName, true);
|
err = Session->openDB(fileName, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(err == DB_Error::DbBusyWhenClosing)
|
if (err == DB_Error::DbBusyWhenClosing)
|
||||||
showCloseWarning();
|
showCloseWarning();
|
||||||
|
|
||||||
if(err != DB_Error::NoError)
|
if (err != DB_Error::NoError)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setCurrentFile(fileName);
|
setCurrentFile(fileName);
|
||||||
|
|
||||||
//Fake we are coming from Start Page
|
// Fake we are coming from Start Page
|
||||||
//Otherwise we cannot show the first line
|
// Otherwise we cannot show the first line
|
||||||
m_mode = CentralWidgetMode::StartPageMode;
|
m_mode = CentralWidgetMode::StartPageMode;
|
||||||
checkLineNumber();
|
checkLineNumber();
|
||||||
|
|
||||||
|
if (!Session->checkImportRSTablesEmpty())
|
||||||
if(!Session->checkImportRSTablesEmpty())
|
|
||||||
{
|
{
|
||||||
//Probably the application crashed before finishing RS importation
|
// Probably the application crashed before finishing RS importation
|
||||||
//Give user choice to resume it or discard
|
// Give user choice to resume it or discard
|
||||||
|
|
||||||
OwningQPointer<QMessageBox> msgBox = new QMessageBox(
|
OwningQPointer<QMessageBox> msgBox =
|
||||||
QMessageBox::Warning,
|
new QMessageBox(QMessageBox::Warning, tr("RS Import"),
|
||||||
tr("RS Import"),
|
tr("There is some rollingstock import data left in this file. "
|
||||||
tr("There is some rollingstock import data left in this file. "
|
"Probably the application has crashed!<br>"
|
||||||
"Probably the application has crashed!<br>"
|
"Before deleting it would you like to resume importation?<br>"
|
||||||
"Before deleting it would you like to resume importation?<br>"
|
"<i>(Sorry for the crash, would you like to contact me and share "
|
||||||
"<i>(Sorry for the crash, would you like to contact me and share information about it?)</i>"),
|
"information about it?)</i>"),
|
||||||
QMessageBox::NoButton, this);
|
QMessageBox::NoButton, this);
|
||||||
auto resumeBut = msgBox->addButton(tr("Resume importation"), QMessageBox::YesRole);
|
auto resumeBut = msgBox->addButton(tr("Resume importation"), QMessageBox::YesRole);
|
||||||
msgBox->addButton(tr("Just delete it"), QMessageBox::NoRole);
|
msgBox->addButton(tr("Just delete it"), QMessageBox::NoRole);
|
||||||
msgBox->setDefaultButton(resumeBut);
|
msgBox->setDefaultButton(resumeBut);
|
||||||
msgBox->setTextFormat(Qt::RichText);
|
msgBox->setTextFormat(Qt::RichText);
|
||||||
|
|
||||||
msgBox->exec();
|
msgBox->exec();
|
||||||
if(!msgBox)
|
if (!msgBox)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(msgBox->clickedButton() == resumeBut)
|
if (msgBox->clickedButton() == resumeBut)
|
||||||
{
|
{
|
||||||
Session->getViewManager()->resumeRSImportation();
|
Session->getViewManager()->resumeRSImportation();
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Session->clearImportRSTables();
|
Session->clearImportRSTables();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setCurrentFile(const QString& fileName)
|
void MainWindow::setCurrentFile(const QString &fileName)
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
if(fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
{
|
{
|
||||||
setWindowFilePath(QString()); //Reset title bar
|
setWindowFilePath(QString()); // Reset title bar
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Qt automatically takes care of showing stripped filename in window title
|
// Qt automatically takes care of showing stripped filename in window title
|
||||||
setWindowFilePath(fileName);
|
setWindowFilePath(fileName);
|
||||||
|
|
||||||
QStringList files = AppSettings.getRecentFiles();
|
QStringList files = AppSettings.getRecentFiles();
|
||||||
|
@ -472,22 +482,23 @@ void MainWindow::setCurrentFile(const QString& fileName)
|
||||||
QString MainWindow::strippedName(const QString &fullFileName, bool *ok)
|
QString MainWindow::strippedName(const QString &fullFileName, bool *ok)
|
||||||
{
|
{
|
||||||
QFileInfo fi(fullFileName);
|
QFileInfo fi(fullFileName);
|
||||||
if(ok) *ok = fi.exists();
|
if (ok)
|
||||||
|
*ok = fi.exists();
|
||||||
return fi.fileName();
|
return fi.fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateRecentFileActions()
|
void MainWindow::updateRecentFileActions()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
QStringList files = AppSettings.getRecentFiles();
|
QStringList files = AppSettings.getRecentFiles();
|
||||||
|
|
||||||
int numRecentFiles = qMin(files.size(), int(MaxRecentFiles));
|
int numRecentFiles = qMin(files.size(), int(MaxRecentFiles));
|
||||||
|
|
||||||
for (int i = 0; i < numRecentFiles; i++)
|
for (int i = 0; i < numRecentFiles; i++)
|
||||||
{
|
{
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
QString name = strippedName(files[i], &ok);
|
QString name = strippedName(files[i], &ok);
|
||||||
if(name.isEmpty() || !ok)
|
if (name.isEmpty() || !ok)
|
||||||
{
|
{
|
||||||
files.removeAt(i);
|
files.removeAt(i);
|
||||||
i--;
|
i--;
|
||||||
|
@ -511,8 +522,8 @@ void MainWindow::updateRecentFileActions()
|
||||||
void MainWindow::onOpenRecent()
|
void MainWindow::onOpenRecent()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
QAction *act = qobject_cast<QAction*>(sender());
|
QAction *act = qobject_cast<QAction *>(sender());
|
||||||
if(!act)
|
if (!act)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loadFile(act->data().toString());
|
loadFile(act->data().toString());
|
||||||
|
@ -527,15 +538,14 @@ void MainWindow::onNew()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
if(Session->getBackgroundManager()->isRunning())
|
if (Session->getBackgroundManager()->isRunning())
|
||||||
{
|
{
|
||||||
int ret = QMessageBox::warning(this,
|
int ret = QMessageBox::warning(
|
||||||
tr("Backgroung Task"),
|
this, tr("Backgroung Task"),
|
||||||
tr("Background task for checking rollingstock errors is still running.\n"
|
tr("Background task for checking rollingstock errors is still running.\n"
|
||||||
"Do you want to cancel it?"),
|
"Do you want to cancel it?"),
|
||||||
QMessageBox::Yes, QMessageBox::No,
|
QMessageBox::Yes, QMessageBox::No, QMessageBox::Yes);
|
||||||
QMessageBox::Yes);
|
if (ret == QMessageBox::Yes)
|
||||||
if(ret == QMessageBox::Yes)
|
|
||||||
Session->getBackgroundManager()->abortAllTasks();
|
Session->getBackgroundManager()->abortAllTasks();
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
@ -553,22 +563,21 @@ void MainWindow::onNew()
|
||||||
filters << FileFormats::tr(FileFormats::allFiles);
|
filters << FileFormats::tr(FileFormats::allFiles);
|
||||||
dlg->setNameFilters(filters);
|
dlg->setNameFilters(filters);
|
||||||
|
|
||||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||||
|
|
||||||
if(fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RecentDirStore::setPath(directory_key::session, fileName);
|
RecentDirStore::setPath(directory_key::session, fileName);
|
||||||
|
|
||||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||||
|
|
||||||
if(!QThreadPool::globalInstance()->waitForDone(2000))
|
if (!QThreadPool::globalInstance()->waitForDone(2000))
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this,
|
QMessageBox::warning(this, tr("Background Tasks"),
|
||||||
tr("Background Tasks"),
|
|
||||||
tr("Some background tasks are still running.\n"
|
tr("Some background tasks are still running.\n"
|
||||||
"The new file was not created. Try again."));
|
"The new file was not created. Try again."));
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
|
@ -576,17 +585,17 @@ void MainWindow::onNew()
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile f(fileName);
|
QFile f(fileName);
|
||||||
if(f.exists())
|
if (f.exists())
|
||||||
f.remove();
|
f.remove();
|
||||||
|
|
||||||
DB_Error err = Session->createNewDB(fileName);
|
DB_Error err = Session->createNewDB(fileName);
|
||||||
|
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
|
|
||||||
if(err == DB_Error::DbBusyWhenClosing)
|
if (err == DB_Error::DbBusyWhenClosing)
|
||||||
showCloseWarning();
|
showCloseWarning();
|
||||||
|
|
||||||
if(err != DB_Error::NoError)
|
if (err != DB_Error::NoError)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setCurrentFile(fileName);
|
setCurrentFile(fileName);
|
||||||
|
@ -595,7 +604,7 @@ void MainWindow::onNew()
|
||||||
|
|
||||||
void MainWindow::onSave()
|
void MainWindow::onSave()
|
||||||
{
|
{
|
||||||
if(!Session->getViewManager()->closeEditors())
|
if (!Session->getViewManager()->closeEditors())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Session->releaseAllSavepoints();
|
Session->releaseAllSavepoints();
|
||||||
|
@ -605,7 +614,7 @@ void MainWindow::onSaveCopyAs()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
if(!Session->getViewManager()->closeEditors())
|
if (!Session->getViewManager()->closeEditors())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OwningQPointer<QFileDialog> dlg = new QFileDialog(this, tr("Save Session Copy"));
|
OwningQPointer<QFileDialog> dlg = new QFileDialog(this, tr("Save Session Copy"));
|
||||||
|
@ -619,29 +628,30 @@ void MainWindow::onSaveCopyAs()
|
||||||
filters << FileFormats::tr(FileFormats::allFiles);
|
filters << FileFormats::tr(FileFormats::allFiles);
|
||||||
dlg->setNameFilters(filters);
|
dlg->setNameFilters(filters);
|
||||||
|
|
||||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||||
|
|
||||||
if(fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RecentDirStore::setPath(directory_key::session, fileName);
|
RecentDirStore::setPath(directory_key::session, fileName);
|
||||||
|
|
||||||
QFile f(fileName);
|
QFile f(fileName);
|
||||||
if(f.exists())
|
if (f.exists())
|
||||||
f.remove();
|
f.remove();
|
||||||
|
|
||||||
database backupDB(fileName.toUtf8(), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
database backupDB(fileName.toUtf8(), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
||||||
|
|
||||||
int rc = Session->m_Db.backup(backupDB, [](int pageCount, int remaining, int res)
|
int rc = Session->m_Db.backup(backupDB,
|
||||||
|
[](int pageCount, int remaining, int res)
|
||||||
{
|
{
|
||||||
Q_UNUSED(res)
|
Q_UNUSED(res)
|
||||||
qDebug() << pageCount << "/" << remaining;
|
qDebug() << pageCount << "/" << remaining;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(rc != SQLITE_OK && rc != SQLITE_DONE)
|
if (rc != SQLITE_OK && rc != SQLITE_DONE)
|
||||||
{
|
{
|
||||||
QString errMsg = Session->m_Db.error_msg();
|
QString errMsg = Session->m_Db.error_msg();
|
||||||
qDebug() << Session->m_Db.error_code() << errMsg;
|
qDebug() << Session->m_Db.error_code() << errMsg;
|
||||||
|
@ -651,7 +661,7 @@ void MainWindow::onSaveCopyAs()
|
||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent *e)
|
void MainWindow::closeEvent(QCloseEvent *e)
|
||||||
{
|
{
|
||||||
if(closeSession())
|
if (closeSession())
|
||||||
e->accept();
|
e->accept();
|
||||||
else
|
else
|
||||||
e->ignore();
|
e->ignore();
|
||||||
|
@ -659,15 +669,14 @@ void MainWindow::closeEvent(QCloseEvent *e)
|
||||||
|
|
||||||
void MainWindow::showCloseWarning()
|
void MainWindow::showCloseWarning()
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this,
|
QMessageBox::warning(this, tr("Error while Closing"),
|
||||||
tr("Error while Closing"),
|
|
||||||
tr("There was an error while closing the database.\n"
|
tr("There was an error while closing the database.\n"
|
||||||
"Make sure there aren't any background tasks running and try again."));
|
"Make sure there aren't any background tasks running and try again."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::stopCloseTimer()
|
void MainWindow::stopCloseTimer()
|
||||||
{
|
{
|
||||||
if(closeTimerId)
|
if (closeTimerId)
|
||||||
{
|
{
|
||||||
killTimer(closeTimerId);
|
killTimer(closeTimerId);
|
||||||
closeTimerId = 0;
|
closeTimerId = 0;
|
||||||
|
@ -701,36 +710,36 @@ void MainWindow::setCentralWidgetMode(MainWindow::CentralWidgetMode mode)
|
||||||
#endif // ENABLE_BACKGROUND_MANAGER
|
#endif // ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
welcomeLabel->setText(
|
welcomeLabel->setText(
|
||||||
tr("<p><b>There are no lines in this session</b></p>"
|
tr("<p><b>There are no lines in this session</b></p>"
|
||||||
"<p>"
|
"<p>"
|
||||||
"<table align=\"center\">"
|
"<table align=\"center\">"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td>Start by creating the railway layout for this session:</td>"
|
"<td>Start by creating the railway layout for this session:</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td>"
|
"<td>"
|
||||||
"<table>"
|
"<table>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td>1.</td>"
|
"<td>1.</td>"
|
||||||
"<td>Create stations (<b>Edit</b> > <b>Stations</b>)</td>"
|
"<td>Create stations (<b>Edit</b> > <b>Stations</b>)</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td>2.</td>"
|
"<td>2.</td>"
|
||||||
"<td>Create railway lines (<b>Edit</b> > <b>Stations</b> > <b>Lines Tab</b>)</td>"
|
"<td>Create railway lines (<b>Edit</b> > <b>Stations</b> > <b>Lines Tab</b>)</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td>3.</td>"
|
"<td>3.</td>"
|
||||||
"<td>Add stations to railway lines</td>"
|
"<td>Add stations to railway lines</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"<tr>"
|
"<tr>"
|
||||||
"<td></td>"
|
"<td></td>"
|
||||||
"<td>(<b>Edit</b> > <b>Stations</b> > <b>Lines Tab</b> > <b>Edit Line</b>)</td>"
|
"<td>(<b>Edit</b> > <b>Stations</b> > <b>Lines Tab</b> > <b>Edit Line</b>)</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"</table>"
|
"</table>"
|
||||||
"</td>"
|
"</td>"
|
||||||
"</tr>"
|
"</tr>"
|
||||||
"</table>"
|
"</table>"
|
||||||
"</p>"));
|
"</p>"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CentralWidgetMode::ViewSessionMode:
|
case CentralWidgetMode::ViewSessionMode:
|
||||||
|
@ -748,37 +757,39 @@ void MainWindow::setCentralWidgetMode(MainWindow::CentralWidgetMode mode)
|
||||||
|
|
||||||
enableDBActions(mode != CentralWidgetMode::StartPageMode);
|
enableDBActions(mode != CentralWidgetMode::StartPageMode);
|
||||||
|
|
||||||
if(mode == CentralWidgetMode::ViewSessionMode)
|
if (mode == CentralWidgetMode::ViewSessionMode)
|
||||||
{
|
{
|
||||||
if(centralWidget() != view)
|
if (centralWidget() != view)
|
||||||
{
|
{
|
||||||
takeCentralWidget(); //Remove ownership from welcomeLabel
|
takeCentralWidget(); // Remove ownership from welcomeLabel
|
||||||
setCentralWidget(view);
|
setCentralWidget(view);
|
||||||
view->show();
|
view->show();
|
||||||
welcomeLabel->hide();
|
welcomeLabel->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Enable Job Creation
|
// Enable Job Creation
|
||||||
ui->actionAddJob->setEnabled(true);
|
ui->actionAddJob->setEnabled(true);
|
||||||
ui->actionAddJob->setToolTip(tr("Add train job"));
|
ui->actionAddJob->setToolTip(tr("Add train job"));
|
||||||
|
|
||||||
//Update actions based on Job selection
|
// Update actions based on Job selection
|
||||||
JobStopEntry selectedJob = Session->getViewManager()->getLineGraphMgr()->getCurrentSelectedJob();
|
JobStopEntry selectedJob =
|
||||||
|
Session->getViewManager()->getLineGraphMgr()->getCurrentSelectedJob();
|
||||||
onJobSelected(selectedJob.jobId);
|
onJobSelected(selectedJob.jobId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(centralWidget() != welcomeLabel)
|
if (centralWidget() != welcomeLabel)
|
||||||
{
|
{
|
||||||
takeCentralWidget(); //Remove ownership from LineGraphWidget
|
takeCentralWidget(); // Remove ownership from LineGraphWidget
|
||||||
setCentralWidget(welcomeLabel);
|
setCentralWidget(welcomeLabel);
|
||||||
view->hide();
|
view->hide();
|
||||||
welcomeLabel->show();
|
welcomeLabel->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
//If there aren't lines prevent from creating jobs
|
// If there aren't lines prevent from creating jobs
|
||||||
ui->actionAddJob->setEnabled(false);
|
ui->actionAddJob->setEnabled(false);
|
||||||
ui->actionAddJob->setToolTip(tr("You must create at least one railway segment before adding job to this session"));
|
ui->actionAddJob->setToolTip(
|
||||||
|
tr("You must create at least one railway segment before adding job to this session"));
|
||||||
ui->actionRemoveJob->setEnabled(false);
|
ui->actionRemoveJob->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,8 +810,8 @@ void MainWindow::onProperties()
|
||||||
void MainWindow::onMeetingInformation()
|
void MainWindow::onMeetingInformation()
|
||||||
{
|
{
|
||||||
OwningQPointer<MeetingInformationDialog> dlg = new MeetingInformationDialog(this);
|
OwningQPointer<MeetingInformationDialog> dlg = new MeetingInformationDialog(this);
|
||||||
int ret = dlg->exec();
|
int ret = dlg->exec();
|
||||||
if(dlg && ret == QDialog::Accepted)
|
if (dlg && ret == QDialog::Accepted)
|
||||||
dlg->saveData();
|
dlg->saveData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,11 +819,11 @@ bool MainWindow::closeSession()
|
||||||
{
|
{
|
||||||
DB_Error err = Session->closeDB();
|
DB_Error err = Session->closeDB();
|
||||||
|
|
||||||
if(err == DB_Error::DbBusyWhenClosing)
|
if (err == DB_Error::DbBusyWhenClosing)
|
||||||
{
|
{
|
||||||
if(closeTimerId)
|
if (closeTimerId)
|
||||||
{
|
{
|
||||||
//We already tried again
|
// We already tried again
|
||||||
|
|
||||||
stopCloseTimer();
|
stopCloseTimer();
|
||||||
|
|
||||||
|
@ -820,19 +831,19 @@ bool MainWindow::closeSession()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Start a timer to try again
|
// Start a timer to try again
|
||||||
closeTimerId = startTimer(1500);
|
closeTimerId = startTimer(1500);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stopCloseTimer();
|
stopCloseTimer();
|
||||||
|
|
||||||
if(err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
if (err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
setCentralWidgetMode(CentralWidgetMode::StartPageMode);
|
setCentralWidgetMode(CentralWidgetMode::StartPageMode);
|
||||||
|
|
||||||
//Reset filePath to refresh title
|
// Reset filePath to refresh title
|
||||||
setCurrentFile(QString());
|
setCurrentFile(QString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -842,7 +853,7 @@ void MainWindow::enableDBActions(bool enable)
|
||||||
{
|
{
|
||||||
databaseActionGroup->setEnabled(enable);
|
databaseActionGroup->setEnabled(enable);
|
||||||
searchEdit->setEnabled(enable);
|
searchEdit->setEnabled(enable);
|
||||||
if(!enable)
|
if (!enable)
|
||||||
jobEditor->setEnabled(false);
|
jobEditor->setEnabled(false);
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
@ -924,30 +935,30 @@ void MainWindow::checkLineNumber()
|
||||||
{
|
{
|
||||||
RailwaySegmentHelper helper(Session->m_Db);
|
RailwaySegmentHelper helper(Session->m_Db);
|
||||||
|
|
||||||
bool isLine = false;
|
bool isLine = false;
|
||||||
db_id graphObjId = 0;
|
db_id graphObjId = 0;
|
||||||
|
|
||||||
if(!helper.findFirstLineOrSegment(graphObjId, isLine))
|
if (!helper.findFirstLineOrSegment(graphObjId, isLine))
|
||||||
graphObjId = 0;
|
graphObjId = 0;
|
||||||
if(graphObjId && m_mode != CentralWidgetMode::ViewSessionMode)
|
if (graphObjId && m_mode != CentralWidgetMode::ViewSessionMode)
|
||||||
{
|
{
|
||||||
//First line was added or newly opened file -> Session has at least one line
|
// First line was added or newly opened file -> Session has at least one line
|
||||||
setCentralWidgetMode(CentralWidgetMode::ViewSessionMode);
|
setCentralWidgetMode(CentralWidgetMode::ViewSessionMode);
|
||||||
|
|
||||||
//Load first line or segment
|
// Load first line or segment
|
||||||
view->tryLoadGraph(graphObjId,
|
view->tryLoadGraph(graphObjId,
|
||||||
isLine ? LineGraphType::RailwayLine : LineGraphType::RailwaySegment);
|
isLine ? LineGraphType::RailwayLine : LineGraphType::RailwaySegment);
|
||||||
}
|
}
|
||||||
else if(graphObjId == 0 && m_mode != CentralWidgetMode::NoLinesWarningMode)
|
else if (graphObjId == 0 && m_mode != CentralWidgetMode::NoLinesWarningMode)
|
||||||
{
|
{
|
||||||
//Last line removed -> Session has no line
|
// Last line removed -> Session has no line
|
||||||
setCentralWidgetMode(CentralWidgetMode::NoLinesWarningMode);
|
setCentralWidgetMode(CentralWidgetMode::NoLinesWarningMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::timerEvent(QTimerEvent *e)
|
void MainWindow::timerEvent(QTimerEvent *e)
|
||||||
{
|
{
|
||||||
if(e->timerId() == closeTimerId)
|
if (e->timerId() == closeTimerId)
|
||||||
{
|
{
|
||||||
closeSession();
|
closeSession();
|
||||||
return;
|
return;
|
||||||
|
@ -964,38 +975,32 @@ void MainWindow::onJobSelected(db_id jobId)
|
||||||
ui->actionRemoveJob->setEnabled(selected);
|
ui->actionRemoveJob->setEnabled(selected);
|
||||||
|
|
||||||
QString removeJobTooltip;
|
QString removeJobTooltip;
|
||||||
if(selected)
|
if (selected)
|
||||||
removeJobTooltip = tr("Remove selected Job");
|
removeJobTooltip = tr("Remove selected Job");
|
||||||
else
|
else
|
||||||
removeJobTooltip = tr("First select a Job by double click on graph or type in search box");
|
removeJobTooltip = tr("First select a Job by double click on graph or type in search box");
|
||||||
ui->actionRemoveJob->setToolTip(removeJobTooltip);
|
ui->actionRemoveJob->setToolTip(removeJobTooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
//QT-BUG 69922: If user closes a floating dock widget, when shown again it cannot dock anymore
|
// QT-BUG 69922: If user closes a floating dock widget, when shown again it cannot dock anymore
|
||||||
//HACK: intercept dock close event and manually re-dock and hide so next time is shown it's docked
|
// HACK: intercept dock close event and manually re-dock and hide so next time is shown it's docked
|
||||||
//NOTE: calling directly 'QDockWidget::setFloating(false)' from inside 'eventFinter()' causes CRASH
|
// NOTE: calling directly 'QDockWidget::setFloating(false)' from inside 'eventFinter()' causes CRASH
|
||||||
// so queue it. Cannot use 'QMetaObject::invokeMethod()' because it's not a slot.
|
// so queue it. Cannot use 'QMetaObject::invokeMethod()' because it's not a slot.
|
||||||
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
|
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
|
||||||
{
|
{
|
||||||
if(watched == jobDock && event->type() == QEvent::Close)
|
if (watched == jobDock && event->type() == QEvent::Close)
|
||||||
{
|
{
|
||||||
if(jobDock->isFloating())
|
if (jobDock->isFloating())
|
||||||
{
|
{
|
||||||
QTimer::singleShot(0, jobDock, [this]()
|
QTimer::singleShot(0, jobDock, [this]() { jobDock->setFloating(false); });
|
||||||
{
|
|
||||||
jobDock->setFloating(false);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
else if(watched == resPanelDock && event->type() == QEvent::Close)
|
else if (watched == resPanelDock && event->type() == QEvent::Close)
|
||||||
{
|
{
|
||||||
if(resPanelDock->isFloating())
|
if (resPanelDock->isFloating())
|
||||||
{
|
{
|
||||||
QTimer::singleShot(0, resPanelDock, [this]()
|
QTimer::singleShot(0, resPanelDock, [this]() { resPanelDock->setFloating(false); });
|
||||||
{
|
|
||||||
resPanelDock->setFloating(false);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // ENABLE_BACKGROUND_MANAGER
|
#endif // ENABLE_BACKGROUND_MANAGER
|
||||||
|
@ -1012,10 +1017,10 @@ void MainWindow::onJobSearchItemSelected()
|
||||||
{
|
{
|
||||||
db_id jobId = 0;
|
db_id jobId = 0;
|
||||||
QString tmp;
|
QString tmp;
|
||||||
if(!searchEdit->getData(jobId, tmp))
|
if (!searchEdit->getData(jobId, tmp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
searchEdit->clear(); //Clear text
|
searchEdit->clear(); // Clear text
|
||||||
Session->getViewManager()->requestJobSelection(jobId, true, true);
|
Session->getViewManager()->requestJobSelection(jobId, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ public:
|
||||||
void loadFile(const QString &fileName);
|
void loadFile(const QString &fileName);
|
||||||
|
|
||||||
bool closeSession();
|
bool closeSession();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onStationManager();
|
void onStationManager();
|
||||||
|
|
||||||
|
@ -140,8 +140,11 @@ private:
|
||||||
|
|
||||||
QActionGroup *databaseActionGroup;
|
QActionGroup *databaseActionGroup;
|
||||||
|
|
||||||
enum { MaxRecentFiles = 5 };
|
enum
|
||||||
QAction* recentFileActs[MaxRecentFiles];
|
{
|
||||||
|
MaxRecentFiles = 5
|
||||||
|
};
|
||||||
|
QAction *recentFileActs[MaxRecentFiles];
|
||||||
|
|
||||||
CentralWidgetMode m_mode;
|
CentralWidgetMode m_mode;
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent) :
|
||||||
pathReadOnlyEdit->setPlaceholderText(tr("No opened file"));
|
pathReadOnlyEdit->setPlaceholderText(tr("No opened file"));
|
||||||
pathReadOnlyEdit->setReadOnly(true);
|
pathReadOnlyEdit->setReadOnly(true);
|
||||||
|
|
||||||
//TODO: make pretty and maybe add other informations like metadata versions
|
// TODO: make pretty and maybe add other informations like metadata versions
|
||||||
|
|
||||||
setMinimumSize(200, 200);
|
setMinimumSize(200, 200);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,19 +28,20 @@ Scope::Scope(const char *fn, const char *s, const char *e) :
|
||||||
start(s),
|
start(s),
|
||||||
end(e)
|
end(e)
|
||||||
{
|
{
|
||||||
qDebug().nospace().noquote()
|
qDebug().nospace().noquote() << start << QByteArray(" ").repeated(stackLevel) << ">>> " << func
|
||||||
<< start << QByteArray(" ").repeated(stackLevel) << ">>> " << func << end;
|
<< end;
|
||||||
stackLevel++;
|
stackLevel++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope::~Scope()
|
Scope::~Scope()
|
||||||
{
|
{
|
||||||
stackLevel--;
|
stackLevel--;
|
||||||
qDebug().nospace().noquote()
|
qDebug().nospace().noquote() << start << QByteArray(" ").repeated(stackLevel) << "<<< " << func
|
||||||
<< start << QByteArray(" ").repeated(stackLevel) << "<<< " << func << end;
|
<< end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeTimer::ScopeTimer(const char *fn, const char *s, const char *e) :Scope(fn, s, e)
|
ScopeTimer::ScopeTimer(const char *fn, const char *s, const char *e) :
|
||||||
|
Scope(fn, s, e)
|
||||||
{
|
{
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,57 +20,52 @@
|
||||||
#ifndef SCOPEDEBUG_H
|
#ifndef SCOPEDEBUG_H
|
||||||
#define SCOPEDEBUG_H
|
#define SCOPEDEBUG_H
|
||||||
|
|
||||||
|
#define SHELL_RESET "\033[0m"
|
||||||
|
|
||||||
#define SHELL_RESET "\033[0m"
|
#define SHELL_RED "\033[031m"
|
||||||
|
#define SHELL_GREEN "\033[032m"
|
||||||
#define SHELL_RED "\033[031m"
|
#define SHELL_YELLOW "\033[033m"
|
||||||
#define SHELL_GREEN "\033[032m"
|
#define SHELL_BLUE "\033[034m"
|
||||||
#define SHELL_YELLOW "\033[033m"
|
|
||||||
#define SHELL_BLUE "\033[034m"
|
|
||||||
|
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
//#define NO_DEBUG_CALL_TRACE
|
// #define NO_DEBUG_CALL_TRACE
|
||||||
|
|
||||||
#ifndef NO_DEBUG_CALL_TRACE
|
#ifndef NO_DEBUG_CALL_TRACE
|
||||||
|
|
||||||
class Scope
|
class Scope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Scope(const char *fn, const char *s="", const char* e="");
|
Scope(const char *fn, const char *s = "", const char *e = "");
|
||||||
~Scope();
|
~Scope();
|
||||||
|
|
||||||
const char *func, *start, *end;
|
const char *func, *start, *end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ScopeTimer : Scope
|
class ScopeTimer : Scope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScopeTimer(const char *fn, const char *s="", const char* e="");
|
ScopeTimer(const char *fn, const char *s = "", const char *e = "");
|
||||||
~ScopeTimer();
|
~ScopeTimer();
|
||||||
|
|
||||||
QElapsedTimer timer;
|
QElapsedTimer timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# define DEBUG_ENTRY_NAME(name) Scope DBG(name)
|
||||||
|
# define DEBUG_ENTRY DEBUG_ENTRY_NAME(__PRETTY_FUNCTION__)
|
||||||
|
# define DEBUG_COLOR_ENTRY(color) Scope DBG(__PRETTY_FUNCTION__, color, SHELL_RESET)
|
||||||
|
# define DEBUG_IMPORTANT_ENTRY DEBUG_COLOR_ENTRY(SHELL_GREEN)
|
||||||
|
|
||||||
|
# define DEBUG_TIME_ENTRY ScopeTimer DBG(__PRETTY_FUNCTION__)
|
||||||
# define DEBUG_ENTRY_NAME(name) Scope DBG(name)
|
|
||||||
# define DEBUG_ENTRY DEBUG_ENTRY_NAME(__PRETTY_FUNCTION__)
|
|
||||||
# define DEBUG_COLOR_ENTRY(color) Scope DBG(__PRETTY_FUNCTION__, color, SHELL_RESET)
|
|
||||||
# define DEBUG_IMPORTANT_ENTRY DEBUG_COLOR_ENTRY(SHELL_GREEN)
|
|
||||||
|
|
||||||
# define DEBUG_TIME_ENTRY ScopeTimer DBG(__PRETTY_FUNCTION__)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define DEBUG_ENTRY_NAME(name)
|
# define DEBUG_ENTRY_NAME(name)
|
||||||
# define DEBUG_ENTRY
|
# define DEBUG_ENTRY
|
||||||
# define DEBUG_COLOR_ENTRY(color)
|
# define DEBUG_COLOR_ENTRY(color)
|
||||||
# define DEBUG_IMPORTANT_ENTRY
|
# define DEBUG_IMPORTANT_ENTRY
|
||||||
# define DEBUG_TIME_ENTRY
|
# define DEBUG_TIME_ENTRY
|
||||||
#endif // NO_DEBUG_CALLTRACE
|
#endif // NO_DEBUG_CALLTRACE
|
||||||
|
|
||||||
#endif // SCOPEDEBUG_H
|
#endif // SCOPEDEBUG_H
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "db_metadata/metadatamanager.h"
|
#include "db_metadata/metadatamanager.h"
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
#include "backgroundmanager/backgroundmanager.h"
|
# include "backgroundmanager/backgroundmanager.h"
|
||||||
#endif // ENABLE_BACKGROUND_MANAGER
|
#endif // ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
|
||||||
MeetingSession* MeetingSession::session;
|
MeetingSession *MeetingSession::session;
|
||||||
QString MeetingSession::appDataPath;
|
QString MeetingSession::appDataPath;
|
||||||
const QLocale MeetingSession::embeddedLocale = QLocale(QLocale::English, QLocale::UnitedStates);
|
const QLocale MeetingSession::embeddedLocale = QLocale(QLocale::English, QLocale::UnitedStates);
|
||||||
|
|
||||||
|
@ -54,13 +54,14 @@ MeetingSession::MeetingSession() :
|
||||||
m_Db(nullptr),
|
m_Db(nullptr),
|
||||||
sheetExportTranslator(nullptr)
|
sheetExportTranslator(nullptr)
|
||||||
{
|
{
|
||||||
session = this; //Global singleton pointer
|
session = this; // Global singleton pointer
|
||||||
|
|
||||||
QString settings_file;
|
QString settings_file;
|
||||||
if(qApp->arguments().contains("test"))
|
if (qApp->arguments().contains("test"))
|
||||||
{
|
{
|
||||||
//If testing use exe folder instead of AppData
|
// If testing use exe folder instead of AppData
|
||||||
settings_file = QCoreApplication::applicationDirPath() + QStringLiteral("/mrtp_settings.ini");
|
settings_file =
|
||||||
|
QCoreApplication::applicationDirPath() + QStringLiteral("/mrtp_settings.ini");
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSettings(settings_file);
|
loadSettings(settings_file);
|
||||||
|
@ -76,7 +77,7 @@ MeetingSession::MeetingSession() :
|
||||||
|
|
||||||
MeetingSession::~MeetingSession()
|
MeetingSession::~MeetingSession()
|
||||||
{
|
{
|
||||||
//Delete sheet export translator
|
// Delete sheet export translator
|
||||||
setSheetExportTranslator(nullptr, sheetExportLocale);
|
setSheetExportTranslator(nullptr, sheetExportLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,29 +91,29 @@ DB_Error MeetingSession::openDB(const QString &str, bool ignoreVersion)
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
DB_Error err = closeDB();
|
DB_Error err = closeDB();
|
||||||
if(err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
if (err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||||
{
|
{
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
//try{
|
// try{
|
||||||
if(m_Db.connect(str.toUtf8(), SQLITE_OPEN_READWRITE) != SQLITE_OK)
|
if (m_Db.connect(str.toUtf8(), SQLITE_OPEN_READWRITE) != SQLITE_OK)
|
||||||
{
|
{
|
||||||
//throw database_error(m_Db);
|
// throw database_error(m_Db);
|
||||||
qWarning() << "DB:" << m_Db.error_msg();
|
qWarning() << "DB:" << m_Db.error_msg();
|
||||||
return DB_Error::GenericError;
|
return DB_Error::GenericError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ignoreVersion)
|
if (!ignoreVersion)
|
||||||
{
|
{
|
||||||
qint64 version = 0;
|
qint64 version = 0;
|
||||||
switch (metaDataMgr->getInt64(version, MetaDataKey::FormatVersionKey))
|
switch (metaDataMgr->getInt64(version, MetaDataKey::FormatVersionKey))
|
||||||
{
|
{
|
||||||
case MetaDataKey::Result::ValueFound:
|
case MetaDataKey::Result::ValueFound:
|
||||||
{
|
{
|
||||||
if(version < FormatVersion)
|
if (version < FormatVersion)
|
||||||
return DB_Error::FormatTooOld;
|
return DB_Error::FormatTooOld;
|
||||||
else if(version > FormatVersion)
|
else if (version > FormatVersion)
|
||||||
return DB_Error::FormatTooNew;
|
return DB_Error::FormatTooNew;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -123,38 +124,38 @@ DB_Error MeetingSession::openDB(const QString &str, bool ignoreVersion)
|
||||||
|
|
||||||
fileName = str;
|
fileName = str;
|
||||||
|
|
||||||
//Enable foreign keys to ensure no invalid operation is allowed
|
// Enable foreign keys to ensure no invalid operation is allowed
|
||||||
m_Db.enable_foreign_keys(true);
|
m_Db.enable_foreign_keys(true);
|
||||||
m_Db.enable_extended_result_codes(true);
|
m_Db.enable_extended_result_codes(true);
|
||||||
|
|
||||||
// }catch(const char *msg)
|
// }catch(const char *msg)
|
||||||
// {
|
// {
|
||||||
// QMessageBox::warning(nullptr,
|
// QMessageBox::warning(nullptr,
|
||||||
// QObject::tr("Error"),
|
// QObject::tr("Error"),
|
||||||
// QObject::tr("Error while opening file:\n%1\n'%2'")
|
// QObject::tr("Error while opening file:\n%1\n'%2'")
|
||||||
// .arg(str)
|
// .arg(str)
|
||||||
// .arg(msg));
|
// .arg(msg));
|
||||||
// throw;
|
// throw;
|
||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
// catch(std::exception& e)
|
// catch(std::exception& e)
|
||||||
// {
|
// {
|
||||||
// QMessageBox::warning(nullptr,
|
// QMessageBox::warning(nullptr,
|
||||||
// QObject::tr("Error"),
|
// QObject::tr("Error"),
|
||||||
// QObject::tr("Error while opening file:\n%1\n'%2'")
|
// QObject::tr("Error while opening file:\n%1\n'%2'")
|
||||||
// .arg(str)
|
// .arg(str)
|
||||||
// .arg(e.what()));
|
// .arg(e.what()));
|
||||||
// throw;
|
// throw;
|
||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
// catch(...)
|
// catch(...)
|
||||||
// {
|
// {
|
||||||
// QMessageBox::warning(nullptr,
|
// QMessageBox::warning(nullptr,
|
||||||
// QObject::tr("Error"),
|
// QObject::tr("Error"),
|
||||||
// QObject::tr("Unknown error while opening file:\n%1").arg(str));
|
// QObject::tr("Unknown error while opening file:\n%1").arg(str));
|
||||||
// throw;
|
// throw;
|
||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
backgroundManager->handleSessionLoaded();
|
backgroundManager->handleSessionLoaded();
|
||||||
|
@ -167,7 +168,7 @@ DB_Error MeetingSession::closeDB()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
if(!m_Db.db())
|
if (!m_Db.db())
|
||||||
return DB_Error::DbNotOpen;
|
return DB_Error::DbNotOpen;
|
||||||
|
|
||||||
#ifdef SEARCHBOX_MODE_ASYNC
|
#ifdef SEARCHBOX_MODE_ASYNC
|
||||||
|
@ -178,27 +179,27 @@ DB_Error MeetingSession::closeDB()
|
||||||
backgroundManager->abortAllTasks();
|
backgroundManager->abortAllTasks();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!viewManager->closeEditors())
|
if (!viewManager->closeEditors())
|
||||||
return DB_Error::EditorsStillOpened; //User wants to continue editing
|
return DB_Error::EditorsStillOpened; // User wants to continue editing
|
||||||
|
|
||||||
//Close all graphs
|
// Close all graphs
|
||||||
viewManager->clearAllLineGraphs();
|
viewManager->clearAllLineGraphs();
|
||||||
|
|
||||||
releaseAllSavepoints();
|
releaseAllSavepoints();
|
||||||
|
|
||||||
//Calls sqlite3_close(), not forcing closing db like sqlite3_close_v2
|
// Calls sqlite3_close(), not forcing closing db like sqlite3_close_v2
|
||||||
//So in case the database is still used by some background task (returns SQLITE_BUSY)
|
// So in case the database is still used by some background task (returns SQLITE_BUSY)
|
||||||
//we abort closing and return. It's like nevere having closed, database is 100% working
|
// we abort closing and return. It's like nevere having closed, database is 100% working
|
||||||
int rc = m_Db.disconnect();
|
int rc = m_Db.disconnect();
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "Err: closing db" << m_Db.error_code() << m_Db.error_msg();
|
qWarning() << "Err: closing db" << m_Db.error_code() << m_Db.error_msg();
|
||||||
|
|
||||||
if(rc == SQLITE_BUSY)
|
if (rc == SQLITE_BUSY)
|
||||||
{
|
{
|
||||||
return DB_Error::DbBusyWhenClosing;
|
return DB_Error::DbBusyWhenClosing;
|
||||||
}
|
}
|
||||||
//return false;
|
// return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
@ -210,22 +211,24 @@ DB_Error MeetingSession::closeDB()
|
||||||
return DB_Error::NoError;
|
return DB_Error::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
DB_Error MeetingSession::createNewDB(const QString& file)
|
DB_Error MeetingSession::createNewDB(const QString &file)
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
DB_Error err = closeDB();
|
DB_Error err = closeDB();
|
||||||
if(err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
if (err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||||
{
|
{
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = SQLITE_OK;
|
int result = SQLITE_OK;
|
||||||
#define CHECK(code) if((code) != SQLITE_OK) qWarning() << __LINE__ << (code) << m_Db.error_code() << m_Db.error_msg()
|
#define CHECK(code) \
|
||||||
|
if ((code) != SQLITE_OK) \
|
||||||
|
qWarning() << __LINE__ << (code) << m_Db.error_code() << m_Db.error_msg()
|
||||||
|
|
||||||
result = m_Db.connect(file.toUtf8(), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
result = m_Db.connect(file.toUtf8(), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
//See 'openDB()'
|
// See 'openDB()'
|
||||||
m_Db.enable_foreign_keys(true);
|
m_Db.enable_foreign_keys(true);
|
||||||
m_Db.enable_extended_result_codes(true);
|
m_Db.enable_extended_result_codes(true);
|
||||||
|
|
||||||
|
@ -237,7 +240,7 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
* if not explicitly set, it will trigger SQLITE_CONSTRAINT_FOREIGNKEY error.
|
* if not explicitly set, it will trigger SQLITE_CONSTRAINT_FOREIGNKEY error.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//Tables
|
// Tables
|
||||||
result = m_Db.execute("CREATE TABLE rs_models ("
|
result = m_Db.execute("CREATE TABLE rs_models ("
|
||||||
"id INTEGER,"
|
"id INTEGER,"
|
||||||
"name TEXT,"
|
"name TEXT,"
|
||||||
|
@ -278,81 +281,87 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"CHECK(length(name)>0) )");
|
"CHECK(length(name)>0) )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE station_tracks ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE station_tracks ("
|
||||||
"station_id INTEGER NOT NULL,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"pos INTEGER NOT NULL,"
|
"station_id INTEGER NOT NULL,"
|
||||||
"type INTEGER NOT NULL,"
|
"pos INTEGER NOT NULL,"
|
||||||
"track_length_cm INTEGER NOT NULL,"
|
"type INTEGER NOT NULL,"
|
||||||
"platf_length_cm INTEGET NOT NULL,"
|
"track_length_cm INTEGER NOT NULL,"
|
||||||
"freight_length_cm INTEGER NOT NULL,"
|
"platf_length_cm INTEGET NOT NULL,"
|
||||||
"max_axes INTEGER NOT NULL,"
|
"freight_length_cm INTEGER NOT NULL,"
|
||||||
"color_rgb INTEGER,"
|
"max_axes INTEGER NOT NULL,"
|
||||||
"name TEXT NOT NULL,"
|
"color_rgb INTEGER,"
|
||||||
"CHECK("
|
"name TEXT NOT NULL,"
|
||||||
" length(name)>0 AND max_axes>=2 AND track_length_cm>0"
|
"CHECK("
|
||||||
" AND (platf_length_cm BETWEEN 0 AND track_length_cm)"
|
" length(name)>0 AND max_axes>=2 AND track_length_cm>0"
|
||||||
" AND (freight_length_cm BETWEEN 0 AND track_length_cm)"
|
" AND (platf_length_cm BETWEEN 0 AND track_length_cm)"
|
||||||
"),"
|
" AND (freight_length_cm BETWEEN 0 AND track_length_cm)"
|
||||||
"UNIQUE(station_id, pos),"
|
"),"
|
||||||
"UNIQUE(station_id, name),"
|
"UNIQUE(station_id, pos),"
|
||||||
"FOREIGN KEY (station_id) REFERENCES stations(id) ON UPDATE CASCADE ON DELETE CASCADE )");
|
"UNIQUE(station_id, name),"
|
||||||
|
"FOREIGN KEY (station_id) REFERENCES stations(id) ON UPDATE CASCADE ON DELETE CASCADE )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE station_gates ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE station_gates ("
|
||||||
"station_id INTEGER NOT NULL,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"out_track_count INTEGER NOT NULL,"
|
"station_id INTEGER NOT NULL,"
|
||||||
"type INTEGER NOT NULL,"
|
"out_track_count INTEGER NOT NULL,"
|
||||||
"def_in_platf_id INTEGER,"
|
"type INTEGER NOT NULL,"
|
||||||
"name TEXT NOT NULL,"
|
"def_in_platf_id INTEGER,"
|
||||||
"side INTEGER NOT NULL,"
|
"name TEXT NOT NULL,"
|
||||||
"CHECK("
|
"side INTEGER NOT NULL,"
|
||||||
" out_track_count>0 AND (type&(1<<0) OR type&(1<<1))"
|
"CHECK("
|
||||||
" AND (length(name)=1 AND name BETWEEN 'A' AND 'Z')"
|
" out_track_count>0 AND (type&(1<<0) OR type&(1<<1))"
|
||||||
")," //NOTE: see utils::GateType
|
" AND (length(name)=1 AND name BETWEEN 'A' AND 'Z')"
|
||||||
"FOREIGN KEY (station_id) REFERENCES stations(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
")," // NOTE: see utils::GateType
|
||||||
"FOREIGN KEY(def_in_platf_id) REFERENCES station_tracks(id) ON UPDATE CASCADE ON DELETE SET NULL,"
|
"FOREIGN KEY (station_id) REFERENCES stations(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||||
"UNIQUE(station_id,name) )");
|
"FOREIGN KEY(def_in_platf_id) REFERENCES station_tracks(id) ON UPDATE CASCADE ON DELETE SET "
|
||||||
|
"NULL,"
|
||||||
|
"UNIQUE(station_id,name) )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE station_gate_connections ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE station_gate_connections ("
|
||||||
"track_id INTEGER NOT NULL,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"track_side INTEGER NOT NULL,"
|
"track_id INTEGER NOT NULL,"
|
||||||
"gate_id INTEGER NOT NULL,"
|
"track_side INTEGER NOT NULL,"
|
||||||
"gate_track INTEGER NOT NULL,"
|
"gate_id INTEGER NOT NULL,"
|
||||||
"UNIQUE(gate_id,track_id,track_side,gate_track),"
|
"gate_track INTEGER NOT NULL,"
|
||||||
"FOREIGN KEY (track_id) REFERENCES station_tracks(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
"UNIQUE(gate_id,track_id,track_side,gate_track),"
|
||||||
"FOREIGN KEY (gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE )");
|
"FOREIGN KEY (track_id) REFERENCES station_tracks(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||||
|
"FOREIGN KEY (gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE railway_segments ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE railway_segments ("
|
||||||
"in_gate_id INTEGER NOT NULL,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"out_gate_id INTEGER NOT NULL,"
|
"in_gate_id INTEGER NOT NULL,"
|
||||||
"name TEXT,"
|
"out_gate_id INTEGER NOT NULL,"
|
||||||
"max_speed_kmh INTEGER NOT NULL,"
|
"name TEXT,"
|
||||||
"type INTEGER NOT NULL,"
|
"max_speed_kmh INTEGER NOT NULL,"
|
||||||
"distance_meters INTEGER NOT NULL,"
|
"type INTEGER NOT NULL,"
|
||||||
"UNIQUE(in_gate_id),"
|
"distance_meters INTEGER NOT NULL,"
|
||||||
"UNIQUE(out_gate_id),"
|
"UNIQUE(in_gate_id),"
|
||||||
"FOREIGN KEY(in_gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
"UNIQUE(out_gate_id),"
|
||||||
"FOREIGN KEY(out_gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
"FOREIGN KEY(in_gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||||
"CHECK(in_gate_id<>out_gate_id AND"
|
"FOREIGN KEY(out_gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||||
" max_speed_kmh>=10 AND"
|
"CHECK(in_gate_id<>out_gate_id AND"
|
||||||
" distance_meters>=100 AND"
|
" max_speed_kmh>=10 AND"
|
||||||
" length(name)>0) )");
|
" distance_meters>=100 AND"
|
||||||
|
" length(name)>0) )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE railway_connections ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE railway_connections ("
|
||||||
"seg_id INTEGER NOT NULL,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"in_track INTEGER NOT NULL,"
|
"seg_id INTEGER NOT NULL,"
|
||||||
"out_track INTEGER NOT NULL,"
|
"in_track INTEGER NOT NULL,"
|
||||||
"UNIQUE(seg_id,in_track),"
|
"out_track INTEGER NOT NULL,"
|
||||||
"UNIQUE(seg_id,out_track),"
|
"UNIQUE(seg_id,in_track),"
|
||||||
"FOREIGN KEY(seg_id) REFERENCES railway_segments(id) ON UPDATE CASCADE ON DELETE RESTRICT )");
|
"UNIQUE(seg_id,out_track),"
|
||||||
|
"FOREIGN KEY(seg_id) REFERENCES railway_segments(id) ON UPDATE CASCADE ON DELETE RESTRICT )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE lines ("
|
result = m_Db.execute("CREATE TABLE lines ("
|
||||||
|
@ -361,17 +370,18 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"start_meters INTEGER NOT NULL DEFAULT 0 )");
|
"start_meters INTEGER NOT NULL DEFAULT 0 )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE line_segments ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE line_segments ("
|
||||||
"line_id INTEGER NOT NULL,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"seg_id INTEGER NOT NULL,"
|
"line_id INTEGER NOT NULL,"
|
||||||
"direction INTEGER NOT NULL,"
|
"seg_id INTEGER NOT NULL,"
|
||||||
"pos INTEGER NOT NULL,"
|
"direction INTEGER NOT NULL,"
|
||||||
"FOREIGN KEY(line_id) REFERENCES lines(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
"pos INTEGER NOT NULL,"
|
||||||
"FOREIGN KEY(seg_id) REFERENCES railway_segments(id) ON UPDATE CASCADE ON DELETE RESTRICT,"
|
"FOREIGN KEY(line_id) REFERENCES lines(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||||
"UNIQUE(line_id, seg_id)"
|
"FOREIGN KEY(seg_id) REFERENCES railway_segments(id) ON UPDATE CASCADE ON DELETE RESTRICT,"
|
||||||
"UNIQUE(line_id, pos)"
|
"UNIQUE(line_id, seg_id)"
|
||||||
"CHECK(pos<100) )"); //Allow up to 100 segments for each line
|
"UNIQUE(line_id, pos)"
|
||||||
|
"CHECK(pos<100) )"); // Allow up to 100 segments for each line
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE jobshifts ("
|
result = m_Db.execute("CREATE TABLE jobshifts ("
|
||||||
|
@ -379,34 +389,39 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"name TEXT UNIQUE NOT NULL)");
|
"name TEXT UNIQUE NOT NULL)");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE jobs ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE jobs ("
|
||||||
"category INTEGER NOT NULL DEFAULT 0,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"shift_id INTEGER,"
|
"category INTEGER NOT NULL DEFAULT 0,"
|
||||||
"FOREIGN KEY(shift_id) REFERENCES jobshifts(id) ON UPDATE CASCADE ON DELETE RESTRICT)");
|
"shift_id INTEGER,"
|
||||||
|
"FOREIGN KEY(shift_id) REFERENCES jobshifts(id) ON UPDATE CASCADE ON DELETE RESTRICT)");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE stops ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE stops ("
|
||||||
"job_id INTEGER NOT NULL,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"station_id INTEGER,"
|
"job_id INTEGER NOT NULL,"
|
||||||
"arrival INTEGER NOT NULL,"
|
"station_id INTEGER,"
|
||||||
"departure INTEGER NOT NULL,"
|
"arrival INTEGER NOT NULL,"
|
||||||
"type INTEGER NOT NULL,"
|
"departure INTEGER NOT NULL,"
|
||||||
"description TEXT,"
|
"type INTEGER NOT NULL,"
|
||||||
|
"description TEXT,"
|
||||||
|
|
||||||
"in_gate_conn INTEGER,"
|
"in_gate_conn INTEGER,"
|
||||||
"out_gate_conn INTEGER,"
|
"out_gate_conn INTEGER,"
|
||||||
"next_segment_conn_id INTEGER,"
|
"next_segment_conn_id INTEGER,"
|
||||||
|
|
||||||
"CHECK(arrival<=departure),"
|
"CHECK(arrival<=departure),"
|
||||||
"UNIQUE(job_id,arrival),"
|
"UNIQUE(job_id,arrival),"
|
||||||
"UNIQUE(job_id,departure),"
|
"UNIQUE(job_id,departure),"
|
||||||
"FOREIGN KEY(job_id) REFERENCES jobs(id) ON DELETE RESTRICT ON UPDATE CASCADE,"
|
"FOREIGN KEY(job_id) REFERENCES jobs(id) ON DELETE RESTRICT ON UPDATE CASCADE,"
|
||||||
"FOREIGN KEY(station_id) REFERENCES stations(id) ON DELETE RESTRICT ON UPDATE CASCADE,"
|
"FOREIGN KEY(station_id) REFERENCES stations(id) ON DELETE RESTRICT ON UPDATE CASCADE,"
|
||||||
"FOREIGN KEY(in_gate_conn) REFERENCES station_gate_connections(id) ON UPDATE CASCADE ON DELETE RESTRICT,"
|
"FOREIGN KEY(in_gate_conn) REFERENCES station_gate_connections(id) ON UPDATE CASCADE ON "
|
||||||
"FOREIGN KEY(out_gate_conn) REFERENCES station_gate_connections(id) ON UPDATE CASCADE ON DELETE RESTRICT,"
|
"DELETE RESTRICT,"
|
||||||
"FOREIGN KEY(next_segment_conn_id) REFERENCES railway_connections(id) ON UPDATE CASCADE ON DELETE RESTRICT )");
|
"FOREIGN KEY(out_gate_conn) REFERENCES station_gate_connections(id) ON UPDATE CASCADE ON "
|
||||||
|
"DELETE RESTRICT,"
|
||||||
|
"FOREIGN KEY(next_segment_conn_id) REFERENCES railway_connections(id) ON UPDATE CASCADE ON "
|
||||||
|
"DELETE RESTRICT )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE coupling ("
|
result = m_Db.execute("CREATE TABLE coupling ("
|
||||||
|
@ -420,41 +435,47 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"UNIQUE(stop_id,rs_id))");
|
"UNIQUE(stop_id,rs_id))");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
//Create also backup tables to save old stops and couplings before editing a job and restore them if user cancels the edits.
|
// Create also backup tables to save old stops and couplings before editing a job and restore
|
||||||
//NOTE: the structure of the table must be the same, remember to update theese if updating stops or couplings
|
// them if user cancels the edits. NOTE: the structure of the table must be the same, remember
|
||||||
|
// to update theese if updating stops or couplings
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE old_stops ("
|
result = m_Db.execute(
|
||||||
"id INTEGER PRIMARY KEY,"
|
"CREATE TABLE old_stops ("
|
||||||
"job_id INTEGER NOT NULL,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"station_id INTEGER,"
|
"job_id INTEGER NOT NULL,"
|
||||||
"arrival INTEGER NOT NULL,"
|
"station_id INTEGER,"
|
||||||
"departure INTEGER NOT NULL,"
|
"arrival INTEGER NOT NULL,"
|
||||||
"type INTEGER NOT NULL,"
|
"departure INTEGER NOT NULL,"
|
||||||
"description TEXT,"
|
"type INTEGER NOT NULL,"
|
||||||
|
"description TEXT,"
|
||||||
|
|
||||||
"in_gate_conn INTEGER,"
|
"in_gate_conn INTEGER,"
|
||||||
"out_gate_conn INTEGER,"
|
"out_gate_conn INTEGER,"
|
||||||
"next_segment_conn_id INTEGER,"
|
"next_segment_conn_id INTEGER,"
|
||||||
|
|
||||||
"CHECK(arrival<=departure),"
|
"CHECK(arrival<=departure),"
|
||||||
"UNIQUE(job_id,arrival),"
|
"UNIQUE(job_id,arrival),"
|
||||||
"UNIQUE(job_id,departure),"
|
"UNIQUE(job_id,departure),"
|
||||||
"FOREIGN KEY(job_id) REFERENCES jobs(id) ON DELETE RESTRICT ON UPDATE CASCADE,"
|
"FOREIGN KEY(job_id) REFERENCES jobs(id) ON DELETE RESTRICT ON UPDATE CASCADE,"
|
||||||
"FOREIGN KEY(station_id) REFERENCES stations(id) ON DELETE RESTRICT ON UPDATE CASCADE,"
|
"FOREIGN KEY(station_id) REFERENCES stations(id) ON DELETE RESTRICT ON UPDATE CASCADE,"
|
||||||
"FOREIGN KEY(in_gate_conn) REFERENCES station_gate_connections(id) ON UPDATE CASCADE ON DELETE RESTRICT,"
|
"FOREIGN KEY(in_gate_conn) REFERENCES station_gate_connections(id) ON UPDATE CASCADE ON "
|
||||||
"FOREIGN KEY(out_gate_conn) REFERENCES station_gate_connections(id) ON UPDATE CASCADE ON DELETE RESTRICT,"
|
"DELETE RESTRICT,"
|
||||||
"FOREIGN KEY(next_segment_conn_id) REFERENCES railway_connections(id) ON UPDATE CASCADE ON DELETE RESTRICT )");
|
"FOREIGN KEY(out_gate_conn) REFERENCES station_gate_connections(id) ON UPDATE CASCADE ON "
|
||||||
|
"DELETE RESTRICT,"
|
||||||
|
"FOREIGN KEY(next_segment_conn_id) REFERENCES railway_connections(id) ON UPDATE CASCADE ON "
|
||||||
|
"DELETE RESTRICT )");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE old_coupling ("
|
result =
|
||||||
"id INTEGER PRIMARY KEY,"
|
m_Db.execute("CREATE TABLE old_coupling ("
|
||||||
"stop_id INTEGER,"
|
"id INTEGER PRIMARY KEY,"
|
||||||
"rs_id INTEGER,"
|
"stop_id INTEGER,"
|
||||||
"operation INTEGER NOT NULL DEFAULT 0,"
|
"rs_id INTEGER,"
|
||||||
|
"operation INTEGER NOT NULL DEFAULT 0,"
|
||||||
|
|
||||||
"FOREIGN KEY(stop_id) REFERENCES old_stops(id) ON DELETE CASCADE," //Old stops
|
"FOREIGN KEY(stop_id) REFERENCES old_stops(id) ON DELETE CASCADE," // Old stops
|
||||||
"FOREIGN KEY(rs_id) REFERENCES rs_list(id) ON DELETE RESTRICT,"
|
"FOREIGN KEY(rs_id) REFERENCES rs_list(id) ON DELETE RESTRICT,"
|
||||||
"UNIQUE(stop_id,rs_id))");
|
"UNIQUE(stop_id,rs_id))");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE imported_rs_owners ("
|
result = m_Db.execute("CREATE TABLE imported_rs_owners ("
|
||||||
|
@ -465,7 +486,8 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"match_existing_id INTEGER,"
|
"match_existing_id INTEGER,"
|
||||||
"sheet_idx INTEGER,"
|
"sheet_idx INTEGER,"
|
||||||
"PRIMARY KEY(id),"
|
"PRIMARY KEY(id),"
|
||||||
"FOREIGN KEY(match_existing_id) REFERENCES rs_owners(id) ON UPDATE RESTRICT ON DELETE RESTRICT)");
|
"FOREIGN KEY(match_existing_id) REFERENCES rs_owners(id) ON UPDATE "
|
||||||
|
"RESTRICT ON DELETE RESTRICT)");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE imported_rs_models ("
|
result = m_Db.execute("CREATE TABLE imported_rs_models ("
|
||||||
|
@ -480,7 +502,8 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"type INTEGER,"
|
"type INTEGER,"
|
||||||
"sub_type INTEGER,"
|
"sub_type INTEGER,"
|
||||||
"PRIMARY KEY(id),"
|
"PRIMARY KEY(id),"
|
||||||
"FOREIGN KEY(match_existing_id) REFERENCES rs_models(id) ON UPDATE RESTRICT ON DELETE RESTRICT)");
|
"FOREIGN KEY(match_existing_id) REFERENCES rs_models(id) ON UPDATE "
|
||||||
|
"RESTRICT ON DELETE RESTRICT)");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE imported_rs_list ("
|
result = m_Db.execute("CREATE TABLE imported_rs_list ("
|
||||||
|
@ -491,8 +514,10 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"number INTEGER,"
|
"number INTEGER,"
|
||||||
"new_number INTEGER,"
|
"new_number INTEGER,"
|
||||||
"PRIMARY KEY(id),"
|
"PRIMARY KEY(id),"
|
||||||
"FOREIGN KEY(model_id) REFERENCES imported_rs_models(id) ON UPDATE RESTRICT ON DELETE RESTRICT,"
|
"FOREIGN KEY(model_id) REFERENCES imported_rs_models(id) ON UPDATE "
|
||||||
"FOREIGN KEY(owner_id) REFERENCES imported_rs_owners(id) ON UPDATE RESTRICT ON DELETE RESTRICT)");
|
"RESTRICT ON DELETE RESTRICT,"
|
||||||
|
"FOREIGN KEY(owner_id) REFERENCES imported_rs_owners(id) ON UPDATE "
|
||||||
|
"RESTRICT ON DELETE RESTRICT)");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TABLE metadata ("
|
result = m_Db.execute("CREATE TABLE metadata ("
|
||||||
|
@ -500,50 +525,56 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"val BLOB)");
|
"val BLOB)");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
//Triggers
|
// Triggers
|
||||||
|
|
||||||
//Prevent multiple segments on same station gate
|
// Prevent multiple segments on same station gate
|
||||||
result = m_Db.execute("CREATE TRIGGER multiple_gate_segments\n"
|
result =
|
||||||
"BEFORE INSERT ON railway_segments\n"
|
m_Db.execute("CREATE TRIGGER multiple_gate_segments\n"
|
||||||
"BEGIN\n"
|
"BEFORE INSERT ON railway_segments\n"
|
||||||
"SELECT RAISE(ABORT, 'Cannot connect same gate twice') FROM railway_segments WHERE in_gate_id=NEW.out_gate_id OR out_gate_id=NEW.in_gate_id;"
|
"BEGIN\n"
|
||||||
"END");
|
"SELECT RAISE(ABORT, 'Cannot connect same gate twice') FROM railway_segments "
|
||||||
|
"WHERE in_gate_id=NEW.out_gate_id OR out_gate_id=NEW.in_gate_id;"
|
||||||
|
"END");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
result = m_Db.execute("CREATE TRIGGER multiple_gate_segments_update_in\n"
|
result = m_Db.execute("CREATE TRIGGER multiple_gate_segments_update_in\n"
|
||||||
"BEFORE UPDATE OF in_gate_id ON railway_segments\n"
|
"BEFORE UPDATE OF in_gate_id ON railway_segments\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
"SELECT RAISE(ABORT, 'Cannot connect same gate twice') FROM railway_segments WHERE out_gate_id=NEW.in_gate_id;"
|
"SELECT RAISE(ABORT, 'Cannot connect same gate twice') FROM "
|
||||||
|
"railway_segments WHERE out_gate_id=NEW.in_gate_id;"
|
||||||
"END");
|
"END");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
result = m_Db.execute("CREATE TRIGGER multiple_gate_segments_update_out\n"
|
result = m_Db.execute("CREATE TRIGGER multiple_gate_segments_update_out\n"
|
||||||
"BEFORE UPDATE OF out_gate_id ON railway_segments\n"
|
"BEFORE UPDATE OF out_gate_id ON railway_segments\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
"SELECT RAISE(ABORT, 'Cannot connect same gate twice') FROM railway_segments WHERE in_gate_id=NEW.out_gate_id;"
|
"SELECT RAISE(ABORT, 'Cannot connect same gate twice') FROM "
|
||||||
|
"railway_segments WHERE in_gate_id=NEW.out_gate_id;"
|
||||||
"END");
|
"END");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
//Prevent connecting a track to a gate of a different station
|
// Prevent connecting a track to a gate of a different station
|
||||||
result = m_Db.execute("CREATE TRIGGER gate_conn_different_station\n"
|
result = m_Db.execute(
|
||||||
"BEFORE INSERT ON station_gate_connections\n"
|
"CREATE TRIGGER gate_conn_different_station\n"
|
||||||
"BEGIN\n"
|
"BEFORE INSERT ON station_gate_connections\n"
|
||||||
"SELECT RAISE(ABORT, 'Cannot connect platform of a different station') FROM station_tracks t"
|
"BEGIN\n"
|
||||||
" JOIN station_gates g ON g.id=NEW.gate_id"
|
"SELECT RAISE(ABORT, 'Cannot connect platform of a different station') FROM station_tracks t"
|
||||||
" WHERE t.id=NEW.track_id AND t.station_id<>g.station_id;"
|
" JOIN station_gates g ON g.id=NEW.gate_id"
|
||||||
"END");
|
" WHERE t.id=NEW.track_id AND t.station_id<>g.station_id;"
|
||||||
|
"END");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
result = m_Db.execute("CREATE TRIGGER gate_conn_different_station_update\n"
|
result = m_Db.execute(
|
||||||
"BEFORE UPDATE OF track_id,gate_id ON station_gate_connections\n"
|
"CREATE TRIGGER gate_conn_different_station_update\n"
|
||||||
"BEGIN\n"
|
"BEFORE UPDATE OF track_id,gate_id ON station_gate_connections\n"
|
||||||
"SELECT RAISE(ABORT, 'Cannot connect platform of a different station') FROM station_tracks t"
|
"BEGIN\n"
|
||||||
" JOIN station_gates g ON g.id=NEW.gate_id"
|
"SELECT RAISE(ABORT, 'Cannot connect platform of a different station') FROM station_tracks t"
|
||||||
" WHERE t.id=NEW.track_id AND t.station_id<>g.station_id;"
|
" JOIN station_gates g ON g.id=NEW.gate_id"
|
||||||
"END");
|
" WHERE t.id=NEW.track_id AND t.station_id<>g.station_id;"
|
||||||
|
"END");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
//FIXME: Remote possibility of updating 'station_id' of track or gate.
|
// FIXME: Remote possibility of updating 'station_id' of track or gate.
|
||||||
|
|
||||||
//Prevent connecting gate track out of bound
|
// Prevent connecting gate track out of bound
|
||||||
result = m_Db.execute("CREATE TRIGGER gate_conn_gate_track_bound\n"
|
result = m_Db.execute("CREATE TRIGGER gate_conn_gate_track_bound\n"
|
||||||
"BEFORE INSERT ON station_gate_connections\n"
|
"BEFORE INSERT ON station_gate_connections\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
|
@ -563,18 +594,20 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
result = m_Db.execute("CREATE TRIGGER gate_out_track_bound_update\n"
|
result = m_Db.execute("CREATE TRIGGER gate_out_track_bound_update\n"
|
||||||
"BEFORE UPDATE OF out_track_count ON station_gates\n"
|
"BEFORE UPDATE OF out_track_count ON station_gates\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
"SELECT RAISE(ABORT, 'Cannot remove gate tracks. Platforms connected.') FROM station_gate_connections c"
|
"SELECT RAISE(ABORT, 'Cannot remove gate tracks. Platforms connected.') "
|
||||||
|
"FROM station_gate_connections c"
|
||||||
" WHERE c.gate_id=NEW.id AND NEW.out_track_count<=c.gate_track;"
|
" WHERE c.gate_id=NEW.id AND NEW.out_track_count<=c.gate_track;"
|
||||||
"END");
|
"END");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
//Prevent setting gate default track to a track which is not connected to it
|
// Prevent setting gate default track to a track which is not connected to it
|
||||||
result = m_Db.execute("CREATE TRIGGER gate_def_platf_not_connected\n"
|
result = m_Db.execute("CREATE TRIGGER gate_def_platf_not_connected\n"
|
||||||
"BEFORE INSERT ON station_gates\n"
|
"BEFORE INSERT ON station_gates\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
"SELECT RAISE(ABORT, 'Platform not connected to this gate') WHERE"
|
"SELECT RAISE(ABORT, 'Platform not connected to this gate') WHERE"
|
||||||
" NEW.def_in_platf_id NOT NULL AND NOT EXISTS ("
|
" NEW.def_in_platf_id NOT NULL AND NOT EXISTS ("
|
||||||
" SELECT 1 FROM station_gate_connections WHERE track_id=NEW.def_in_platf_id AND gate_id=NEW.id"
|
" SELECT 1 FROM station_gate_connections WHERE "
|
||||||
|
"track_id=NEW.def_in_platf_id AND gate_id=NEW.id"
|
||||||
");"
|
");"
|
||||||
"END");
|
"END");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
@ -584,13 +617,13 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
"SELECT RAISE(ABORT, 'Platform not connected to this gate') WHERE"
|
"SELECT RAISE(ABORT, 'Platform not connected to this gate') WHERE"
|
||||||
" NEW.def_in_platf_id NOT NULL AND NOT EXISTS ("
|
" NEW.def_in_platf_id NOT NULL AND NOT EXISTS ("
|
||||||
" SELECT 1 FROM station_gate_connections WHERE track_id=NEW.def_in_platf_id AND gate_id=NEW.id"
|
" SELECT 1 FROM station_gate_connections WHERE "
|
||||||
|
"track_id=NEW.def_in_platf_id AND gate_id=NEW.id"
|
||||||
");"
|
");"
|
||||||
"END");
|
"END");
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
|
|
||||||
//FIXME: if setting default gate track but then delete track connection -> invalid state
|
// FIXME: if setting default gate track but then delete track connection -> invalid state
|
||||||
|
|
||||||
|
|
||||||
#undef CHECK
|
#undef CHECK
|
||||||
|
|
||||||
|
@ -605,25 +638,25 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
||||||
* Theese tables are used during RS importation and are cleared when the process
|
* Theese tables are used during RS importation and are cleared when the process
|
||||||
* completes or gets canceled by the user
|
* completes or gets canceled by the user
|
||||||
* If they are not empty it might be because the application crashed before clearing theese tables
|
* If they are not empty it might be because the application crashed before clearing theese tables
|
||||||
*/
|
*/
|
||||||
bool MeetingSession::checkImportRSTablesEmpty()
|
bool MeetingSession::checkImportRSTablesEmpty()
|
||||||
{
|
{
|
||||||
query q(m_Db, "SELECT COUNT(1) FROM imported_rs_list");
|
query q(m_Db, "SELECT COUNT(1) FROM imported_rs_list");
|
||||||
q.step();
|
q.step();
|
||||||
int count = q.getRows().get<int>(0);
|
int count = q.getRows().get<int>(0);
|
||||||
if(count)
|
if (count)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
q.prepare("SELECT COUNT(1) FROM imported_rs_models");
|
q.prepare("SELECT COUNT(1) FROM imported_rs_models");
|
||||||
q.step();
|
q.step();
|
||||||
count = q.getRows().get<int>(0);
|
count = q.getRows().get<int>(0);
|
||||||
if(count)
|
if (count)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
q.prepare("SELECT COUNT(1) FROM imported_rs_owners");
|
q.prepare("SELECT COUNT(1) FROM imported_rs_owners");
|
||||||
q.step();
|
q.step();
|
||||||
count = q.getRows().get<int>(0);
|
count = q.getRows().get<int>(0);
|
||||||
if(count)
|
if (count)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -631,15 +664,15 @@ bool MeetingSession::checkImportRSTablesEmpty()
|
||||||
bool MeetingSession::clearImportRSTables()
|
bool MeetingSession::clearImportRSTables()
|
||||||
{
|
{
|
||||||
command cmd(m_Db, "DELETE FROM imported_rs_list");
|
command cmd(m_Db, "DELETE FROM imported_rs_list");
|
||||||
if(cmd.execute() != SQLITE_OK)
|
if (cmd.execute() != SQLITE_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cmd.prepare("DELETE FROM imported_rs_models");
|
cmd.prepare("DELETE FROM imported_rs_models");
|
||||||
if(cmd.execute() != SQLITE_OK)
|
if (cmd.execute() != SQLITE_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cmd.prepare("DELETE FROM imported_rs_owners");
|
cmd.prepare("DELETE FROM imported_rs_owners");
|
||||||
if(cmd.execute() != SQLITE_OK)
|
if (cmd.execute() != SQLITE_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -647,15 +680,15 @@ bool MeetingSession::clearImportRSTables()
|
||||||
|
|
||||||
bool MeetingSession::setSavepoint(const QString &pointname)
|
bool MeetingSession::setSavepoint(const QString &pointname)
|
||||||
{
|
{
|
||||||
if(!m_Db.db())
|
if (!m_Db.db())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(savepointList.contains(pointname))
|
if (savepointList.contains(pointname))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
QString sql = QStringLiteral("SAVEPOINT %1;");
|
QString sql = QStringLiteral("SAVEPOINT %1;");
|
||||||
|
|
||||||
if(m_Db.execute(sql.arg(pointname).toUtf8()) != SQLITE_OK)
|
if (m_Db.execute(sql.arg(pointname).toUtf8()) != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qDebug() << m_Db.error_msg();
|
qDebug() << m_Db.error_msg();
|
||||||
return false;
|
return false;
|
||||||
|
@ -667,15 +700,15 @@ bool MeetingSession::setSavepoint(const QString &pointname)
|
||||||
|
|
||||||
bool MeetingSession::releaseSavepoint(const QString &pointname)
|
bool MeetingSession::releaseSavepoint(const QString &pointname)
|
||||||
{
|
{
|
||||||
if(!m_Db.db())
|
if (!m_Db.db())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!savepointList.contains(pointname))
|
if (!savepointList.contains(pointname))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
QString sql = QStringLiteral("RELEASE %1;");
|
QString sql = QStringLiteral("RELEASE %1;");
|
||||||
|
|
||||||
if(m_Db.execute(sql.arg(pointname).toUtf8()) != SQLITE_OK)
|
if (m_Db.execute(sql.arg(pointname).toUtf8()) != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qDebug() << m_Db.error_msg();
|
qDebug() << m_Db.error_msg();
|
||||||
return false;
|
return false;
|
||||||
|
@ -689,15 +722,15 @@ bool MeetingSession::releaseSavepoint(const QString &pointname)
|
||||||
|
|
||||||
bool MeetingSession::revertToSavepoint(const QString &pointname)
|
bool MeetingSession::revertToSavepoint(const QString &pointname)
|
||||||
{
|
{
|
||||||
if(!m_Db.db())
|
if (!m_Db.db())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!savepointList.contains(pointname))
|
if (!savepointList.contains(pointname))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QString sql = QStringLiteral("ROLLBACK TO SAVEPOINT %1;");
|
QString sql = QStringLiteral("ROLLBACK TO SAVEPOINT %1;");
|
||||||
|
|
||||||
if(m_Db.execute(sql.arg(pointname).toUtf8()) != SQLITE_OK)
|
if (m_Db.execute(sql.arg(pointname).toUtf8()) != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qDebug() << m_Db.error_msg();
|
qDebug() << m_Db.error_msg();
|
||||||
return false;
|
return false;
|
||||||
|
@ -711,17 +744,17 @@ bool MeetingSession::revertToSavepoint(const QString &pointname)
|
||||||
|
|
||||||
bool MeetingSession::releaseAllSavepoints()
|
bool MeetingSession::releaseAllSavepoints()
|
||||||
{
|
{
|
||||||
if(!m_Db.db())
|
if (!m_Db.db())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(const QString& point : qAsConst(savepointList))
|
for (const QString &point : qAsConst(savepointList))
|
||||||
{
|
{
|
||||||
if(!releaseSavepoint(point))
|
if (!releaseSavepoint(point))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When still in a transaction, commit that too
|
// When still in a transaction, commit that too
|
||||||
if(sqlite3_get_autocommit(m_Db.db()) == 0)
|
if (sqlite3_get_autocommit(m_Db.db()) == 0)
|
||||||
m_Db.execute("COMMIT;");
|
m_Db.execute("COMMIT;");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -729,9 +762,9 @@ bool MeetingSession::releaseAllSavepoints()
|
||||||
|
|
||||||
bool MeetingSession::revertAll()
|
bool MeetingSession::revertAll()
|
||||||
{
|
{
|
||||||
for(const QString& point : qAsConst(savepointList))
|
for (const QString &point : qAsConst(savepointList))
|
||||||
{
|
{
|
||||||
if(!revertToSavepoint(point))
|
if (!revertToSavepoint(point))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -739,59 +772,59 @@ bool MeetingSession::revertAll()
|
||||||
|
|
||||||
QColor MeetingSession::colorForCat(JobCategory cat)
|
QColor MeetingSession::colorForCat(JobCategory cat)
|
||||||
{
|
{
|
||||||
QColor col = settings.getCategoryColor(int(cat)); //TODO: maybe session-specific
|
QColor col = settings.getCategoryColor(int(cat)); // TODO: maybe session-specific
|
||||||
if(col.isValid())
|
if (col.isValid())
|
||||||
return col;
|
return col;
|
||||||
return QColor(Qt::gray); //Error
|
return QColor(Qt::gray); // Error
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeetingSession::locateAppdata()
|
void MeetingSession::locateAppdata()
|
||||||
{
|
{
|
||||||
appDataPath = QStringLiteral("%1/%2/%3")
|
appDataPath = QStringLiteral("%1/%2/%3")
|
||||||
.arg(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation),
|
.arg(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation),
|
||||||
AppCompany, AppProductShort);
|
AppCompany, AppProductShort);
|
||||||
appDataPath = QDir::cleanPath(appDataPath);
|
appDataPath = QDir::cleanPath(appDataPath);
|
||||||
qDebug() << appDataPath;
|
qDebug() << appDataPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeetingSession::setSheetExportTranslator(QTranslator *translator, const QLocale &loc)
|
void MeetingSession::setSheetExportTranslator(QTranslator *translator, const QLocale &loc)
|
||||||
{
|
{
|
||||||
//NOTE: if Sheet Language is of Application Language then set a nullptr translator
|
// NOTE: if Sheet Language is of Application Language then set a nullptr translator
|
||||||
//If translator is valid use it
|
// If translator is valid use it
|
||||||
//If translator is nullptr and language is default English locale, use hardcoded strings
|
// If translator is nullptr and language is default English locale, use hardcoded strings
|
||||||
//If translator is nullptr and language is different from English, use default translations
|
// If translator is nullptr and language is different from English, use default translations
|
||||||
|
|
||||||
if(sheetExportTranslator && sheetExportTranslator != translator)
|
if (sheetExportTranslator && sheetExportTranslator != translator)
|
||||||
delete sheetExportTranslator;
|
delete sheetExportTranslator;
|
||||||
sheetExportTranslator = translator;
|
sheetExportTranslator = translator;
|
||||||
sheetExportLocale = loc;
|
sheetExportLocale = loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeetingSession::loadSettings(const QString& settings_file)
|
void MeetingSession::loadSettings(const QString &settings_file)
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
if(settings_file.isEmpty())
|
if (settings_file.isEmpty())
|
||||||
settings.loadSettings(appDataPath + QStringLiteral("/mrtp_settings.ini"));
|
settings.loadSettings(appDataPath + QStringLiteral("/mrtp_settings.ini"));
|
||||||
else
|
else
|
||||||
settings.loadSettings(settings_file);
|
settings.loadSettings(settings_file);
|
||||||
|
|
||||||
hourOffset = settings.getHourOffset();
|
hourOffset = settings.getHourOffset();
|
||||||
stationOffset = settings.getStationOffset();
|
stationOffset = settings.getStationOffset();
|
||||||
horizOffset = settings.getHorizontalOffset();
|
horizOffset = settings.getHorizontalOffset();
|
||||||
vertOffset = settings.getVerticalOffset();
|
vertOffset = settings.getVerticalOffset();
|
||||||
platformOffset = settings.getPlatformOffset();
|
platformOffset = settings.getPlatformOffset();
|
||||||
|
|
||||||
jobLineWidth = settings.getJobLineWidth();
|
jobLineWidth = settings.getJobLineWidth();
|
||||||
|
|
||||||
originalAppLocale = settings.getLanguage();
|
originalAppLocale = settings.getLanguage();
|
||||||
|
|
||||||
//Default initialize to same value of application language
|
// Default initialize to same value of application language
|
||||||
setSheetExportTranslator(nullptr, originalAppLocale);
|
setSheetExportTranslator(nullptr, originalAppLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
BackgroundManager* MeetingSession::getBackgroundManager() const
|
BackgroundManager *MeetingSession::getBackgroundManager() const
|
||||||
{
|
{
|
||||||
return backgroundManager.get();
|
return backgroundManager.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ using namespace sqlite3pp;
|
||||||
|
|
||||||
#include <settings/appsettings.h>
|
#include <settings/appsettings.h>
|
||||||
|
|
||||||
|
|
||||||
class ViewManager;
|
class ViewManager;
|
||||||
class MetaDataManager;
|
class MetaDataManager;
|
||||||
|
|
||||||
|
@ -65,53 +64,60 @@ class MeetingSession : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static MeetingSession* session;
|
static MeetingSession *session;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MeetingSession();
|
MeetingSession();
|
||||||
~MeetingSession();
|
~MeetingSession();
|
||||||
|
|
||||||
static MeetingSession* Get();
|
static MeetingSession *Get();
|
||||||
|
|
||||||
inline ViewManager* getViewManager() { return viewManager.get(); }
|
inline ViewManager *getViewManager()
|
||||||
|
{
|
||||||
|
return viewManager.get();
|
||||||
|
}
|
||||||
|
|
||||||
inline MetaDataManager* getMetaDataManager() { return metaDataMgr.get(); }
|
inline MetaDataManager *getMetaDataManager()
|
||||||
|
{
|
||||||
|
return metaDataMgr.get();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
BackgroundManager *getBackgroundManager() const;
|
BackgroundManager *getBackgroundManager() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
//Shifts
|
// Shifts
|
||||||
void shiftAdded(db_id shiftId);
|
void shiftAdded(db_id shiftId);
|
||||||
void shiftRemoved(db_id shiftId);
|
void shiftRemoved(db_id shiftId);
|
||||||
void shiftNameChanged(db_id shiftId);
|
void shiftNameChanged(db_id shiftId);
|
||||||
|
|
||||||
//A job was added/removed/modified belonging to this shift
|
// A job was added/removed/modified belonging to this shift
|
||||||
void shiftJobsChanged(db_id shiftId, db_id jobId);
|
void shiftJobsChanged(db_id shiftId, db_id jobId);
|
||||||
|
|
||||||
//Rollingstock
|
// Rollingstock
|
||||||
void rollingstockRemoved(db_id rsId);
|
void rollingstockRemoved(db_id rsId);
|
||||||
void rollingStockPlanChanged(QSet<db_id> rsIds);
|
void rollingStockPlanChanged(QSet<db_id> rsIds);
|
||||||
void rollingStockModified(db_id rsId);
|
void rollingStockModified(db_id rsId);
|
||||||
|
|
||||||
//Jobs
|
// Jobs
|
||||||
void jobAdded(db_id jobId);
|
void jobAdded(db_id jobId);
|
||||||
void jobChanged(db_id jobId, db_id oldJobId); //Updated id/category/stops
|
void jobChanged(db_id jobId, db_id oldJobId); // Updated id/category/stops
|
||||||
void jobRemoved(db_id jobId);
|
void jobRemoved(db_id jobId);
|
||||||
|
|
||||||
//Stations
|
// Stations
|
||||||
void stationNameChanged(db_id stationId);
|
void stationNameChanged(db_id stationId);
|
||||||
void stationJobsPlanChanged(const QSet<db_id>& stationIds);
|
void stationJobsPlanChanged(const QSet<db_id> &stationIds);
|
||||||
void stationTrackPlanChanged(const QSet<db_id>& stationIds);
|
void stationTrackPlanChanged(const QSet<db_id> &stationIds);
|
||||||
void stationRemoved(db_id stationId);
|
void stationRemoved(db_id stationId);
|
||||||
|
|
||||||
//Segments
|
// Segments
|
||||||
void segmentAdded(db_id segmentId);
|
void segmentAdded(db_id segmentId);
|
||||||
void segmentNameChanged(db_id segmentId);
|
void segmentNameChanged(db_id segmentId);
|
||||||
void segmentStationsChanged(db_id segmentId);
|
void segmentStationsChanged(db_id segmentId);
|
||||||
void segmentRemoved(db_id segmentId);
|
void segmentRemoved(db_id segmentId);
|
||||||
|
|
||||||
//Lines
|
// Lines
|
||||||
void lineAdded(db_id lineId);
|
void lineAdded(db_id lineId);
|
||||||
void lineNameChanged(db_id lineId);
|
void lineNameChanged(db_id lineId);
|
||||||
void lineSegmentsChanged(db_id lineId);
|
void lineSegmentsChanged(db_id lineId);
|
||||||
|
@ -126,45 +132,48 @@ private:
|
||||||
std::unique_ptr<BackgroundManager> backgroundManager;
|
std::unique_ptr<BackgroundManager> backgroundManager;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Settings TODO: remove
|
// Settings TODO: remove
|
||||||
public:
|
public:
|
||||||
void loadSettings(const QString &settings_file);
|
void loadSettings(const QString &settings_file);
|
||||||
|
|
||||||
MRTPSettings settings;
|
MRTPSettings settings;
|
||||||
|
|
||||||
int hourOffset;
|
int hourOffset;
|
||||||
int stationOffset;
|
int stationOffset;
|
||||||
qreal platformOffset;
|
qreal platformOffset;
|
||||||
|
|
||||||
int horizOffset;
|
int horizOffset;
|
||||||
int vertOffset;
|
int vertOffset;
|
||||||
|
|
||||||
int jobLineWidth;
|
int jobLineWidth;
|
||||||
|
|
||||||
//Database
|
// Database
|
||||||
public:
|
public:
|
||||||
database m_Db;
|
database m_Db;
|
||||||
|
|
||||||
//Job Categories:
|
// Job Categories:
|
||||||
public:
|
public:
|
||||||
QColor colorForCat(JobCategory cat);
|
QColor colorForCat(JobCategory cat);
|
||||||
|
|
||||||
//Savepoints TODO: seem unused
|
// Savepoints TODO: seem unused
|
||||||
public:
|
public:
|
||||||
inline bool getDBDirty() { return !savepointList.isEmpty(); }
|
inline bool getDBDirty()
|
||||||
|
{
|
||||||
|
return !savepointList.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
bool setSavepoint(const QString& pointname = "RESTOREPOINT");
|
bool setSavepoint(const QString &pointname = "RESTOREPOINT");
|
||||||
bool releaseSavepoint(const QString& pointname = "RESTOREPOINT");
|
bool releaseSavepoint(const QString &pointname = "RESTOREPOINT");
|
||||||
bool revertToSavepoint(const QString& pointname = "RESTOREPOINT");
|
bool revertToSavepoint(const QString &pointname = "RESTOREPOINT");
|
||||||
bool releaseAllSavepoints();
|
bool releaseAllSavepoints();
|
||||||
bool revertAll();
|
bool revertAll();
|
||||||
|
|
||||||
QStringList savepointList;
|
QStringList savepointList;
|
||||||
|
|
||||||
//DB
|
// DB
|
||||||
public:
|
public:
|
||||||
DB_Error createNewDB(const QString &file);
|
DB_Error createNewDB(const QString &file);
|
||||||
DB_Error openDB(const QString& str, bool ignoreVersion);
|
DB_Error openDB(const QString &str, bool ignoreVersion);
|
||||||
DB_Error closeDB();
|
DB_Error closeDB();
|
||||||
|
|
||||||
bool checkImportRSTablesEmpty();
|
bool checkImportRSTablesEmpty();
|
||||||
|
@ -172,7 +181,7 @@ public:
|
||||||
|
|
||||||
QString fileName;
|
QString fileName;
|
||||||
|
|
||||||
//AppData
|
// AppData
|
||||||
public:
|
public:
|
||||||
static void locateAppdata();
|
static void locateAppdata();
|
||||||
static QString appDataPath;
|
static QString appDataPath;
|
||||||
|
@ -228,14 +237,25 @@ public:
|
||||||
*/
|
*/
|
||||||
static const QLocale embeddedLocale;
|
static const QLocale embeddedLocale;
|
||||||
|
|
||||||
void setSheetExportTranslator(QTranslator *translator, const QLocale& loc);
|
void setSheetExportTranslator(QTranslator *translator, const QLocale &loc);
|
||||||
|
|
||||||
inline QTranslator *getSheetExportTranslator() const { return sheetExportTranslator; }
|
inline QTranslator *getSheetExportTranslator() const
|
||||||
inline QLocale getSheetExportLocale() const { return sheetExportLocale; }
|
{
|
||||||
inline QLocale getAppLanguage() const { return originalAppLocale; }
|
return sheetExportTranslator;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QLocale getSheetExportLocale() const
|
||||||
|
{
|
||||||
|
return sheetExportLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QLocale getAppLanguage() const
|
||||||
|
{
|
||||||
|
return originalAppLocale;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define Session MeetingSession::Get()
|
#define Session MeetingSession::Get()
|
||||||
|
|
||||||
#define AppSettings Session->settings
|
#define AppSettings Session->settings
|
||||||
|
|
||||||
|
|
|
@ -20,25 +20,23 @@
|
||||||
#include "backgroundmanager.h"
|
#include "backgroundmanager.h"
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
#include "backgroundmanager/ibackgroundchecker.h"
|
# include "backgroundmanager/ibackgroundchecker.h"
|
||||||
|
|
||||||
#include <QThreadPool>
|
# include <QThreadPool>
|
||||||
#include <QSet>
|
# include <QSet>
|
||||||
|
|
||||||
BackgroundManager::BackgroundManager(QObject *parent) :
|
BackgroundManager::BackgroundManager(QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BackgroundManager::~BackgroundManager()
|
BackgroundManager::~BackgroundManager()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundManager::handleSessionLoaded()
|
void BackgroundManager::handleSessionLoaded()
|
||||||
{
|
{
|
||||||
for(IBackgroundChecker *mgr : qAsConst(checkers))
|
for (IBackgroundChecker *mgr : qAsConst(checkers))
|
||||||
mgr->startWorker();
|
mgr->startWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,19 +44,19 @@ void BackgroundManager::abortAllTasks()
|
||||||
{
|
{
|
||||||
emit abortTrivialTasks();
|
emit abortTrivialTasks();
|
||||||
|
|
||||||
for(IBackgroundChecker *mgr : qAsConst(checkers))
|
for (IBackgroundChecker *mgr : qAsConst(checkers))
|
||||||
mgr->abortTasks();
|
mgr->abortTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BackgroundManager::isRunning()
|
bool BackgroundManager::isRunning()
|
||||||
{
|
{
|
||||||
bool running = QThreadPool::globalInstance()->activeThreadCount() > 0;
|
bool running = QThreadPool::globalInstance()->activeThreadCount() > 0;
|
||||||
if(running)
|
if (running)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for(IBackgroundChecker *mgr : qAsConst(checkers))
|
for (IBackgroundChecker *mgr : qAsConst(checkers))
|
||||||
{
|
{
|
||||||
if(mgr->isRunning())
|
if (mgr->isRunning())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,10 +67,8 @@ void BackgroundManager::addChecker(IBackgroundChecker *mgr)
|
||||||
{
|
{
|
||||||
checkers.append(mgr);
|
checkers.append(mgr);
|
||||||
|
|
||||||
connect(mgr, &IBackgroundChecker::destroyed, this, [this](QObject *self)
|
connect(mgr, &IBackgroundChecker::destroyed, this,
|
||||||
{
|
[this](QObject *self) { removeChecker(static_cast<IBackgroundChecker *>(self)); });
|
||||||
removeChecker(static_cast<IBackgroundChecker *>(self));
|
|
||||||
});
|
|
||||||
|
|
||||||
emit checkerAdded(mgr);
|
emit checkerAdded(mgr);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +82,7 @@ void BackgroundManager::removeChecker(IBackgroundChecker *mgr)
|
||||||
|
|
||||||
void BackgroundManager::clearResults()
|
void BackgroundManager::clearResults()
|
||||||
{
|
{
|
||||||
for(IBackgroundChecker *mgr : qAsConst(checkers))
|
for (IBackgroundChecker *mgr : qAsConst(checkers))
|
||||||
{
|
{
|
||||||
mgr->clearModel();
|
mgr->clearModel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include <QObject>
|
# include <QObject>
|
||||||
#include <QVector>
|
# include <QVector>
|
||||||
|
|
||||||
class IBackgroundChecker;
|
class IBackgroundChecker;
|
||||||
|
|
||||||
//TODO: show a progress bar for all task like Qt Creator does
|
// TODO: show a progress bar for all task like Qt Creator does
|
||||||
class BackgroundManager : public QObject
|
class BackgroundManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include "backgroundresultpanel.h"
|
# include "backgroundresultpanel.h"
|
||||||
|
|
||||||
#include "backgroundmanager/ibackgroundchecker.h"
|
# include "backgroundmanager/ibackgroundchecker.h"
|
||||||
#include "backgroundresultwidget.h"
|
# include "backgroundresultwidget.h"
|
||||||
|
|
||||||
#include "app/session.h"
|
# include "app/session.h"
|
||||||
#include "backgroundmanager.h"
|
# include "backgroundmanager.h"
|
||||||
|
|
||||||
BackgroundResultPanel::BackgroundResultPanel(QWidget *parent) :
|
BackgroundResultPanel::BackgroundResultPanel(QWidget *parent) :
|
||||||
QTabWidget(parent)
|
QTabWidget(parent)
|
||||||
|
@ -34,7 +34,7 @@ BackgroundResultPanel::BackgroundResultPanel(QWidget *parent) :
|
||||||
connect(bkMgr, &BackgroundManager::checkerAdded, this, &BackgroundResultPanel::addChecker);
|
connect(bkMgr, &BackgroundManager::checkerAdded, this, &BackgroundResultPanel::addChecker);
|
||||||
connect(bkMgr, &BackgroundManager::checkerRemoved, this, &BackgroundResultPanel::removeChecker);
|
connect(bkMgr, &BackgroundManager::checkerRemoved, this, &BackgroundResultPanel::removeChecker);
|
||||||
|
|
||||||
for(auto mgr : bkMgr->checkers)
|
for (auto mgr : bkMgr->checkers)
|
||||||
addChecker(mgr);
|
addChecker(mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,10 +46,10 @@ void BackgroundResultPanel::addChecker(IBackgroundChecker *mgr)
|
||||||
|
|
||||||
void BackgroundResultPanel::removeChecker(IBackgroundChecker *mgr)
|
void BackgroundResultPanel::removeChecker(IBackgroundChecker *mgr)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < count(); i++)
|
for (int i = 0; i < count(); i++)
|
||||||
{
|
{
|
||||||
BackgroundResultWidget *w = static_cast<BackgroundResultWidget *>(widget(i));
|
BackgroundResultWidget *w = static_cast<BackgroundResultWidget *>(widget(i));
|
||||||
if(w->mgr == mgr)
|
if (w->mgr == mgr)
|
||||||
{
|
{
|
||||||
removeTab(i);
|
removeTab(i);
|
||||||
delete w;
|
delete w;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include <QTabWidget>
|
# include <QTabWidget>
|
||||||
|
|
||||||
class IBackgroundChecker;
|
class IBackgroundChecker;
|
||||||
|
|
||||||
|
|
|
@ -19,21 +19,20 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include "ibackgroundchecker.h"
|
# include "ibackgroundchecker.h"
|
||||||
#include "backgroundresultwidget.h"
|
# include "backgroundresultwidget.h"
|
||||||
|
|
||||||
#include <QTreeView>
|
# include <QTreeView>
|
||||||
#include <QHeaderView>
|
# include <QHeaderView>
|
||||||
#include <QProgressBar>
|
# include <QProgressBar>
|
||||||
#include <QPushButton>
|
# include <QPushButton>
|
||||||
|
|
||||||
#include <QGridLayout>
|
# include <QGridLayout>
|
||||||
|
|
||||||
#include <QMenu>
|
# include <QMenu>
|
||||||
#include <QAction>
|
# include <QAction>
|
||||||
|
|
||||||
#include <QTimerEvent>
|
|
||||||
|
|
||||||
|
# include <QTimerEvent>
|
||||||
|
|
||||||
BackgroundResultWidget::BackgroundResultWidget(IBackgroundChecker *mgr_, QWidget *parent) :
|
BackgroundResultWidget::BackgroundResultWidget(IBackgroundChecker *mgr_, QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
|
@ -45,8 +44,8 @@ BackgroundResultWidget::BackgroundResultWidget(IBackgroundChecker *mgr_, QWidget
|
||||||
view->setSelectionBehavior(QTreeView::SelectRows);
|
view->setSelectionBehavior(QTreeView::SelectRows);
|
||||||
|
|
||||||
progressBar = new QProgressBar;
|
progressBar = new QProgressBar;
|
||||||
startBut = new QPushButton(tr("Start"));
|
startBut = new QPushButton(tr("Start"));
|
||||||
stopBut = new QPushButton(tr("Stop"));
|
stopBut = new QPushButton(tr("Stop"));
|
||||||
|
|
||||||
startBut->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
startBut->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
stopBut->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
stopBut->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
|
@ -68,7 +67,8 @@ BackgroundResultWidget::BackgroundResultWidget(IBackgroundChecker *mgr_, QWidget
|
||||||
connect(stopBut, &QPushButton::clicked, this, &BackgroundResultWidget::stopTask);
|
connect(stopBut, &QPushButton::clicked, this, &BackgroundResultWidget::stopTask);
|
||||||
|
|
||||||
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(view, &QTreeView::customContextMenuRequested, this, &BackgroundResultWidget::showContextMenu);
|
connect(view, &QTreeView::customContextMenuRequested, this,
|
||||||
|
&BackgroundResultWidget::showContextMenu);
|
||||||
|
|
||||||
setWindowTitle(tr("Error Results"));
|
setWindowTitle(tr("Error Results"));
|
||||||
|
|
||||||
|
@ -79,11 +79,11 @@ void BackgroundResultWidget::startTask()
|
||||||
{
|
{
|
||||||
progressBar->setValue(0);
|
progressBar->setValue(0);
|
||||||
|
|
||||||
if(mgr->startWorker())
|
if (mgr->startWorker())
|
||||||
{
|
{
|
||||||
if(timerId)
|
if (timerId)
|
||||||
{
|
{
|
||||||
killTimer(timerId); //Stop progressBar from hiding in 1 second
|
killTimer(timerId); // Stop progressBar from hiding in 1 second
|
||||||
timerId = 0;
|
timerId = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,14 +105,14 @@ void BackgroundResultWidget::taskFinished()
|
||||||
{
|
{
|
||||||
progressBar->setValue(progressBar->maximum());
|
progressBar->setValue(progressBar->maximum());
|
||||||
|
|
||||||
if(timerId)
|
if (timerId)
|
||||||
killTimer(timerId);
|
killTimer(timerId);
|
||||||
timerId = startTimer(1000); //Hide progressBar after 1 second
|
timerId = startTimer(1000); // Hide progressBar after 1 second
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundResultWidget::timerEvent(QTimerEvent *e)
|
void BackgroundResultWidget::timerEvent(QTimerEvent *e)
|
||||||
{
|
{
|
||||||
if(e->timerId() == timerId)
|
if (e->timerId() == timerId)
|
||||||
{
|
{
|
||||||
killTimer(timerId);
|
killTimer(timerId);
|
||||||
timerId = 0;
|
timerId = 0;
|
||||||
|
@ -120,10 +120,10 @@ void BackgroundResultWidget::timerEvent(QTimerEvent *e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundResultWidget::showContextMenu(const QPoint& pos)
|
void BackgroundResultWidget::showContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
QModelIndex idx = view->indexAt(pos);
|
QModelIndex idx = view->indexAt(pos);
|
||||||
if(!idx.isValid())
|
if (!idx.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mgr->showContextMenu(this, view->viewport()->mapToGlobal(pos), idx);
|
mgr->showContextMenu(this, view->viewport()->mapToGlobal(pos), idx);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include <QWidget>
|
# include <QWidget>
|
||||||
|
|
||||||
class QTreeView;
|
class QTreeView;
|
||||||
class QProgressBar;
|
class QProgressBar;
|
||||||
|
|
|
@ -19,25 +19,23 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include "ibackgroundchecker.h"
|
# include "ibackgroundchecker.h"
|
||||||
|
|
||||||
#include <QThreadPool>
|
# include <QThreadPool>
|
||||||
#include "utils/thread/iquittabletask.h"
|
# include "utils/thread/iquittabletask.h"
|
||||||
#include "utils/thread/taskprogressevent.h"
|
# include "utils/thread/taskprogressevent.h"
|
||||||
|
|
||||||
#include "sqlite3pp/sqlite3pp.h"
|
|
||||||
|
|
||||||
|
# include "sqlite3pp/sqlite3pp.h"
|
||||||
|
|
||||||
IBackgroundChecker::IBackgroundChecker(sqlite3pp::database &db, QObject *parent) :
|
IBackgroundChecker::IBackgroundChecker(sqlite3pp::database &db, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
mDb(db)
|
mDb(db)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IBackgroundChecker::event(QEvent *e)
|
bool IBackgroundChecker::event(QEvent *e)
|
||||||
{
|
{
|
||||||
if(e->type() == TaskProgressEvent::_Type)
|
if (e->type() == TaskProgressEvent::_Type)
|
||||||
{
|
{
|
||||||
e->setAccepted(true);
|
e->setAccepted(true);
|
||||||
|
|
||||||
|
@ -46,14 +44,14 @@ bool IBackgroundChecker::event(QEvent *e)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(e->type() == eventType)
|
else if (e->type() == eventType)
|
||||||
{
|
{
|
||||||
e->setAccepted(true);
|
e->setAccepted(true);
|
||||||
|
|
||||||
GenericTaskEvent *ev = static_cast<GenericTaskEvent *>(e);
|
GenericTaskEvent *ev = static_cast<GenericTaskEvent *>(e);
|
||||||
if(m_mainWorker && ev->task == m_mainWorker)
|
if (m_mainWorker && ev->task == m_mainWorker)
|
||||||
{
|
{
|
||||||
if(!m_mainWorker->wasStopped())
|
if (!m_mainWorker->wasStopped())
|
||||||
{
|
{
|
||||||
setErrors(ev, false);
|
setErrors(ev, false);
|
||||||
}
|
}
|
||||||
|
@ -66,10 +64,10 @@ bool IBackgroundChecker::event(QEvent *e)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int idx = m_workers.indexOf(ev->task);
|
int idx = m_workers.indexOf(ev->task);
|
||||||
if(idx != -1)
|
if (idx != -1)
|
||||||
{
|
{
|
||||||
m_workers.removeAt(idx);
|
m_workers.removeAt(idx);
|
||||||
if(!ev->task->wasStopped())
|
if (!ev->task->wasStopped())
|
||||||
setErrors(ev, true);
|
setErrors(ev, true);
|
||||||
|
|
||||||
delete ev->task;
|
delete ev->task;
|
||||||
|
@ -84,19 +82,19 @@ bool IBackgroundChecker::event(QEvent *e)
|
||||||
|
|
||||||
bool IBackgroundChecker::startWorker()
|
bool IBackgroundChecker::startWorker()
|
||||||
{
|
{
|
||||||
if(m_mainWorker)
|
if (m_mainWorker)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!mDb.db())
|
if (!mDb.db())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_mainWorker = createMainWorker();
|
m_mainWorker = createMainWorker();
|
||||||
|
|
||||||
QThreadPool::globalInstance()->start(m_mainWorker);
|
QThreadPool::globalInstance()->start(m_mainWorker);
|
||||||
|
|
||||||
for(auto task = m_workers.begin(); task != m_workers.end(); task++)
|
for (auto task = m_workers.begin(); task != m_workers.end(); task++)
|
||||||
{
|
{
|
||||||
if(QThreadPool::globalInstance()->tryTake(*task))
|
if (QThreadPool::globalInstance()->tryTake(*task))
|
||||||
{
|
{
|
||||||
IQuittableTask *ptr = *task;
|
IQuittableTask *ptr = *task;
|
||||||
m_workers.erase(task);
|
m_workers.erase(task);
|
||||||
|
@ -113,12 +111,12 @@ bool IBackgroundChecker::startWorker()
|
||||||
|
|
||||||
void IBackgroundChecker::abortTasks()
|
void IBackgroundChecker::abortTasks()
|
||||||
{
|
{
|
||||||
if(m_mainWorker)
|
if (m_mainWorker)
|
||||||
{
|
{
|
||||||
m_mainWorker->stop();
|
m_mainWorker->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
for(IQuittableTask *task : qAsConst(m_workers))
|
for (IQuittableTask *task : qAsConst(m_workers))
|
||||||
{
|
{
|
||||||
task->stop();
|
task->stop();
|
||||||
}
|
}
|
||||||
|
@ -126,7 +124,7 @@ void IBackgroundChecker::abortTasks()
|
||||||
|
|
||||||
void IBackgroundChecker::sessionLoadedHandler()
|
void IBackgroundChecker::sessionLoadedHandler()
|
||||||
{
|
{
|
||||||
//no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
void IBackgroundChecker::addSubTask(IQuittableTask *task)
|
void IBackgroundChecker::addSubTask(IQuittableTask *task)
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include <QObject>
|
# include <QObject>
|
||||||
#include <QVector>
|
# include <QVector>
|
||||||
|
|
||||||
class QAbstractItemModel;
|
class QAbstractItemModel;
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
|
@ -47,13 +47,20 @@ public:
|
||||||
bool startWorker();
|
bool startWorker();
|
||||||
void abortTasks();
|
void abortTasks();
|
||||||
|
|
||||||
inline bool isRunning() const { return m_mainWorker || m_workers.size() > 0; }
|
inline bool isRunning() const
|
||||||
|
{
|
||||||
|
return m_mainWorker || m_workers.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
inline QAbstractItemModel *getModel() const { return errorsModel; };
|
inline QAbstractItemModel *getModel() const
|
||||||
|
{
|
||||||
|
return errorsModel;
|
||||||
|
};
|
||||||
|
|
||||||
virtual QString getName() const = 0;
|
virtual QString getName() const = 0;
|
||||||
virtual void clearModel() = 0;
|
virtual void clearModel() = 0;
|
||||||
virtual void showContextMenu(QWidget *panel, const QPoint& globalPos, const QModelIndex& idx) const = 0;
|
virtual void showContextMenu(QWidget *panel, const QPoint &globalPos,
|
||||||
|
const QModelIndex &idx) const = 0;
|
||||||
|
|
||||||
virtual void sessionLoadedHandler();
|
virtual void sessionLoadedHandler();
|
||||||
|
|
||||||
|
@ -64,13 +71,13 @@ signals:
|
||||||
protected:
|
protected:
|
||||||
void addSubTask(IQuittableTask *task);
|
void addSubTask(IQuittableTask *task);
|
||||||
|
|
||||||
virtual IQuittableTask *createMainWorker() = 0;
|
virtual IQuittableTask *createMainWorker() = 0;
|
||||||
virtual void setErrors(QEvent *e, bool merge) = 0;
|
virtual void setErrors(QEvent *e, bool merge) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
sqlite3pp::database &mDb;
|
sqlite3pp::database &mDb;
|
||||||
QAbstractItemModel *errorsModel = nullptr;
|
QAbstractItemModel *errorsModel = nullptr;
|
||||||
int eventType = 0;
|
int eventType = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IQuittableTask *m_mainWorker = nullptr;
|
IQuittableTask *m_mainWorker = nullptr;
|
||||||
|
|
|
@ -23,8 +23,7 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
namespace ImageMetaData
|
namespace ImageMetaData {
|
||||||
{
|
|
||||||
|
|
||||||
constexpr char sql_get_key_id[] = "SELECT rowid FROM metadata WHERE name=? AND val NOT NULL";
|
constexpr char sql_get_key_id[] = "SELECT rowid FROM metadata WHERE name=? AND val NOT NULL";
|
||||||
|
|
||||||
|
@ -35,7 +34,6 @@ ImageBlobDevice::ImageBlobDevice(sqlite3 *db, QObject *parent) :
|
||||||
mDb(db),
|
mDb(db),
|
||||||
mBlob(nullptr)
|
mBlob(nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageBlobDevice::~ImageBlobDevice()
|
ImageBlobDevice::~ImageBlobDevice()
|
||||||
|
@ -45,40 +43,40 @@ ImageBlobDevice::~ImageBlobDevice()
|
||||||
|
|
||||||
void ImageBlobDevice::setBlobInfo(const QByteArray &table, const QByteArray &column, qint64 rowId)
|
void ImageBlobDevice::setBlobInfo(const QByteArray &table, const QByteArray &column, qint64 rowId)
|
||||||
{
|
{
|
||||||
mRowId = rowId;
|
mRowId = rowId;
|
||||||
mTable = table;
|
mTable = table;
|
||||||
mColumn = column;
|
mColumn = column;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageBlobDevice::reserveSizeAndReset(qint64 len)
|
bool ImageBlobDevice::reserveSizeAndReset(qint64 len)
|
||||||
{
|
{
|
||||||
//NOTE: this will discard any previous content
|
// NOTE: this will discard any previous content
|
||||||
|
|
||||||
//Close previous BLOB handle
|
// Close previous BLOB handle
|
||||||
if(mBlob)
|
if (mBlob)
|
||||||
close();
|
close();
|
||||||
|
|
||||||
//Create SQL statement
|
// Create SQL statement
|
||||||
QByteArray sql = "UPDATE " + mTable + " SET " + mColumn + "=? WHERE rowId=?";
|
QByteArray sql = "UPDATE " + mTable + " SET " + mColumn + "=? WHERE rowId=?";
|
||||||
|
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
int rc = sqlite3_prepare_v2(mDb, sql.constData(), sql.size(), &stmt, nullptr);
|
int rc = sqlite3_prepare_v2(mDb, sql.constData(), sql.size(), &stmt, nullptr);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "ImageBlobDevice::reserveSizeAndReset cannot prepare:" << sqlite3_errmsg(mDb);
|
qWarning() << "ImageBlobDevice::reserveSizeAndReset cannot prepare:" << sqlite3_errmsg(mDb);
|
||||||
setErrorString(tr("Cannot query database"));
|
setErrorString(tr("Cannot query database"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reserve BLOB memory
|
// Reserve BLOB memory
|
||||||
rc = sqlite3_bind_zeroblob64(stmt, 1, len);
|
rc = sqlite3_bind_zeroblob64(stmt, 1, len);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
rc = sqlite3_bind_int64(stmt, 2, mRowId);
|
rc = sqlite3_bind_int64(stmt, 2, mRowId);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return false;
|
return false;
|
||||||
|
@ -88,30 +86,30 @@ bool ImageBlobDevice::reserveSizeAndReset(qint64 len)
|
||||||
|
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
if(rc != SQLITE_OK && rc != SQLITE_DONE)
|
if (rc != SQLITE_OK && rc != SQLITE_DONE)
|
||||||
{
|
{
|
||||||
qWarning() << "ImageBlobDevice::reserveSizeAndReset cannot step:" << sqlite3_errmsg(mDb);
|
qWarning() << "ImageBlobDevice::reserveSizeAndReset cannot step:" << sqlite3_errmsg(mDb);
|
||||||
setErrorString(tr("Cannot create BLOB"));
|
setErrorString(tr("Cannot create BLOB"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Open new BLOB handle
|
// Open new BLOB handle
|
||||||
return open(QIODevice::ReadWrite);
|
return open(QIODevice::ReadWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageBlobDevice::open(QIODevice::OpenMode mode)
|
bool ImageBlobDevice::open(QIODevice::OpenMode mode)
|
||||||
{
|
{
|
||||||
if(isOpen())
|
if (isOpen())
|
||||||
{
|
{
|
||||||
qWarning().nospace() << "ImageBlobDevice::open Device already open "
|
qWarning().nospace() << "ImageBlobDevice::open Device already open " << '(' << mTable << '.'
|
||||||
<< '(' << mTable << '.' << mColumn << ')';
|
<< mColumn << ')';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mode |= QIODevice::ReadOnly; //Always enable reading
|
mode |= QIODevice::ReadOnly; // Always enable reading
|
||||||
int rc = sqlite3_blob_open(mDb, "main", mTable.constData(), mColumn.constData(),
|
int rc = sqlite3_blob_open(mDb, "main", mTable.constData(), mColumn.constData(), mRowId,
|
||||||
mRowId, (mode & QIODevice::WriteOnly) != 0, &mBlob);
|
(mode & QIODevice::WriteOnly) != 0, &mBlob);
|
||||||
if(rc != SQLITE_OK || !mBlob)
|
if (rc != SQLITE_OK || !mBlob)
|
||||||
{
|
{
|
||||||
mBlob = nullptr;
|
mBlob = nullptr;
|
||||||
setErrorString(sqlite3_errmsg(mDb));
|
setErrorString(sqlite3_errmsg(mDb));
|
||||||
|
@ -127,7 +125,7 @@ bool ImageBlobDevice::open(QIODevice::OpenMode mode)
|
||||||
|
|
||||||
void ImageBlobDevice::close()
|
void ImageBlobDevice::close()
|
||||||
{
|
{
|
||||||
if(mBlob)
|
if (mBlob)
|
||||||
{
|
{
|
||||||
sqlite3_blob_close(mBlob);
|
sqlite3_blob_close(mBlob);
|
||||||
mBlob = nullptr;
|
mBlob = nullptr;
|
||||||
|
@ -144,21 +142,21 @@ qint64 ImageBlobDevice::size() const
|
||||||
|
|
||||||
qint64 ImageBlobDevice::writeData(const char *data, qint64 len)
|
qint64 ImageBlobDevice::writeData(const char *data, qint64 len)
|
||||||
{
|
{
|
||||||
if(!mBlob)
|
if (!mBlob)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int offset = int(pos());
|
int offset = int(pos());
|
||||||
if(len + offset >= mSize)
|
if (len + offset >= mSize)
|
||||||
len = mSize - offset;
|
len = mSize - offset;
|
||||||
|
|
||||||
if(!len)
|
if (!len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int rc = sqlite3_blob_write(mBlob, data, int(len), offset);
|
int rc = sqlite3_blob_write(mBlob, data, int(len), offset);
|
||||||
if(rc == SQLITE_OK)
|
if (rc == SQLITE_OK)
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
if(rc == SQLITE_READONLY)
|
if (rc == SQLITE_READONLY)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
setErrorString(sqlite3_errmsg(mDb));
|
setErrorString(sqlite3_errmsg(mDb));
|
||||||
|
@ -167,45 +165,46 @@ qint64 ImageBlobDevice::writeData(const char *data, qint64 len)
|
||||||
|
|
||||||
qint64 ImageBlobDevice::readData(char *data, qint64 maxlen)
|
qint64 ImageBlobDevice::readData(char *data, qint64 maxlen)
|
||||||
{
|
{
|
||||||
if(!mBlob)
|
if (!mBlob)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int offset = int(pos());
|
int offset = int(pos());
|
||||||
if(maxlen + offset >= mSize)
|
if (maxlen + offset >= mSize)
|
||||||
maxlen = mSize - offset;
|
maxlen = mSize - offset;
|
||||||
|
|
||||||
if(!maxlen)
|
if (!maxlen)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int rc = sqlite3_blob_read(mBlob, data, int(maxlen), offset);
|
int rc = sqlite3_blob_read(mBlob, data, int(maxlen), offset);
|
||||||
if(rc == SQLITE_OK)
|
if (rc == SQLITE_OK)
|
||||||
return maxlen;
|
return maxlen;
|
||||||
|
|
||||||
setErrorString(sqlite3_errmsg(mDb));
|
setErrorString(sqlite3_errmsg(mDb));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageBlobDevice* getImage(sqlite3pp::database& db, const MetaDataManager::Key &key)
|
ImageBlobDevice *getImage(sqlite3pp::database &db, const MetaDataManager::Key &key)
|
||||||
{
|
{
|
||||||
if(!db.db())
|
if (!db.db())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
int rc = sqlite3_prepare_v2(db.db(), sql_get_key_id, sizeof (sql_get_key_id) - 1, &stmt, nullptr);
|
int rc =
|
||||||
if(rc != SQLITE_OK)
|
sqlite3_prepare_v2(db.db(), sql_get_key_id, sizeof(sql_get_key_id) - 1, &stmt, nullptr);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
qint64 rowId = 0;
|
qint64 rowId = 0;
|
||||||
if(rc != SQLITE_ROW)
|
if (rc != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -214,7 +213,7 @@ ImageBlobDevice* getImage(sqlite3pp::database& db, const MetaDataManager::Key &k
|
||||||
rowId = sqlite3_column_int64(stmt, 0);
|
rowId = sqlite3_column_int64(stmt, 0);
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
if(!rowId)
|
if (!rowId)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ImageBlobDevice *dev = new ImageBlobDevice(db.db());
|
ImageBlobDevice *dev = new ImageBlobDevice(db.db());
|
||||||
|
@ -222,11 +221,11 @@ ImageBlobDevice* getImage(sqlite3pp::database& db, const MetaDataManager::Key &k
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setImage(sqlite3pp::database& db, const MetaDataManager::Key &key, const void *data, int size)
|
void setImage(sqlite3pp::database &db, const MetaDataManager::Key &key, const void *data, int size)
|
||||||
{
|
{
|
||||||
sqlite3pp::command cmd(db, "REPLACE INTO metadata(name, val) VALUES(?, ?)");
|
sqlite3pp::command cmd(db, "REPLACE INTO metadata(name, val) VALUES(?, ?)");
|
||||||
sqlite3_bind_text(cmd.stmt(), 1, key.str, key.len, SQLITE_STATIC);
|
sqlite3_bind_text(cmd.stmt(), 1, key.str, key.len, SQLITE_STATIC);
|
||||||
if(data)
|
if (data)
|
||||||
sqlite3_bind_blob(cmd.stmt(), 2, data, size, SQLITE_STATIC);
|
sqlite3_bind_blob(cmd.stmt(), 2, data, size, SQLITE_STATIC);
|
||||||
else
|
else
|
||||||
sqlite3_bind_null(cmd.stmt(), 2);
|
sqlite3_bind_null(cmd.stmt(), 2);
|
||||||
|
|
|
@ -27,10 +27,9 @@
|
||||||
typedef struct sqlite3 sqlite3;
|
typedef struct sqlite3 sqlite3;
|
||||||
typedef struct sqlite3_blob sqlite3_blob;
|
typedef struct sqlite3_blob sqlite3_blob;
|
||||||
|
|
||||||
namespace ImageMetaData
|
namespace ImageMetaData {
|
||||||
{
|
|
||||||
|
|
||||||
//TODO: move to utils
|
// TODO: move to utils
|
||||||
class ImageBlobDevice : public QIODevice
|
class ImageBlobDevice : public QIODevice
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -38,7 +37,7 @@ public:
|
||||||
ImageBlobDevice(sqlite3 *db, QObject *parent = nullptr);
|
ImageBlobDevice(sqlite3 *db, QObject *parent = nullptr);
|
||||||
~ImageBlobDevice() override;
|
~ImageBlobDevice() override;
|
||||||
|
|
||||||
void setBlobInfo(const QByteArray& table, const QByteArray& column, qint64 rowId);
|
void setBlobInfo(const QByteArray &table, const QByteArray &column, qint64 rowId);
|
||||||
|
|
||||||
bool reserveSizeAndReset(qint64 len);
|
bool reserveSizeAndReset(qint64 len);
|
||||||
|
|
||||||
|
@ -61,8 +60,8 @@ private:
|
||||||
QByteArray mColumn;
|
QByteArray mColumn;
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageBlobDevice *getImage(sqlite3pp::database& db, const MetaDataManager::Key& key);
|
ImageBlobDevice *getImage(sqlite3pp::database &db, const MetaDataManager::Key &key);
|
||||||
void setImage(sqlite3pp::database& db, const MetaDataManager::Key &key, const void *data, int size);
|
void setImage(sqlite3pp::database &db, const MetaDataManager::Key &key, const void *data, int size);
|
||||||
|
|
||||||
} // namespace ImageMetaData
|
} // namespace ImageMetaData
|
||||||
|
|
||||||
|
|
|
@ -47,28 +47,34 @@ MeetingInformationDialog::MeetingInformationDialog(QWidget *parent) :
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
connect(ui->viewPictureBut, &QPushButton::clicked, this, &MeetingInformationDialog::showImage);
|
connect(ui->viewPictureBut, &QPushButton::clicked, this, &MeetingInformationDialog::showImage);
|
||||||
connect(ui->importPictureBut, &QPushButton::clicked, this, &MeetingInformationDialog::importImage);
|
connect(ui->importPictureBut, &QPushButton::clicked, this,
|
||||||
connect(ui->removePictureBut, &QPushButton::clicked, this, &MeetingInformationDialog::removeImage);
|
&MeetingInformationDialog::importImage);
|
||||||
connect(ui->resetHeaderBut, &QPushButton::clicked, this, &MeetingInformationDialog::toggleHeader);
|
connect(ui->removePictureBut, &QPushButton::clicked, this,
|
||||||
connect(ui->resetFooterBut, &QPushButton::clicked, this, &MeetingInformationDialog::toggleFooter);
|
&MeetingInformationDialog::removeImage);
|
||||||
connect(ui->startDate, &QDateEdit::dateChanged, this, &MeetingInformationDialog::updateMinumumDate);
|
connect(ui->resetHeaderBut, &QPushButton::clicked, this,
|
||||||
|
&MeetingInformationDialog::toggleHeader);
|
||||||
|
connect(ui->resetFooterBut, &QPushButton::clicked, this,
|
||||||
|
&MeetingInformationDialog::toggleFooter);
|
||||||
|
connect(ui->startDate, &QDateEdit::dateChanged, this,
|
||||||
|
&MeetingInformationDialog::updateMinumumDate);
|
||||||
|
|
||||||
QSizePolicy sp = ui->headerEdit->sizePolicy();
|
QSizePolicy sp = ui->headerEdit->sizePolicy();
|
||||||
sp.setRetainSizeWhenHidden(true);
|
sp.setRetainSizeWhenHidden(true);
|
||||||
ui->headerEdit->setSizePolicy(sp);
|
ui->headerEdit->setSizePolicy(sp);
|
||||||
ui->footerEdit->setSizePolicy(sp);
|
ui->footerEdit->setSizePolicy(sp);
|
||||||
|
|
||||||
//Use similar font to the actual font used in sheet export
|
// Use similar font to the actual font used in sheet export
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setBold(true);
|
font.setBold(true);
|
||||||
font.setPointSize(18);
|
font.setPointSize(18);
|
||||||
ui->descrEdit->document()->setDefaultFont(font);
|
ui->descrEdit->document()->setDefaultFont(font);
|
||||||
|
|
||||||
if(!loadData())
|
if (!loadData())
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Database Error"),
|
QMessageBox::warning(this, tr("Database Error"),
|
||||||
tr("This database doesn't support metadata.\n"
|
tr("This database doesn't support metadata.\n"
|
||||||
"Make sure it was created by a recent version of the application and was not manipulated."));
|
"Make sure it was created by a recent version of the application "
|
||||||
|
"and was not manipulated."));
|
||||||
setDisabled(true);
|
setDisabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +88,7 @@ bool MeetingInformationDialog::loadData()
|
||||||
{
|
{
|
||||||
MetaDataManager *meta = Session->getMetaDataManager();
|
MetaDataManager *meta = Session->getMetaDataManager();
|
||||||
|
|
||||||
qint64 tmp = 0;
|
qint64 tmp = 0;
|
||||||
QDate date;
|
QDate date;
|
||||||
|
|
||||||
switch (meta->getInt64(tmp, MetaDataKey::MeetingStartDate))
|
switch (meta->getInt64(tmp, MetaDataKey::MeetingStartDate))
|
||||||
|
@ -93,7 +99,7 @@ bool MeetingInformationDialog::loadData()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaDataKey::Result::NoMetaDataTable:
|
case MetaDataKey::Result::NoMetaDataTable:
|
||||||
return false; //Database has no well-formed metadata
|
return false; // Database has no well-formed metadata
|
||||||
default:
|
default:
|
||||||
date = QDate::currentDate();
|
date = QDate::currentDate();
|
||||||
}
|
}
|
||||||
|
@ -126,7 +132,7 @@ bool MeetingInformationDialog::loadData()
|
||||||
text.clear();
|
text.clear();
|
||||||
meta->getString(text, MetaDataKey::MeetingDescription);
|
meta->getString(text, MetaDataKey::MeetingDescription);
|
||||||
ui->descrEdit->setPlainText(text);
|
ui->descrEdit->setPlainText(text);
|
||||||
//Align all text to center
|
// Align all text to center
|
||||||
QTextCursor c = ui->descrEdit->textCursor();
|
QTextCursor c = ui->descrEdit->textCursor();
|
||||||
c.select(QTextCursor::Document);
|
c.select(QTextCursor::Document);
|
||||||
QTextBlockFormat fmt;
|
QTextBlockFormat fmt;
|
||||||
|
@ -145,11 +151,12 @@ bool MeetingInformationDialog::loadData()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeetingInformationDialog::setSheetText(QLineEdit *lineEdit, QPushButton *but, const QString& text, bool isNull)
|
void MeetingInformationDialog::setSheetText(QLineEdit *lineEdit, QPushButton *but,
|
||||||
|
const QString &text, bool isNull)
|
||||||
{
|
{
|
||||||
lineEdit->setVisible(!isNull);
|
lineEdit->setVisible(!isNull);
|
||||||
|
|
||||||
if(isNull)
|
if (isNull)
|
||||||
{
|
{
|
||||||
but->setText(tr("Set custom text"));
|
but->setText(tr("Set custom text"));
|
||||||
lineEdit->setText(QString());
|
lineEdit->setText(QString());
|
||||||
|
@ -170,15 +177,18 @@ void MeetingInformationDialog::saveData()
|
||||||
meta->setInt64(ui->showDatesBox->isChecked() ? 1 : 0, false, MetaDataKey::MeetingShowDates);
|
meta->setInt64(ui->showDatesBox->isChecked() ? 1 : 0, false, MetaDataKey::MeetingShowDates);
|
||||||
|
|
||||||
meta->setString(ui->locationEdit->text().simplified(), false, MetaDataKey::MeetingLocation);
|
meta->setString(ui->locationEdit->text().simplified(), false, MetaDataKey::MeetingLocation);
|
||||||
meta->setString(ui->associationEdit->text().simplified(), false, MetaDataKey::MeetingHostAssociation);
|
meta->setString(ui->associationEdit->text().simplified(), false,
|
||||||
|
MetaDataKey::MeetingHostAssociation);
|
||||||
meta->setString(ui->descrEdit->toPlainText(), false, MetaDataKey::MeetingDescription);
|
meta->setString(ui->descrEdit->toPlainText(), false, MetaDataKey::MeetingDescription);
|
||||||
|
|
||||||
meta->setString(ui->headerEdit->text().simplified(), headerIsNull, MetaDataKey::SheetHeaderText);
|
meta->setString(ui->headerEdit->text().simplified(), headerIsNull,
|
||||||
meta->setString(ui->footerEdit->text().simplified(), footerIsNull, MetaDataKey::SheetFooterText);
|
MetaDataKey::SheetHeaderText);
|
||||||
|
meta->setString(ui->footerEdit->text().simplified(), footerIsNull,
|
||||||
|
MetaDataKey::SheetFooterText);
|
||||||
|
|
||||||
if(needsToSaveImg)
|
if (needsToSaveImg)
|
||||||
{
|
{
|
||||||
if(img.isNull())
|
if (img.isNull())
|
||||||
{
|
{
|
||||||
ImageMetaData::setImage(Session->m_Db, MetaDataKey::MeetingLogoPicture, nullptr, 0);
|
ImageMetaData::setImage(Session->m_Db, MetaDataKey::MeetingLogoPicture, nullptr, 0);
|
||||||
}
|
}
|
||||||
|
@ -189,10 +199,13 @@ void MeetingInformationDialog::saveData()
|
||||||
buf.open(QIODevice::WriteOnly);
|
buf.open(QIODevice::WriteOnly);
|
||||||
|
|
||||||
QImageWriter writer(&buf, "PNG");
|
QImageWriter writer(&buf, "PNG");
|
||||||
if(writer.canWrite() && writer.write(img))
|
if (writer.canWrite() && writer.write(img))
|
||||||
|
{
|
||||||
|
ImageMetaData::setImage(Session->m_Db, MetaDataKey::MeetingLogoPicture, arr.data(),
|
||||||
|
arr.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ImageMetaData::setImage(Session->m_Db, MetaDataKey::MeetingLogoPicture, arr.data(), arr.size());
|
|
||||||
}else{
|
|
||||||
qDebug() << "MeetingInformationDialog: error saving image," << writer.errorString();
|
qDebug() << "MeetingInformationDialog: error saving image," << writer.errorString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,25 +216,28 @@ void MeetingInformationDialog::showImage()
|
||||||
{
|
{
|
||||||
OwningQPointer<ImageViewer> dlg = new ImageViewer(this);
|
OwningQPointer<ImageViewer> dlg = new ImageViewer(this);
|
||||||
|
|
||||||
if(img.isNull() && !needsToSaveImg)
|
if (img.isNull() && !needsToSaveImg)
|
||||||
{
|
{
|
||||||
std::unique_ptr<ImageMetaData::ImageBlobDevice> imageIO;
|
std::unique_ptr<ImageMetaData::ImageBlobDevice> imageIO;
|
||||||
imageIO.reset(ImageMetaData::getImage(Session->m_Db, MetaDataKey::MeetingLogoPicture));
|
imageIO.reset(ImageMetaData::getImage(Session->m_Db, MetaDataKey::MeetingLogoPicture));
|
||||||
if(imageIO && imageIO->open(QIODevice::ReadOnly))
|
if (imageIO && imageIO->open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
QImageReader reader(imageIO.get());
|
QImageReader reader(imageIO.get());
|
||||||
if(reader.canRead())
|
if (reader.canRead())
|
||||||
{
|
{
|
||||||
img = reader.read(); //ERRORMSG: handle errors, show to user
|
img = reader.read(); // ERRORMSG: handle errors, show to user
|
||||||
}
|
}
|
||||||
|
|
||||||
if(img.isNull())
|
if (img.isNull())
|
||||||
{
|
{
|
||||||
qDebug() << "MeetingInformationDialog: error loading image," << reader.errorString();
|
qDebug() << "MeetingInformationDialog: error loading image,"
|
||||||
|
<< reader.errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
imageIO->close();
|
imageIO->close();
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
qDebug() << "MeetingInformationDialog: error query image," << Session->m_Db.error_msg();
|
qDebug() << "MeetingInformationDialog: error query image," << Session->m_Db.error_msg();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,15 +246,15 @@ void MeetingInformationDialog::showImage()
|
||||||
|
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
|
|
||||||
if(!needsToSaveImg)
|
if (!needsToSaveImg)
|
||||||
img = QImage(); //Cleanup to free memory
|
img = QImage(); // Cleanup to free memory
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeetingInformationDialog::importImage()
|
void MeetingInformationDialog::importImage()
|
||||||
{
|
{
|
||||||
const QLatin1String meeting_image_key = QLatin1String("meeting_image_key");
|
const QLatin1String meeting_image_key = QLatin1String("meeting_image_key");
|
||||||
|
|
||||||
OwningQPointer<QFileDialog> dlg = new QFileDialog(this, tr("Import image"));
|
OwningQPointer<QFileDialog> dlg = new QFileDialog(this, tr("Import image"));
|
||||||
dlg->setFileMode(QFileDialog::ExistingFile);
|
dlg->setFileMode(QFileDialog::ExistingFile);
|
||||||
dlg->setAcceptMode(QFileDialog::AcceptOpen);
|
dlg->setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
dlg->setDirectory(RecentDirStore::getDir(meeting_image_key, RecentDirStore::Images));
|
dlg->setDirectory(RecentDirStore::getDir(meeting_image_key, RecentDirStore::Images));
|
||||||
|
@ -246,28 +262,28 @@ void MeetingInformationDialog::importImage()
|
||||||
QList<QByteArray> mimes = QImageReader::supportedMimeTypes();
|
QList<QByteArray> mimes = QImageReader::supportedMimeTypes();
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
filters.reserve(mimes.size() + 1);
|
filters.reserve(mimes.size() + 1);
|
||||||
for(const QByteArray &ba : mimes)
|
for (const QByteArray &ba : mimes)
|
||||||
filters.append(QString::fromUtf8(ba));
|
filters.append(QString::fromUtf8(ba));
|
||||||
|
|
||||||
filters << "application/octet-stream"; // will show "All files (*)"
|
filters << "application/octet-stream"; // will show "All files (*)"
|
||||||
|
|
||||||
dlg->setMimeTypeFilters(filters);
|
dlg->setMimeTypeFilters(filters);
|
||||||
|
|
||||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||||
if(fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RecentDirStore::setPath(meeting_image_key, fileName);
|
RecentDirStore::setPath(meeting_image_key, fileName);
|
||||||
|
|
||||||
QImageReader reader(fileName);
|
QImageReader reader(fileName);
|
||||||
reader.setQuality(100);
|
reader.setQuality(100);
|
||||||
if(reader.canRead())
|
if (reader.canRead())
|
||||||
{
|
{
|
||||||
QImage image = reader.read();
|
QImage image = reader.read();
|
||||||
if(image.isNull())
|
if (image.isNull())
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Importing error"),
|
QMessageBox::warning(this, tr("Importing error"),
|
||||||
tr("The image format is not supported or the file is corrupted."));
|
tr("The image format is not supported or the file is corrupted."));
|
||||||
|
@ -275,7 +291,7 @@ void MeetingInformationDialog::importImage()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
img = image;
|
img = image;
|
||||||
needsToSaveImg = true;
|
needsToSaveImg = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,10 +300,10 @@ void MeetingInformationDialog::removeImage()
|
||||||
{
|
{
|
||||||
int ret = QMessageBox::question(this, tr("Remove image?"),
|
int ret = QMessageBox::question(this, tr("Remove image?"),
|
||||||
tr("Are you sure to remove the image logo?"));
|
tr("Are you sure to remove the image logo?"));
|
||||||
if(ret != QMessageBox::Yes)
|
if (ret != QMessageBox::Yes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
img = QImage(); //Cleanup to free memory
|
img = QImage(); // Cleanup to free memory
|
||||||
needsToSaveImg = true;
|
needsToSaveImg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,29 +21,29 @@
|
||||||
|
|
||||||
#include <sqlite3pp/sqlite3pp.h>
|
#include <sqlite3pp/sqlite3pp.h>
|
||||||
|
|
||||||
constexpr char sql_get_metadata[] = "SELECT val FROM metadata WHERE name=?";
|
constexpr char sql_get_metadata[] = "SELECT val FROM metadata WHERE name=?";
|
||||||
constexpr char sql_has_metadata_key[] = "SELECT 1 FROM metadata WHERE name=? AND val NOT NULL";
|
constexpr char sql_has_metadata_key[] = "SELECT 1 FROM metadata WHERE name=? AND val NOT NULL";
|
||||||
constexpr char sql_set_metadata[] = "REPLACE INTO metadata(name, val) VALUES(?, ?)";
|
constexpr char sql_set_metadata[] = "REPLACE INTO metadata(name, val) VALUES(?, ?)";
|
||||||
|
|
||||||
MetaDataManager::MetaDataManager(sqlite3pp::database &db) :
|
MetaDataManager::MetaDataManager(sqlite3pp::database &db) :
|
||||||
mDb(db)
|
mDb(db)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDataKey::Result MetaDataManager::hasKey(const MetaDataManager::Key &key)
|
MetaDataKey::Result MetaDataManager::hasKey(const MetaDataManager::Key &key)
|
||||||
{
|
{
|
||||||
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
||||||
if(!mDb.db())
|
if (!mDb.db())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_has_metadata_key, sizeof (sql_has_metadata_key) - 1, &stmt, nullptr);
|
int rc = sqlite3_prepare_v2(mDb.db(), sql_has_metadata_key, sizeof(sql_has_metadata_key) - 1,
|
||||||
if(rc != SQLITE_OK)
|
&stmt, nullptr);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return result;
|
return result;
|
||||||
|
@ -51,11 +51,11 @@ MetaDataKey::Result MetaDataManager::hasKey(const MetaDataManager::Key &key)
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
if(rc == SQLITE_ROW)
|
if (rc == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueFound;
|
result = MetaDataKey::Result::ValueFound;
|
||||||
}
|
}
|
||||||
else if(rc == SQLITE_OK || rc == SQLITE_DONE)
|
else if (rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueNotFound;
|
result = MetaDataKey::Result::ValueNotFound;
|
||||||
}
|
}
|
||||||
|
@ -68,19 +68,20 @@ MetaDataKey::Result MetaDataManager::hasKey(const MetaDataManager::Key &key)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDataKey::Result MetaDataManager::getInt64(qint64 &out, const Key& key)
|
MetaDataKey::Result MetaDataManager::getInt64(qint64 &out, const Key &key)
|
||||||
{
|
{
|
||||||
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
||||||
if(!mDb.db())
|
if (!mDb.db())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_get_metadata, sizeof (sql_get_metadata) - 1, &stmt, nullptr);
|
int rc =
|
||||||
if(rc != SQLITE_OK)
|
sqlite3_prepare_v2(mDb.db(), sql_get_metadata, sizeof(sql_get_metadata) - 1, &stmt, nullptr);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return result;
|
return result;
|
||||||
|
@ -88,19 +89,19 @@ MetaDataKey::Result MetaDataManager::getInt64(qint64 &out, const Key& key)
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
if(rc == SQLITE_ROW)
|
if (rc == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
if(sqlite3_column_type(stmt, 0) == SQLITE_NULL)
|
if (sqlite3_column_type(stmt, 0) == SQLITE_NULL)
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueIsNull;
|
result = MetaDataKey::Result::ValueIsNull;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueFound;
|
result = MetaDataKey::Result::ValueFound;
|
||||||
out = sqlite3_column_int64(stmt, 0);
|
out = sqlite3_column_int64(stmt, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(rc == SQLITE_OK || rc == SQLITE_DONE)
|
else if (rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueNotFound;
|
result = MetaDataKey::Result::ValueNotFound;
|
||||||
}
|
}
|
||||||
|
@ -113,29 +114,30 @@ MetaDataKey::Result MetaDataManager::getInt64(qint64 &out, const Key& key)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDataKey::Result MetaDataManager::setInt64(qint64 in, bool setToNull, const Key& key)
|
MetaDataKey::Result MetaDataManager::setInt64(qint64 in, bool setToNull, const Key &key)
|
||||||
{
|
{
|
||||||
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
||||||
if(!mDb.db())
|
if (!mDb.db())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_set_metadata, sizeof (sql_set_metadata) - 1, &stmt, nullptr);
|
int rc =
|
||||||
if(rc != SQLITE_OK)
|
sqlite3_prepare_v2(mDb.db(), sql_set_metadata, sizeof(sql_set_metadata) - 1, &stmt, nullptr);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(setToNull)
|
if (setToNull)
|
||||||
rc = sqlite3_bind_null(stmt, 2);
|
rc = sqlite3_bind_null(stmt, 2);
|
||||||
else
|
else
|
||||||
rc = sqlite3_bind_int64(stmt, 2, in);
|
rc = sqlite3_bind_int64(stmt, 2, in);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return result;
|
return result;
|
||||||
|
@ -143,7 +145,7 @@ MetaDataKey::Result MetaDataManager::setInt64(qint64 in, bool setToNull, const K
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
if(rc == SQLITE_OK || rc == SQLITE_DONE)
|
if (rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueFound;
|
result = MetaDataKey::Result::ValueFound;
|
||||||
}
|
}
|
||||||
|
@ -156,19 +158,20 @@ MetaDataKey::Result MetaDataManager::setInt64(qint64 in, bool setToNull, const K
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDataKey::Result MetaDataManager::getString(QString &out, const Key& key)
|
MetaDataKey::Result MetaDataManager::getString(QString &out, const Key &key)
|
||||||
{
|
{
|
||||||
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
||||||
if(!mDb.db())
|
if (!mDb.db())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_get_metadata, sizeof (sql_get_metadata) - 1, &stmt, nullptr);
|
int rc =
|
||||||
if(rc != SQLITE_OK)
|
sqlite3_prepare_v2(mDb.db(), sql_get_metadata, sizeof(sql_get_metadata) - 1, &stmt, nullptr);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return result;
|
return result;
|
||||||
|
@ -176,21 +179,21 @@ MetaDataKey::Result MetaDataManager::getString(QString &out, const Key& key)
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
if(rc == SQLITE_ROW)
|
if (rc == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
if(sqlite3_column_type(stmt, 0) == SQLITE_NULL)
|
if (sqlite3_column_type(stmt, 0) == SQLITE_NULL)
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueIsNull;
|
result = MetaDataKey::Result::ValueIsNull;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueFound;
|
result = MetaDataKey::Result::ValueFound;
|
||||||
const int len = sqlite3_column_bytes(stmt, 0);
|
const int len = sqlite3_column_bytes(stmt, 0);
|
||||||
const char *text = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 0));
|
const char *text = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 0));
|
||||||
out = QString::fromUtf8(text, len);
|
out = QString::fromUtf8(text, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(rc == SQLITE_OK || rc == SQLITE_DONE)
|
else if (rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueNotFound;
|
result = MetaDataKey::Result::ValueNotFound;
|
||||||
}
|
}
|
||||||
|
@ -203,19 +206,20 @@ MetaDataKey::Result MetaDataManager::getString(QString &out, const Key& key)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDataKey::Result MetaDataManager::setString(const QString& in, bool setToNull, const Key& key)
|
MetaDataKey::Result MetaDataManager::setString(const QString &in, bool setToNull, const Key &key)
|
||||||
{
|
{
|
||||||
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
||||||
if(!mDb.db())
|
if (!mDb.db())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_set_metadata, sizeof (sql_set_metadata) - 1, &stmt, nullptr);
|
int rc =
|
||||||
if(rc != SQLITE_OK)
|
sqlite3_prepare_v2(mDb.db(), sql_set_metadata, sizeof(sql_set_metadata) - 1, &stmt, nullptr);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return result;
|
return result;
|
||||||
|
@ -223,13 +227,13 @@ MetaDataKey::Result MetaDataManager::setString(const QString& in, bool setToNull
|
||||||
|
|
||||||
QByteArray arr = in.toUtf8();
|
QByteArray arr = in.toUtf8();
|
||||||
|
|
||||||
if(setToNull)
|
if (setToNull)
|
||||||
rc = sqlite3_bind_null(stmt, 2);
|
rc = sqlite3_bind_null(stmt, 2);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = sqlite3_bind_text(stmt, 2, arr.data(), arr.size(), SQLITE_STATIC);
|
rc = sqlite3_bind_text(stmt, 2, arr.data(), arr.size(), SQLITE_STATIC);
|
||||||
}
|
}
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
return result;
|
return result;
|
||||||
|
@ -237,7 +241,7 @@ MetaDataKey::Result MetaDataManager::setString(const QString& in, bool setToNull
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
if(rc == SQLITE_OK || rc == SQLITE_DONE)
|
if (rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
result = MetaDataKey::Result::ValueFound;
|
result = MetaDataKey::Result::ValueFound;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,42 +27,46 @@ namespace sqlite3pp {
|
||||||
class database;
|
class database;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MetaDataKey
|
namespace MetaDataKey {
|
||||||
{
|
|
||||||
enum Result
|
enum Result
|
||||||
{
|
{
|
||||||
ValueFound = 0,
|
ValueFound = 0,
|
||||||
ValueIsNull,
|
ValueIsNull,
|
||||||
ValueNotFound,
|
ValueNotFound,
|
||||||
NoMetaDataTable, //Format is too old, 'metadata' table is not present
|
NoMetaDataTable, // Format is too old, 'metadata' table is not present
|
||||||
|
|
||||||
NResults
|
NResults
|
||||||
};
|
};
|
||||||
|
|
||||||
//BEGING Key constants TODO: maybe make static or extern to avoid duplication
|
// BEGING Key constants TODO: maybe make static or extern to avoid duplication
|
||||||
|
|
||||||
//Database
|
// Database
|
||||||
constexpr char FormatVersionKey[] = "format_version"; //INTEGER: version, NOTE: FormatVersion is aleady used by info.h constants
|
constexpr char FormatVersionKey[] =
|
||||||
constexpr char ApplicationString[] = "application_str"; //STRING: application version string 'maj.min.patch'
|
"format_version"; // INTEGER: version, NOTE: FormatVersion is aleady used by info.h constants
|
||||||
|
constexpr char ApplicationString[] =
|
||||||
|
"application_str"; // STRING: application version string 'maj.min.patch'
|
||||||
|
|
||||||
//Meeting
|
// Meeting
|
||||||
constexpr char MeetingShowDates[] = "meeting_show_dates"; //INTEGER: 1 shows dates, 0 hides them
|
constexpr char MeetingShowDates[] = "meeting_show_dates"; // INTEGER: 1 shows dates, 0 hides them
|
||||||
constexpr char MeetingStartDate[] = "meeting_start_date"; //INTEGER: Start date in Julian Day integer
|
constexpr char MeetingStartDate[] =
|
||||||
constexpr char MeetingEndDate[] = "meeting_end_date"; //INTEGER: End date in Juliand Day integer
|
"meeting_start_date"; // INTEGER: Start date in Julian Day integer
|
||||||
constexpr char MeetingLocation[] = "meeting_location"; //STRING: city name
|
constexpr char MeetingEndDate[] = "meeting_end_date"; // INTEGER: End date in Juliand Day integer
|
||||||
constexpr char MeetingDescription[] = "meeting_descr"; //STRING: brief description of the meeting
|
constexpr char MeetingLocation[] = "meeting_location"; // STRING: city name
|
||||||
constexpr char MeetingHostAssociation[] = "meeting_host"; //STRING: name of association that is hosting the meeting
|
constexpr char MeetingDescription[] = "meeting_descr"; // STRING: brief description of the meeting
|
||||||
constexpr char MeetingLogoPicture[] = "meeting_logo"; //BLOB: PNG alpha image, usually hosting association logo
|
constexpr char MeetingHostAssociation[] =
|
||||||
|
"meeting_host"; // STRING: name of association that is hosting the meeting
|
||||||
|
constexpr char MeetingLogoPicture[] =
|
||||||
|
"meeting_logo"; // BLOB: PNG alpha image, usually hosting association logo
|
||||||
|
|
||||||
//ODT Export Sheet
|
// ODT Export Sheet
|
||||||
constexpr char SheetHeaderText[] = "sheet_header"; //STRING: sheet header text
|
constexpr char SheetHeaderText[] = "sheet_header"; // STRING: sheet header text
|
||||||
constexpr char SheetFooterText[] = "sheet_footer"; //STRING: sheet footer text
|
constexpr char SheetFooterText[] = "sheet_footer"; // STRING: sheet footer text
|
||||||
|
|
||||||
//Jobs
|
// Jobs
|
||||||
#define METADATA_MAKE_RS_KEY(category) ("job_default_stop_" ## #category)
|
#define METADATA_MAKE_RS_KEY(category) ("job_default_stop_"## #category)
|
||||||
|
|
||||||
//END Key constants
|
// END Key constants
|
||||||
}
|
} // namespace MetaDataKey
|
||||||
|
|
||||||
class MetaDataManager
|
class MetaDataManager
|
||||||
{
|
{
|
||||||
|
@ -71,16 +75,20 @@ public:
|
||||||
|
|
||||||
struct Key
|
struct Key
|
||||||
{
|
{
|
||||||
template<int N>
|
template <int N>
|
||||||
constexpr inline Key(const char (&val)[N]) :str(val), len(N - 1) {}
|
constexpr inline Key(const char (&val)[N]) :
|
||||||
|
str(val),
|
||||||
|
len(N - 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
const char *str;
|
const char *str;
|
||||||
const int len;
|
const int len;
|
||||||
};
|
};
|
||||||
|
|
||||||
MetaDataKey::Result hasKey(const Key& key);
|
MetaDataKey::Result hasKey(const Key &key);
|
||||||
|
|
||||||
MetaDataKey::Result getInt64(qint64 &out, const Key& key);
|
MetaDataKey::Result getInt64(qint64 &out, const Key &key);
|
||||||
MetaDataKey::Result setInt64(qint64 in, bool setToNull, const Key &key);
|
MetaDataKey::Result setInt64(qint64 in, bool setToNull, const Key &key);
|
||||||
|
|
||||||
MetaDataKey::Result getString(QString &out, const Key &key);
|
MetaDataKey::Result getString(QString &out, const Key &key);
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
add_subdirectory(model)
|
add_subdirectory(model) add_subdirectory(view)
|
||||||
add_subdirectory(view)
|
|
||||||
|
|
||||||
set(MR_TIMETABLE_PLANNER_SOURCES
|
set(MR_TIMETABLE_PLANNER_SOURCES ${MR_TIMETABLE_PLANNER_SOURCES} graph / linegraphtypes.h graph
|
||||||
${MR_TIMETABLE_PLANNER_SOURCES}
|
/ linegraphtypes.cpp PARENT_SCOPE)
|
||||||
graph/linegraphtypes.h
|
|
||||||
graph/linegraphtypes.cpp
|
|
||||||
PARENT_SCOPE
|
|
||||||
)
|
|
||||||
|
|
|
@ -28,16 +28,14 @@ public:
|
||||||
static const char *texts[];
|
static const char *texts[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *LineGraphTypeNames::texts[] = {
|
const char *LineGraphTypeNames::texts[] = {QT_TRANSLATE_NOOP("LineGraphTypeNames", "No Graph"),
|
||||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "No Graph"),
|
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Station"),
|
||||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Station"),
|
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Segment"),
|
||||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Segment"),
|
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Line")};
|
||||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Line")
|
|
||||||
};
|
|
||||||
|
|
||||||
QString utils::getLineGraphTypeName(LineGraphType type)
|
QString utils::getLineGraphTypeName(LineGraphType type)
|
||||||
{
|
{
|
||||||
if(type >= LineGraphType::NTypes)
|
if (type >= LineGraphType::NTypes)
|
||||||
return QString();
|
return QString();
|
||||||
return LineGraphTypeNames::tr(LineGraphTypeNames::texts[int(type)]);
|
return LineGraphTypeNames::tr(LineGraphTypeNames::texts[int(type)]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,10 @@
|
||||||
*/
|
*/
|
||||||
enum class LineGraphType
|
enum class LineGraphType
|
||||||
{
|
{
|
||||||
NoGraph = 0, //!< No content displayed
|
NoGraph = 0, //!< No content displayed
|
||||||
SingleStation, //!< Show a single station
|
SingleStation, //!< Show a single station
|
||||||
RailwaySegment, //!< Show two adjacent stations and the segment in between
|
RailwaySegment, //!< Show two adjacent stations and the segment in between
|
||||||
RailwayLine, //!< Show a complete railway line (multiple adjacent segments)
|
RailwayLine, //!< Show a complete railway line (multiple adjacent segments)
|
||||||
NTypes
|
NTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,34 +41,41 @@ LineGraphManager::LineGraphManager(QObject *parent) :
|
||||||
m_hasScheduledUpdate(false)
|
m_hasScheduledUpdate(false)
|
||||||
{
|
{
|
||||||
auto session = Session;
|
auto session = Session;
|
||||||
//Stations
|
// Stations
|
||||||
connect(session, &MeetingSession::stationNameChanged, this, &LineGraphManager::onStationNameChanged);
|
connect(session, &MeetingSession::stationNameChanged, this,
|
||||||
connect(session, &MeetingSession::stationJobsPlanChanged, this, &LineGraphManager::onStationJobPlanChanged);
|
&LineGraphManager::onStationNameChanged);
|
||||||
connect(session, &MeetingSession::stationTrackPlanChanged, this, &LineGraphManager::onStationTrackPlanChanged);
|
connect(session, &MeetingSession::stationJobsPlanChanged, this,
|
||||||
|
&LineGraphManager::onStationJobPlanChanged);
|
||||||
|
connect(session, &MeetingSession::stationTrackPlanChanged, this,
|
||||||
|
&LineGraphManager::onStationTrackPlanChanged);
|
||||||
connect(session, &MeetingSession::stationRemoved, this, &LineGraphManager::onStationRemoved);
|
connect(session, &MeetingSession::stationRemoved, this, &LineGraphManager::onStationRemoved);
|
||||||
|
|
||||||
//Segments
|
// Segments
|
||||||
connect(session, &MeetingSession::segmentNameChanged, this, &LineGraphManager::onSegmentNameChanged);
|
connect(session, &MeetingSession::segmentNameChanged, this,
|
||||||
connect(session, &MeetingSession::segmentStationsChanged, this, &LineGraphManager::onSegmentStationsChanged);
|
&LineGraphManager::onSegmentNameChanged);
|
||||||
|
connect(session, &MeetingSession::segmentStationsChanged, this,
|
||||||
|
&LineGraphManager::onSegmentStationsChanged);
|
||||||
connect(session, &MeetingSession::segmentRemoved, this, &LineGraphManager::onSegmentRemoved);
|
connect(session, &MeetingSession::segmentRemoved, this, &LineGraphManager::onSegmentRemoved);
|
||||||
|
|
||||||
//Lines
|
// Lines
|
||||||
connect(session, &MeetingSession::lineNameChanged, this, &LineGraphManager::onLineNameChanged);
|
connect(session, &MeetingSession::lineNameChanged, this, &LineGraphManager::onLineNameChanged);
|
||||||
connect(session, &MeetingSession::lineSegmentsChanged, this, &LineGraphManager::onLineSegmentsChanged);
|
connect(session, &MeetingSession::lineSegmentsChanged, this,
|
||||||
|
&LineGraphManager::onLineSegmentsChanged);
|
||||||
connect(session, &MeetingSession::lineRemoved, this, &LineGraphManager::onLineRemoved);
|
connect(session, &MeetingSession::lineRemoved, this, &LineGraphManager::onLineRemoved);
|
||||||
|
|
||||||
//Jobs
|
// Jobs
|
||||||
connect(session, &MeetingSession::jobChanged, this, &LineGraphManager::onJobChanged);
|
connect(session, &MeetingSession::jobChanged, this, &LineGraphManager::onJobChanged);
|
||||||
connect(session, &MeetingSession::jobRemoved, this, &LineGraphManager::onJobRemoved);
|
connect(session, &MeetingSession::jobRemoved, this, &LineGraphManager::onJobRemoved);
|
||||||
|
|
||||||
//Settings
|
// Settings
|
||||||
connect(&AppSettings, &MRTPSettings::jobGraphOptionsChanged, this, &LineGraphManager::updateGraphOptions);
|
connect(&AppSettings, &MRTPSettings::jobGraphOptionsChanged, this,
|
||||||
|
&LineGraphManager::updateGraphOptions);
|
||||||
m_followJobOnGraphChange = AppSettings.getFollowSelectionOnGraphChange();
|
m_followJobOnGraphChange = AppSettings.getFollowSelectionOnGraphChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphManager::event(QEvent *ev)
|
bool LineGraphManager::event(QEvent *ev)
|
||||||
{
|
{
|
||||||
if(ev->type() == QEvent::Type(CustomEvents::LineGraphManagerUpdate))
|
if (ev->type() == QEvent::Type(CustomEvents::LineGraphManagerUpdate))
|
||||||
{
|
{
|
||||||
ev->accept();
|
ev->accept();
|
||||||
processPendingUpdates();
|
processPendingUpdates();
|
||||||
|
@ -88,13 +95,13 @@ void LineGraphManager::registerScene(LineGraphScene *scene)
|
||||||
connect(scene, &LineGraphScene::sceneActivated, this, &LineGraphManager::setActiveScene);
|
connect(scene, &LineGraphScene::sceneActivated, this, &LineGraphManager::setActiveScene);
|
||||||
connect(scene, &LineGraphScene::jobSelected, this, &LineGraphManager::onJobSelected);
|
connect(scene, &LineGraphScene::jobSelected, this, &LineGraphManager::onJobSelected);
|
||||||
|
|
||||||
if(m_followJobOnGraphChange)
|
if (m_followJobOnGraphChange)
|
||||||
connect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
connect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
||||||
|
|
||||||
if(scenes.count() == 1)
|
if (scenes.count() == 1)
|
||||||
{
|
{
|
||||||
//This is the first scene registered
|
// This is the first scene registered
|
||||||
//activate it so we have an active scene even if user does't activate one
|
// activate it so we have an active scene even if user does't activate one
|
||||||
setActiveScene(scene);
|
setActiveScene(scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,17 +116,17 @@ void LineGraphManager::unregisterScene(LineGraphScene *scene)
|
||||||
disconnect(scene, &LineGraphScene::sceneActivated, this, &LineGraphManager::setActiveScene);
|
disconnect(scene, &LineGraphScene::sceneActivated, this, &LineGraphManager::setActiveScene);
|
||||||
disconnect(scene, &LineGraphScene::jobSelected, this, &LineGraphManager::onJobSelected);
|
disconnect(scene, &LineGraphScene::jobSelected, this, &LineGraphManager::onJobSelected);
|
||||||
|
|
||||||
if(m_followJobOnGraphChange)
|
if (m_followJobOnGraphChange)
|
||||||
disconnect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
disconnect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
||||||
|
|
||||||
//Reset active scene if it is unregistered
|
// Reset active scene if it is unregistered
|
||||||
if(activeScene == scene)
|
if (activeScene == scene)
|
||||||
setActiveScene(nullptr);
|
setActiveScene(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::clearAllGraphs()
|
void LineGraphManager::clearAllGraphs()
|
||||||
{
|
{
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
scene->loadGraph(0, LineGraphType::NoGraph, true);
|
scene->loadGraph(0, LineGraphType::NoGraph, true);
|
||||||
}
|
}
|
||||||
|
@ -127,9 +134,9 @@ void LineGraphManager::clearAllGraphs()
|
||||||
|
|
||||||
void LineGraphManager::clearGraphsOfObject(db_id objectId, LineGraphType type)
|
void LineGraphManager::clearGraphsOfObject(db_id objectId, LineGraphType type)
|
||||||
{
|
{
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(scene->getGraphObjectId() == objectId && scene->getGraphType() == type)
|
if (scene->getGraphObjectId() == objectId && scene->getGraphType() == type)
|
||||||
scene->loadGraph(0, LineGraphType::NoGraph);
|
scene->loadGraph(0, LineGraphType::NoGraph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,61 +144,60 @@ void LineGraphManager::clearGraphsOfObject(db_id objectId, LineGraphType type)
|
||||||
JobStopEntry LineGraphManager::getCurrentSelectedJob() const
|
JobStopEntry LineGraphManager::getCurrentSelectedJob() const
|
||||||
{
|
{
|
||||||
JobStopEntry selectedJob;
|
JobStopEntry selectedJob;
|
||||||
if(activeScene)
|
if (activeScene)
|
||||||
selectedJob = activeScene->getSelectedJob();
|
selectedJob = activeScene->getSelectedJob();
|
||||||
return selectedJob;
|
return selectedJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::scheduleUpdate()
|
void LineGraphManager::scheduleUpdate()
|
||||||
{
|
{
|
||||||
if(m_hasScheduledUpdate)
|
if (m_hasScheduledUpdate)
|
||||||
return; //Already scheduled
|
return; // Already scheduled
|
||||||
|
|
||||||
//Mark as scheduled and post event to ourself
|
// Mark as scheduled and post event to ourself
|
||||||
m_hasScheduledUpdate = true;
|
m_hasScheduledUpdate = true;
|
||||||
QCoreApplication::postEvent(this,
|
QCoreApplication::postEvent(
|
||||||
new QEvent(QEvent::Type(CustomEvents::LineGraphManagerUpdate)),
|
this, new QEvent(QEvent::Type(CustomEvents::LineGraphManagerUpdate)), Qt::HighEventPriority);
|
||||||
Qt::HighEventPriority);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::processPendingUpdates()
|
void LineGraphManager::processPendingUpdates()
|
||||||
{
|
{
|
||||||
constexpr int MAX_UPDATE_TIME_MS = 1000;
|
constexpr int MAX_UPDATE_TIME_MS = 1000;
|
||||||
|
|
||||||
//Clear update flag before updating in case one operation triggers update
|
// Clear update flag before updating in case one operation triggers update
|
||||||
m_hasScheduledUpdate = false;
|
m_hasScheduledUpdate = false;
|
||||||
|
|
||||||
QElapsedTimer timer;
|
QElapsedTimer timer;
|
||||||
timer.start();
|
timer.start();
|
||||||
|
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(timer.elapsed() > MAX_UPDATE_TIME_MS)
|
if (timer.elapsed() > MAX_UPDATE_TIME_MS)
|
||||||
{
|
{
|
||||||
//It's taking to long, schedule a second update batch to finish
|
// It's taking to long, schedule a second update batch to finish
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::NothingToDo))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::NothingToDo))
|
||||||
continue; //Skip
|
continue; // Skip
|
||||||
|
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||||
{
|
{
|
||||||
scene->reload();
|
scene->reload();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::ReloadJobs))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::ReloadJobs))
|
||||||
{
|
{
|
||||||
scene->reloadJobs();
|
scene->reloadJobs();
|
||||||
}
|
}
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::ReloadStationNames))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::ReloadStationNames))
|
||||||
{
|
{
|
||||||
scene->updateStationNames();
|
scene->updateStationNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Manually cleare pending update and trigger redraw
|
// Manually cleare pending update and trigger redraw
|
||||||
scene->pendingUpdate = PendingUpdate::NothingToDo;
|
scene->pendingUpdate = PendingUpdate::NothingToDo;
|
||||||
emit scene->redrawGraph();
|
emit scene->redrawGraph();
|
||||||
}
|
}
|
||||||
|
@ -202,28 +208,28 @@ void LineGraphManager::setActiveScene(IGraphScene *scene)
|
||||||
{
|
{
|
||||||
LineGraphScene *lineScene = qobject_cast<LineGraphScene *>(scene);
|
LineGraphScene *lineScene = qobject_cast<LineGraphScene *>(scene);
|
||||||
|
|
||||||
if(lineScene)
|
if (lineScene)
|
||||||
{
|
{
|
||||||
if(activeScene == lineScene)
|
if (activeScene == lineScene)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//NOTE: Only registere scenes can become active
|
// NOTE: Only registere scenes can become active
|
||||||
//Otherwise we cannot track if scene got destroyed and reset active scene.
|
// Otherwise we cannot track if scene got destroyed and reset active scene.
|
||||||
if(!scenes.contains(lineScene))
|
if (!scenes.contains(lineScene))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(!scenes.isEmpty())
|
else if (!scenes.isEmpty())
|
||||||
{
|
{
|
||||||
//Activate first registered scene because previous one was unregistered
|
// Activate first registered scene because previous one was unregistered
|
||||||
lineScene = scenes.first();
|
lineScene = scenes.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
activeScene = lineScene;
|
activeScene = lineScene;
|
||||||
emit activeSceneChanged(activeScene);
|
emit activeSceneChanged(activeScene);
|
||||||
|
|
||||||
//Triegger selection update or clear it
|
// Triegger selection update or clear it
|
||||||
JobStopEntry selectedJob;
|
JobStopEntry selectedJob;
|
||||||
if(activeScene)
|
if (activeScene)
|
||||||
{
|
{
|
||||||
selectedJob = activeScene->getSelectedJob();
|
selectedJob = activeScene->getSelectedJob();
|
||||||
}
|
}
|
||||||
|
@ -239,58 +245,60 @@ void LineGraphManager::onSceneDestroyed(QObject *obj)
|
||||||
|
|
||||||
void LineGraphManager::onGraphChanged(int /*graphType_*/, db_id graphObjId, LineGraphScene *scene)
|
void LineGraphManager::onGraphChanged(int /*graphType_*/, db_id graphObjId, LineGraphScene *scene)
|
||||||
{
|
{
|
||||||
if(!m_followJobOnGraphChange || !scenes.contains(scene))
|
if (!m_followJobOnGraphChange || !scenes.contains(scene))
|
||||||
{
|
{
|
||||||
qWarning() << "LineGraphManager: should not receive graph change for scene" << scene;
|
qWarning() << "LineGraphManager: should not receive graph change for scene" << scene;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!graphObjId || scene->getGraphType() == LineGraphType::NoGraph)
|
if (!graphObjId || scene->getGraphType() == LineGraphType::NoGraph)
|
||||||
return; //No graph selected
|
return; // No graph selected
|
||||||
|
|
||||||
//Graph has changed, ensure selected job is still visible (if possible)
|
// Graph has changed, ensure selected job is still visible (if possible)
|
||||||
JobStopEntry selectedJob = scene->getSelectedJob();
|
JobStopEntry selectedJob = scene->getSelectedJob();
|
||||||
if(!selectedJob.jobId)
|
if (!selectedJob.jobId)
|
||||||
return; //No job selected, nothing to do
|
return; // No job selected, nothing to do
|
||||||
|
|
||||||
LineGraphSelectionHelper helper(Session->m_Db);
|
LineGraphSelectionHelper helper(Session->m_Db);
|
||||||
|
|
||||||
LineGraphSelectionHelper::SegmentInfo info;
|
LineGraphSelectionHelper::SegmentInfo info;
|
||||||
if(!helper.tryFindJobStopInGraph(scene, selectedJob.jobId, info))
|
if (!helper.tryFindJobStopInGraph(scene, selectedJob.jobId, info))
|
||||||
return; //Cannot find job in current graph, give up
|
return; // Cannot find job in current graph, give up
|
||||||
|
|
||||||
//Ensure job is visible
|
// Ensure job is visible
|
||||||
scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart, info.departure);
|
scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart,
|
||||||
|
info.departure);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::onJobSelected(db_id jobId, int category, db_id stopId)
|
void LineGraphManager::onJobSelected(db_id jobId, int category, db_id stopId)
|
||||||
{
|
{
|
||||||
JobCategory cat = JobCategory(category);
|
JobCategory cat = JobCategory(category);
|
||||||
if(lastSelectedJob.jobId == jobId && lastSelectedJob.category == cat && lastSelectedJob.stopId == stopId)
|
if (lastSelectedJob.jobId == jobId && lastSelectedJob.category == cat
|
||||||
return; //Selection did not change
|
&& lastSelectedJob.stopId == stopId)
|
||||||
|
return; // Selection did not change
|
||||||
|
|
||||||
lastSelectedJob.jobId = jobId;
|
lastSelectedJob.jobId = jobId;
|
||||||
lastSelectedJob.category = cat;
|
lastSelectedJob.category = cat;
|
||||||
lastSelectedJob.stopId = stopId;
|
lastSelectedJob.stopId = stopId;
|
||||||
|
|
||||||
if(jobId)
|
if (jobId)
|
||||||
Session->getViewManager()->requestJobEditor(jobId);
|
Session->getViewManager()->requestJobEditor(jobId);
|
||||||
else
|
else
|
||||||
Session->getViewManager()->requestClearJob();
|
Session->getViewManager()->requestClearJob();
|
||||||
|
|
||||||
if(AppSettings.getSyncSelectionOnAllGraphs())
|
if (AppSettings.getSyncSelectionOnAllGraphs())
|
||||||
{
|
{
|
||||||
//Sync selection among all registered scenes
|
// Sync selection among all registered scenes
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
scene->setSelectedJob(lastSelectedJob);
|
scene->setSelectedJob(lastSelectedJob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(activeScene)
|
if (activeScene)
|
||||||
{
|
{
|
||||||
const JobStopEntry selectedJob = activeScene->getSelectedJob();
|
const JobStopEntry selectedJob = activeScene->getSelectedJob();
|
||||||
if(selectedJob.jobId == lastSelectedJob.jobId)
|
if (selectedJob.jobId == lastSelectedJob.jobId)
|
||||||
{
|
{
|
||||||
emit jobSelected(lastSelectedJob.jobId, int(lastSelectedJob.category),
|
emit jobSelected(lastSelectedJob.jobId, int(lastSelectedJob.category),
|
||||||
lastSelectedJob.stopId);
|
lastSelectedJob.stopId);
|
||||||
|
@ -302,23 +310,23 @@ void LineGraphManager::onStationNameChanged(db_id stationId)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||||
continue; //Already flagged
|
continue; // Already flagged
|
||||||
|
|
||||||
if(scene->stations.contains(stationId))
|
if (scene->stations.contains(stationId))
|
||||||
{
|
{
|
||||||
scene->pendingUpdate.setFlag(PendingUpdate::ReloadStationNames);
|
scene->pendingUpdate.setFlag(PendingUpdate::ReloadStationNames);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(found)
|
if (found)
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::onStationJobPlanChanged(const QSet<db_id>& stationIds)
|
void LineGraphManager::onStationJobPlanChanged(const QSet<db_id> &stationIds)
|
||||||
{
|
{
|
||||||
onStationPlanChanged_internal(stationIds, int(PendingUpdate::ReloadJobs));
|
onStationPlanChanged_internal(stationIds, int(PendingUpdate::ReloadJobs));
|
||||||
}
|
}
|
||||||
|
@ -330,9 +338,9 @@ void LineGraphManager::onStationTrackPlanChanged(const QSet<db_id> &stationIds)
|
||||||
|
|
||||||
void LineGraphManager::onStationRemoved(db_id stationId)
|
void LineGraphManager::onStationRemoved(db_id stationId)
|
||||||
{
|
{
|
||||||
//A station can be removed only when not connected and no jobs pass through it.
|
// A station can be removed only when not connected and no jobs pass through it.
|
||||||
//So there is no need to update other scenes because no line will contain
|
// So there is no need to update other scenes because no line will contain
|
||||||
//The removed station
|
// The removed station
|
||||||
clearGraphsOfObject(stationId, LineGraphType::SingleStation);
|
clearGraphsOfObject(stationId, LineGraphType::SingleStation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,25 +348,25 @@ void LineGraphManager::onSegmentNameChanged(db_id segmentId)
|
||||||
{
|
{
|
||||||
QString segName;
|
QString segName;
|
||||||
|
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||||
continue; //Already flagged
|
continue; // Already flagged
|
||||||
|
|
||||||
if(scene->graphType == LineGraphType::RailwaySegment && scene->graphObjectId == segmentId)
|
if (scene->graphType == LineGraphType::RailwaySegment && scene->graphObjectId == segmentId)
|
||||||
{
|
{
|
||||||
if(segName.isEmpty())
|
if (segName.isEmpty())
|
||||||
{
|
{
|
||||||
//Fetch new name and cache it
|
// Fetch new name and cache it
|
||||||
sqlite3pp::query q(scene->mDb, "SELECT name FROM railway_segments WHERE id=?");
|
sqlite3pp::query q(scene->mDb, "SELECT name FROM railway_segments WHERE id=?");
|
||||||
q.bind(1, segmentId);
|
q.bind(1, segmentId);
|
||||||
if(q.step() != SQLITE_ROW)
|
if (q.step() != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
qWarning() << "Graph: invalid segment ID" << segmentId;
|
qWarning() << "Graph: invalid segment ID" << segmentId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Store segment name
|
// Store segment name
|
||||||
segName = q.getRows().get<QString>(0);
|
segName = q.getRows().get<QString>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,16 +380,16 @@ void LineGraphManager::onSegmentStationsChanged(db_id segmentId)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||||
continue; //Already flagged
|
continue; // Already flagged
|
||||||
|
|
||||||
if(scene->graphType == LineGraphType::RailwayLine)
|
if (scene->graphType == LineGraphType::RailwayLine)
|
||||||
{
|
{
|
||||||
for(const auto& stPos : qAsConst(scene->stationPositions))
|
for (const auto &stPos : qAsConst(scene->stationPositions))
|
||||||
{
|
{
|
||||||
if(stPos.segmentId == segmentId)
|
if (stPos.segmentId == segmentId)
|
||||||
{
|
{
|
||||||
scene->pendingUpdate.setFlag(PendingUpdate::FullReload);
|
scene->pendingUpdate.setFlag(PendingUpdate::FullReload);
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -389,23 +397,24 @@ void LineGraphManager::onSegmentStationsChanged(db_id segmentId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(scene->graphType == LineGraphType::RailwaySegment && scene->graphObjectId == segmentId)
|
else if (scene->graphType == LineGraphType::RailwaySegment
|
||||||
|
&& scene->graphObjectId == segmentId)
|
||||||
{
|
{
|
||||||
scene->pendingUpdate.setFlag(PendingUpdate::FullReload);
|
scene->pendingUpdate.setFlag(PendingUpdate::FullReload);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(found)
|
if (found)
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::onSegmentRemoved(db_id segmentId)
|
void LineGraphManager::onSegmentRemoved(db_id segmentId)
|
||||||
{
|
{
|
||||||
//A segment can be removed only when is not on any line
|
// A segment can be removed only when is not on any line
|
||||||
//And when no jobs pass through it.
|
// And when no jobs pass through it.
|
||||||
//So there is no need to update other line scenes because no line will contain
|
// So there is no need to update other line scenes because no line will contain
|
||||||
//The removed segment
|
// The removed segment
|
||||||
clearGraphsOfObject(segmentId, LineGraphType::RailwaySegment);
|
clearGraphsOfObject(segmentId, LineGraphType::RailwaySegment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,25 +422,25 @@ void LineGraphManager::onLineNameChanged(db_id lineId)
|
||||||
{
|
{
|
||||||
QString lineName;
|
QString lineName;
|
||||||
|
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||||
continue; //Already flagged
|
continue; // Already flagged
|
||||||
|
|
||||||
if(scene->graphType == LineGraphType::RailwayLine && scene->graphObjectId == lineId)
|
if (scene->graphType == LineGraphType::RailwayLine && scene->graphObjectId == lineId)
|
||||||
{
|
{
|
||||||
if(lineName.isEmpty())
|
if (lineName.isEmpty())
|
||||||
{
|
{
|
||||||
//Fetch new name and cache it
|
// Fetch new name and cache it
|
||||||
sqlite3pp::query q(scene->mDb, "SELECT name FROM lines WHERE id=?");
|
sqlite3pp::query q(scene->mDb, "SELECT name FROM lines WHERE id=?");
|
||||||
q.bind(1, lineId);
|
q.bind(1, lineId);
|
||||||
if(q.step() != SQLITE_ROW)
|
if (q.step() != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
qWarning() << "Graph: invalid line ID" << lineId;
|
qWarning() << "Graph: invalid line ID" << lineId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Store line name
|
// Store line name
|
||||||
lineName = q.getRows().get<QString>(0);
|
lineName = q.getRows().get<QString>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,60 +454,61 @@ void LineGraphManager::onLineSegmentsChanged(db_id lineId)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||||
continue; //Already flagged
|
continue; // Already flagged
|
||||||
|
|
||||||
if(scene->graphType == LineGraphType::RailwayLine && scene->graphObjectId == lineId)
|
if (scene->graphType == LineGraphType::RailwayLine && scene->graphObjectId == lineId)
|
||||||
{
|
{
|
||||||
scene->pendingUpdate.setFlag(PendingUpdate::FullReload);
|
scene->pendingUpdate.setFlag(PendingUpdate::FullReload);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(found)
|
if (found)
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::onLineRemoved(db_id lineId)
|
void LineGraphManager::onLineRemoved(db_id lineId)
|
||||||
{
|
{
|
||||||
//Lines do not affect segments and stations
|
// Lines do not affect segments and stations
|
||||||
//So no other scene needs updating
|
// So no other scene needs updating
|
||||||
clearGraphsOfObject(lineId, LineGraphType::RailwayLine);
|
clearGraphsOfObject(lineId, LineGraphType::RailwayLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::onJobChanged(db_id jobId, db_id oldJobId)
|
void LineGraphManager::onJobChanged(db_id jobId, db_id oldJobId)
|
||||||
{
|
{
|
||||||
//If job changed ID or category, update selection on all scenes which had it selected
|
// If job changed ID or category, update selection on all scenes which had it selected
|
||||||
//There is no need to reload jobs because it is already done.
|
// There is no need to reload jobs because it is already done.
|
||||||
//In fact when a job changes ID, all station interested by this job get informed, and scenes reloaded
|
// In fact when a job changes ID, all station interested by this job get informed, and scenes
|
||||||
|
// reloaded
|
||||||
|
|
||||||
JobStopEntry selectedJob;
|
JobStopEntry selectedJob;
|
||||||
selectedJob.jobId = jobId;
|
selectedJob.jobId = jobId;
|
||||||
|
|
||||||
LineGraphScene::updateJobSelection(Session->m_Db, selectedJob);
|
LineGraphScene::updateJobSelection(Session->m_Db, selectedJob);
|
||||||
|
|
||||||
if(!selectedJob.jobId)
|
if (!selectedJob.jobId)
|
||||||
return; //Invalid job ID
|
return; // Invalid job ID
|
||||||
|
|
||||||
if(activeScene && AppSettings.getSyncSelectionOnAllGraphs())
|
if (activeScene && AppSettings.getSyncSelectionOnAllGraphs())
|
||||||
{
|
{
|
||||||
//Update active scene before others in case selection is synced
|
// Update active scene before others in case selection is synced
|
||||||
//This way all scenes get updated selection
|
// This way all scenes get updated selection
|
||||||
JobStopEntry oldSelectedJob = activeScene->getSelectedJob();
|
JobStopEntry oldSelectedJob = activeScene->getSelectedJob();
|
||||||
if(oldSelectedJob.jobId == oldJobId)
|
if (oldSelectedJob.jobId == oldJobId)
|
||||||
{
|
{
|
||||||
activeScene->setSelectedJob(selectedJob);
|
activeScene->setSelectedJob(selectedJob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Manually update all scenes
|
// Manually update all scenes
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
JobStopEntry oldSelectedJob = scene->getSelectedJob();
|
JobStopEntry oldSelectedJob = scene->getSelectedJob();
|
||||||
if(oldSelectedJob.jobId == oldJobId)
|
if (oldSelectedJob.jobId == oldJobId)
|
||||||
{
|
{
|
||||||
scene->setSelectedJob(selectedJob);
|
scene->setSelectedJob(selectedJob);
|
||||||
}
|
}
|
||||||
|
@ -508,64 +518,66 @@ void LineGraphManager::onJobChanged(db_id jobId, db_id oldJobId)
|
||||||
|
|
||||||
void LineGraphManager::onJobRemoved(db_id jobId)
|
void LineGraphManager::onJobRemoved(db_id jobId)
|
||||||
{
|
{
|
||||||
//We already catch normal job removal with other signals
|
// We already catch normal job removal with other signals
|
||||||
if(jobId)
|
if (jobId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//If jobId is zero, it means all jobs have been deleted
|
// If jobId is zero, it means all jobs have been deleted
|
||||||
//Reload all scenes
|
// Reload all scenes
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload)
|
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload)
|
||||||
|| scene->pendingUpdate.testFlag(PendingUpdate(PendingUpdate::ReloadJobs)))
|
|| scene->pendingUpdate.testFlag(PendingUpdate(PendingUpdate::ReloadJobs)))
|
||||||
continue; //Already flagged
|
continue; // Already flagged
|
||||||
|
|
||||||
scene->pendingUpdate.setFlag(PendingUpdate(PendingUpdate::ReloadJobs));
|
scene->pendingUpdate.setFlag(PendingUpdate(PendingUpdate::ReloadJobs));
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(found)
|
if (found)
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphManager::updateGraphOptions()
|
void LineGraphManager::updateGraphOptions()
|
||||||
{
|
{
|
||||||
//TODO: maybe get rid of theese variables in MeetingSession and always use AppSettings?
|
// TODO: maybe get rid of theese variables in MeetingSession and always use AppSettings?
|
||||||
int hourOffset = AppSettings.getHourOffset();
|
int hourOffset = AppSettings.getHourOffset();
|
||||||
Session->hourOffset = hourOffset;
|
Session->hourOffset = hourOffset;
|
||||||
|
|
||||||
int horizOffset = AppSettings.getHorizontalOffset();
|
int horizOffset = AppSettings.getHorizontalOffset();
|
||||||
Session->horizOffset = horizOffset;
|
Session->horizOffset = horizOffset;
|
||||||
|
|
||||||
int vertOffset = AppSettings.getVerticalOffset();
|
int vertOffset = AppSettings.getVerticalOffset();
|
||||||
Session->vertOffset = vertOffset;
|
Session->vertOffset = vertOffset;
|
||||||
|
|
||||||
Session->stationOffset = AppSettings.getStationOffset();
|
Session->stationOffset = AppSettings.getStationOffset();
|
||||||
Session->platformOffset = AppSettings.getPlatformOffset();
|
Session->platformOffset = AppSettings.getPlatformOffset();
|
||||||
|
|
||||||
Session->jobLineWidth = AppSettings.getJobLineWidth();
|
Session->jobLineWidth = AppSettings.getJobLineWidth();
|
||||||
|
|
||||||
//Reload all graphs
|
// Reload all graphs
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
scene->reload();
|
scene->reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool oldVal = m_followJobOnGraphChange;
|
const bool oldVal = m_followJobOnGraphChange;
|
||||||
m_followJobOnGraphChange = AppSettings.getFollowSelectionOnGraphChange();
|
m_followJobOnGraphChange = AppSettings.getFollowSelectionOnGraphChange();
|
||||||
|
|
||||||
if(m_followJobOnGraphChange != oldVal)
|
if (m_followJobOnGraphChange != oldVal)
|
||||||
{
|
{
|
||||||
//Update connections
|
// Update connections
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(m_followJobOnGraphChange)
|
if (m_followJobOnGraphChange)
|
||||||
connect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
connect(scene, &LineGraphScene::graphChanged, this,
|
||||||
|
&LineGraphManager::onGraphChanged);
|
||||||
else
|
else
|
||||||
disconnect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
disconnect(scene, &LineGraphScene::graphChanged, this,
|
||||||
|
&LineGraphManager::onGraphChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -574,15 +586,15 @@ void LineGraphManager::onStationPlanChanged_internal(const QSet<db_id> &stationI
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for(LineGraphScene *scene : qAsConst(scenes))
|
for (LineGraphScene *scene : qAsConst(scenes))
|
||||||
{
|
{
|
||||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload)
|
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload)
|
||||||
|| scene->pendingUpdate.testFlag(PendingUpdate(flag)))
|
|| scene->pendingUpdate.testFlag(PendingUpdate(flag)))
|
||||||
continue; //Already flagged
|
continue; // Already flagged
|
||||||
|
|
||||||
for(db_id stationId : stationIds)
|
for (db_id stationId : stationIds)
|
||||||
{
|
{
|
||||||
if(scene->stations.contains(stationId))
|
if (scene->stations.contains(stationId))
|
||||||
{
|
{
|
||||||
scene->pendingUpdate.setFlag(PendingUpdate(flag));
|
scene->pendingUpdate.setFlag(PendingUpdate(flag));
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -591,6 +603,6 @@ void LineGraphManager::onStationPlanChanged_internal(const QSet<db_id> &stationI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(found)
|
if (found)
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,10 @@ public:
|
||||||
* \brief get active scene
|
* \brief get active scene
|
||||||
* \return Scene instance or nullptr if no scene is active
|
* \return Scene instance or nullptr if no scene is active
|
||||||
*/
|
*/
|
||||||
inline LineGraphScene *getActiveScene() const { return activeScene; }
|
inline LineGraphScene *getActiveScene() const
|
||||||
|
{
|
||||||
|
return activeScene;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief get current selected job
|
* \brief get current selected job
|
||||||
|
@ -151,32 +154,32 @@ public slots:
|
||||||
void setActiveScene(IGraphScene *scene);
|
void setActiveScene(IGraphScene *scene);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
//Scenes
|
// Scenes
|
||||||
void onSceneDestroyed(QObject *obj);
|
void onSceneDestroyed(QObject *obj);
|
||||||
void onGraphChanged(int graphType_, db_id graphObjId, LineGraphScene *scene);
|
void onGraphChanged(int graphType_, db_id graphObjId, LineGraphScene *scene);
|
||||||
void onJobSelected(db_id jobId, int category, db_id stopId);
|
void onJobSelected(db_id jobId, int category, db_id stopId);
|
||||||
|
|
||||||
//Stations
|
// Stations
|
||||||
void onStationNameChanged(db_id stationId);
|
void onStationNameChanged(db_id stationId);
|
||||||
void onStationJobPlanChanged(const QSet<db_id> &stationIds);
|
void onStationJobPlanChanged(const QSet<db_id> &stationIds);
|
||||||
void onStationTrackPlanChanged(const QSet<db_id> &stationIds);
|
void onStationTrackPlanChanged(const QSet<db_id> &stationIds);
|
||||||
void onStationRemoved(db_id stationId);
|
void onStationRemoved(db_id stationId);
|
||||||
|
|
||||||
//Segments
|
// Segments
|
||||||
void onSegmentNameChanged(db_id segmentId);
|
void onSegmentNameChanged(db_id segmentId);
|
||||||
void onSegmentStationsChanged(db_id segmentId);
|
void onSegmentStationsChanged(db_id segmentId);
|
||||||
void onSegmentRemoved(db_id segmentId);
|
void onSegmentRemoved(db_id segmentId);
|
||||||
|
|
||||||
//Lines
|
// Lines
|
||||||
void onLineNameChanged(db_id lineId);
|
void onLineNameChanged(db_id lineId);
|
||||||
void onLineSegmentsChanged(db_id lineId);
|
void onLineSegmentsChanged(db_id lineId);
|
||||||
void onLineRemoved(db_id lineId);
|
void onLineRemoved(db_id lineId);
|
||||||
|
|
||||||
//Jobs
|
// Jobs
|
||||||
void onJobChanged(db_id jobId, db_id oldJobId);
|
void onJobChanged(db_id jobId, db_id oldJobId);
|
||||||
void onJobRemoved(db_id jobId);
|
void onJobRemoved(db_id jobId);
|
||||||
|
|
||||||
//Settings
|
// Settings
|
||||||
void updateGraphOptions();
|
void updateGraphOptions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -57,18 +57,18 @@ public:
|
||||||
*/
|
*/
|
||||||
enum class PendingUpdate
|
enum class PendingUpdate
|
||||||
{
|
{
|
||||||
NothingToDo = 0x0, //!< No content needs updating
|
NothingToDo = 0x0, //!< No content needs updating
|
||||||
ReloadJobs = 0x1, //!< Only Jobs need to be reloaded
|
ReloadJobs = 0x1, //!< Only Jobs need to be reloaded
|
||||||
ReloadStationNames = 0x2, //!< Only Station Names but not Station Plan has changed
|
ReloadStationNames = 0x2, //!< Only Station Names but not Station Plan has changed
|
||||||
FullReload = 0x4 //!< Do a full reload
|
FullReload = 0x4 //!< Do a full reload
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(PendingUpdateFlags, PendingUpdate)
|
Q_DECLARE_FLAGS(PendingUpdateFlags, PendingUpdate)
|
||||||
|
|
||||||
LineGraphScene(sqlite3pp::database &db, QObject *parent = nullptr);
|
LineGraphScene(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||||
|
|
||||||
void renderContents(QPainter *painter, const QRectF& sceneRect) override;
|
void renderContents(QPainter *painter, const QRectF &sceneRect) override;
|
||||||
void renderHeader(QPainter *painter, const QRectF& sceneRect,
|
void renderHeader(QPainter *painter, const QRectF &sceneRect, Qt::Orientation orient,
|
||||||
Qt::Orientation orient, double scroll) override;
|
double scroll) override;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Load graph contents
|
* \brief Load graph contents
|
||||||
|
@ -109,7 +109,7 @@ public:
|
||||||
* \param pos Point in scene coordinates
|
* \param pos Point in scene coordinates
|
||||||
* \param tolerance A tolerance if mouse doesn't exactly click on job item
|
* \param tolerance A tolerance if mouse doesn't exactly click on job item
|
||||||
*/
|
*/
|
||||||
JobStopEntry getJobAt(const QPointF& pos, const double tolerance);
|
JobStopEntry getJobAt(const QPointF &pos, const double tolerance);
|
||||||
|
|
||||||
inline LineGraphType getGraphType() const
|
inline LineGraphType getGraphType() const
|
||||||
{
|
{
|
||||||
|
@ -154,7 +154,10 @@ public:
|
||||||
*
|
*
|
||||||
* \sa setDrawSelection()
|
* \sa setDrawSelection()
|
||||||
*/
|
*/
|
||||||
inline bool getDrawSelection() { return m_drawSelection; }
|
inline bool getDrawSelection()
|
||||||
|
{
|
||||||
|
return m_drawSelection;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief setDrawSelection
|
* \brief setDrawSelection
|
||||||
|
@ -165,7 +168,10 @@ public:
|
||||||
*
|
*
|
||||||
* \sa getDrawSelection()
|
* \sa getDrawSelection()
|
||||||
*/
|
*/
|
||||||
inline void setDrawSelection(bool val) { m_drawSelection = val; }
|
inline void setDrawSelection(bool val)
|
||||||
|
{
|
||||||
|
m_drawSelection = val;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief requestShowZone
|
* \brief requestShowZone
|
||||||
|
@ -208,7 +214,6 @@ public slots:
|
||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Graph of the job while is moving
|
* \brief Graph of the job while is moving
|
||||||
*
|
*
|
||||||
|
@ -308,7 +313,8 @@ private:
|
||||||
* Load job segments and stores them in 'from' station
|
* Load job segments and stores them in 'from' station
|
||||||
* \sa loadStationJobStops()
|
* \sa loadStationJobStops()
|
||||||
*/
|
*/
|
||||||
bool loadSegmentJobs(StationPosEntry &stPos, const StationGraphObject &fromSt, const StationGraphObject &toSt);
|
bool loadSegmentJobs(StationPosEntry &stPos, const StationGraphObject &fromSt,
|
||||||
|
const StationGraphObject &toSt);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Update job selection category
|
* \brief Update job selection category
|
||||||
|
@ -324,7 +330,7 @@ private:
|
||||||
friend class BackgroundHelper;
|
friend class BackgroundHelper;
|
||||||
friend class LineGraphManager;
|
friend class LineGraphManager;
|
||||||
|
|
||||||
sqlite3pp::database& mDb;
|
sqlite3pp::database &mDb;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Graph Object ID
|
* \brief Graph Object ID
|
||||||
|
|
|
@ -27,10 +27,10 @@ using namespace sqlite3pp;
|
||||||
LineGraphSelectionHelper::LineGraphSelectionHelper(sqlite3pp::database &db) :
|
LineGraphSelectionHelper::LineGraphSelectionHelper(sqlite3pp::database &db) :
|
||||||
mDb(db)
|
mDb(db)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphSelectionHelper::tryFindJobStopInGraph(LineGraphScene *scene, db_id jobId, SegmentInfo &info)
|
bool LineGraphSelectionHelper::tryFindJobStopInGraph(LineGraphScene *scene, db_id jobId,
|
||||||
|
SegmentInfo &info)
|
||||||
{
|
{
|
||||||
query q(mDb);
|
query q(mDb);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ bool LineGraphSelectionHelper::tryFindJobStopInGraph(LineGraphScene *scene, db_i
|
||||||
case LineGraphType::NoGraph:
|
case LineGraphType::NoGraph:
|
||||||
case LineGraphType::NTypes:
|
case LineGraphType::NTypes:
|
||||||
{
|
{
|
||||||
//We need to load a new graph, give up
|
// We need to load a new graph, give up
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,18 +80,18 @@ bool LineGraphSelectionHelper::tryFindJobStopInGraph(LineGraphScene *scene, db_i
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
q.bind(2, scene->getGraphObjectId());
|
q.bind(2, scene->getGraphObjectId());
|
||||||
|
|
||||||
if(q.step() != SQLITE_ROW || q.getRows().column_type(0) == SQLITE_NULL)
|
if (q.step() != SQLITE_ROW || q.getRows().column_type(0) == SQLITE_NULL)
|
||||||
return false; //We didn't find a stop in current graph, give up
|
return false; // We didn't find a stop in current graph, give up
|
||||||
|
|
||||||
//Get stop info
|
// Get stop info
|
||||||
auto stop = q.getRows();
|
auto stop = q.getRows();
|
||||||
info.firstStopId = stop.get<db_id>(0);
|
info.firstStopId = stop.get<db_id>(0);
|
||||||
info.segmentId = stop.get<db_id>(1);
|
info.segmentId = stop.get<db_id>(1);
|
||||||
info.arrivalAndStart = stop.get<QTime>(2);
|
info.arrivalAndStart = stop.get<QTime>(2);
|
||||||
info.departure = stop.get<QTime>(3);
|
info.departure = stop.get<QTime>(3);
|
||||||
|
|
||||||
//If graph is SingleStation we already know the station ID
|
// If graph is SingleStation we already know the station ID
|
||||||
if(scene->getGraphType() == LineGraphType::SingleStation)
|
if (scene->getGraphType() == LineGraphType::SingleStation)
|
||||||
info.firstStationId = scene->getGraphObjectId();
|
info.firstStationId = scene->getGraphObjectId();
|
||||||
else
|
else
|
||||||
info.firstStationId = stop.get<db_id>(4);
|
info.firstStationId = stop.get<db_id>(4);
|
||||||
|
@ -99,96 +99,98 @@ bool LineGraphSelectionHelper::tryFindJobStopInGraph(LineGraphScene *scene, db_i
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphSelectionHelper::tryFindJobStopsAfter(db_id jobId, SegmentInfo& info)
|
bool LineGraphSelectionHelper::tryFindJobStopsAfter(db_id jobId, SegmentInfo &info)
|
||||||
{
|
{
|
||||||
query q(mDb, "SELECT stops.id, MIN(stops.arrival), stops.departure, stops.station_id, c.seg_id"
|
query q(mDb, "SELECT stops.id, MIN(stops.arrival), stops.departure, stops.station_id, c.seg_id"
|
||||||
" FROM stops"
|
" FROM stops"
|
||||||
" LEFT JOIN railway_connections c ON c.id=stops.next_segment_conn_id"
|
" LEFT JOIN railway_connections c ON c.id=stops.next_segment_conn_id"
|
||||||
" WHERE stops.job_id=? AND stops.arrival>=?");
|
" WHERE stops.job_id=? AND stops.arrival>=?");
|
||||||
|
|
||||||
//Find first job stop after or equal to startTime
|
// Find first job stop after or equal to startTime
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
q.bind(2, info.arrivalAndStart);
|
q.bind(2, info.arrivalAndStart);
|
||||||
if(q.step() != SQLITE_ROW || q.getRows().column_type(0) == SQLITE_NULL)
|
if (q.step() != SQLITE_ROW || q.getRows().column_type(0) == SQLITE_NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//Get first stop info
|
// Get first stop info
|
||||||
auto stop = q.getRows();
|
auto stop = q.getRows();
|
||||||
info.firstStopId = stop.get<db_id>(0);
|
info.firstStopId = stop.get<db_id>(0);
|
||||||
info.arrivalAndStart = stop.get<QTime>(1);
|
info.arrivalAndStart = stop.get<QTime>(1);
|
||||||
info.departure = stop.get<QTime>(2);
|
info.departure = stop.get<QTime>(2);
|
||||||
info.firstStationId = stop.get<db_id>(3);
|
info.firstStationId = stop.get<db_id>(3);
|
||||||
info.segmentId = stop.get<db_id>(4);
|
info.segmentId = stop.get<db_id>(4);
|
||||||
q.reset();
|
q.reset();
|
||||||
|
|
||||||
//Try get a second stop after the first departure
|
// Try get a second stop after the first departure
|
||||||
//NOTE: minimum 60 seconds of travel between 2 consecutive stops
|
// NOTE: minimum 60 seconds of travel between 2 consecutive stops
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
q.bind(2, info.departure.addSecs(60));
|
q.bind(2, info.departure.addSecs(60));
|
||||||
if(q.step() != SQLITE_ROW)
|
if (q.step() != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
//We found only 1 stop, return that
|
// We found only 1 stop, return that
|
||||||
info.secondStationId = 0;
|
info.secondStationId = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get first stop info
|
// Get first stop info
|
||||||
stop = q.getRows();
|
stop = q.getRows();
|
||||||
//db_id secondStopId = stop.get<db_id>(0);
|
// db_id secondStopId = stop.get<db_id>(0);
|
||||||
//QTime secondArrival = stop.get<QTime>(1);
|
// QTime secondArrival = stop.get<QTime>(1);
|
||||||
info.departure = stop.get<QTime>(2); //Overwrite departure
|
info.departure = stop.get<QTime>(2); // Overwrite departure
|
||||||
info.secondStationId = stop.get<db_id>(3);
|
info.secondStationId = stop.get<db_id>(3);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphSelectionHelper::tryFindNewGraphForJob(db_id jobId, SegmentInfo& info,
|
bool LineGraphSelectionHelper::tryFindNewGraphForJob(db_id jobId, SegmentInfo &info,
|
||||||
db_id &outGraphObjId, LineGraphType &outGraphType)
|
db_id &outGraphObjId,
|
||||||
|
LineGraphType &outGraphType)
|
||||||
{
|
{
|
||||||
if(!tryFindJobStopsAfter(jobId, info))
|
if (!tryFindJobStopsAfter(jobId, info))
|
||||||
return false; //No stops found
|
return false; // No stops found
|
||||||
|
|
||||||
if(!info.secondStationId || !info.segmentId)
|
if (!info.secondStationId || !info.segmentId)
|
||||||
{
|
{
|
||||||
//We found only 1 stop, select first station
|
// We found only 1 stop, select first station
|
||||||
outGraphObjId = info.firstStationId;
|
outGraphObjId = info.firstStationId;
|
||||||
outGraphType = LineGraphType::SingleStation;
|
outGraphType = LineGraphType::SingleStation;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Try to find a railway line which contains this segment
|
// Try to find a railway line which contains this segment
|
||||||
//FIXME: better criteria to choose a line (name?, number of segments?, prompt user?)
|
// FIXME: better criteria to choose a line (name?, number of segments?, prompt user?)
|
||||||
query q(mDb, "SELECT ls.line_id"
|
query q(mDb, "SELECT ls.line_id"
|
||||||
" FROM line_segments ls"
|
" FROM line_segments ls"
|
||||||
" WHERE ls.seg_id=?");
|
" WHERE ls.seg_id=?");
|
||||||
q.bind(1, info.segmentId);
|
q.bind(1, info.segmentId);
|
||||||
|
|
||||||
if(q.step() == SQLITE_ROW)
|
if (q.step() == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
//Found a line
|
// Found a line
|
||||||
outGraphObjId = q.getRows().get<db_id>(0);
|
outGraphObjId = q.getRows().get<db_id>(0);
|
||||||
outGraphType = LineGraphType::RailwayLine;
|
outGraphType = LineGraphType::RailwayLine;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//No lines found, use the railway segment
|
// No lines found, use the railway segment
|
||||||
outGraphObjId = info.segmentId;
|
outGraphObjId = info.segmentId;
|
||||||
outGraphType = LineGraphType::RailwaySegment;
|
outGraphType = LineGraphType::RailwaySegment;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphSelectionHelper::requestJobSelection(LineGraphScene *scene, db_id jobId, bool select, bool ensureVisible)
|
bool LineGraphSelectionHelper::requestJobSelection(LineGraphScene *scene, db_id jobId, bool select,
|
||||||
|
bool ensureVisible)
|
||||||
{
|
{
|
||||||
//Check jobId is valid and get category
|
// Check jobId is valid and get category
|
||||||
|
|
||||||
query q(mDb, "SELECT category FROM jobs WHERE id=?");
|
query q(mDb, "SELECT category FROM jobs WHERE id=?");
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
if(q.step() != SQLITE_ROW)
|
if (q.step() != SQLITE_ROW)
|
||||||
return false; //Job doen't exist
|
return false; // Job doen't exist
|
||||||
|
|
||||||
JobStopEntry selectedJob;
|
JobStopEntry selectedJob;
|
||||||
selectedJob.jobId = jobId;
|
selectedJob.jobId = jobId;
|
||||||
selectedJob.category = JobCategory(q.getRows().get<int>(0));
|
selectedJob.category = JobCategory(q.getRows().get<int>(0));
|
||||||
|
|
||||||
SegmentInfo info;
|
SegmentInfo info;
|
||||||
|
@ -196,65 +198,66 @@ bool LineGraphSelectionHelper::requestJobSelection(LineGraphScene *scene, db_id
|
||||||
// Try to select earliest stop of this job in current graph, if any
|
// Try to select earliest stop of this job in current graph, if any
|
||||||
const bool found = tryFindJobStopInGraph(scene, selectedJob.jobId, info);
|
const bool found = tryFindJobStopInGraph(scene, selectedJob.jobId, info);
|
||||||
|
|
||||||
if(!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
//Find a NEW line graph or segment or station with this job
|
// Find a NEW line graph or segment or station with this job
|
||||||
|
|
||||||
//Find first 2 stops of the job
|
// Find first 2 stops of the job
|
||||||
|
|
||||||
db_id graphObjId = 0;
|
db_id graphObjId = 0;
|
||||||
LineGraphType graphType = LineGraphType::NoGraph;
|
LineGraphType graphType = LineGraphType::NoGraph;
|
||||||
|
|
||||||
if(!tryFindNewGraphForJob(selectedJob.jobId, info, graphObjId, graphType))
|
if (!tryFindNewGraphForJob(selectedJob.jobId, info, graphObjId, graphType))
|
||||||
{
|
{
|
||||||
//Could not find a suitable graph, abort
|
// Could not find a suitable graph, abort
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
// NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||||
//do not emit change because selection might be synced between all scenes
|
// do not emit change because selection might be synced between all scenes
|
||||||
//and because it's restored soon after
|
// and because it's restored soon after
|
||||||
const JobStopEntry oldSelection = scene->getSelectedJob();
|
const JobStopEntry oldSelection = scene->getSelectedJob();
|
||||||
scene->setSelectedJob(JobStopEntry{}, false); //Clear selection
|
scene->setSelectedJob(JobStopEntry{}, false); // Clear selection
|
||||||
|
|
||||||
//Select the graph
|
// Select the graph
|
||||||
scene->loadGraph(graphObjId, graphType);
|
scene->loadGraph(graphObjId, graphType);
|
||||||
|
|
||||||
//Restore previous selection
|
// Restore previous selection
|
||||||
scene->setSelectedJob(oldSelection, false);
|
scene->setSelectedJob(oldSelection, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Extract the info
|
// Extract the info
|
||||||
selectedJob.stopId = info.firstStopId;
|
selectedJob.stopId = info.firstStopId;
|
||||||
|
|
||||||
if(!selectedJob.stopId)
|
if (!selectedJob.stopId)
|
||||||
return false; //No stop found, abort
|
return false; // No stop found, abort
|
||||||
|
|
||||||
//Select job
|
// Select job
|
||||||
if(select)
|
if (select)
|
||||||
scene->setSelectedJob(selectedJob);
|
scene->setSelectedJob(selectedJob);
|
||||||
|
|
||||||
if(ensureVisible)
|
if (ensureVisible)
|
||||||
{
|
{
|
||||||
return scene->requestShowZone(info.firstStationId, info.segmentId,
|
return scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart,
|
||||||
info.arrivalAndStart, info.departure);
|
info.departure);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphSelectionHelper::requestCurrentJobPrevSegmentVisible(LineGraphScene *scene, bool goToStart)
|
bool LineGraphSelectionHelper::requestCurrentJobPrevSegmentVisible(LineGraphScene *scene,
|
||||||
|
bool goToStart)
|
||||||
{
|
{
|
||||||
JobStopEntry selectedJob = scene->getSelectedJob();
|
JobStopEntry selectedJob = scene->getSelectedJob();
|
||||||
if(!selectedJob.jobId)
|
if (!selectedJob.jobId)
|
||||||
return false; //No job selected, nothing to do
|
return false; // No job selected, nothing to do
|
||||||
|
|
||||||
query q(mDb);
|
query q(mDb);
|
||||||
|
|
||||||
SegmentInfo info;
|
SegmentInfo info;
|
||||||
if(selectedJob.stopId && !goToStart)
|
if (selectedJob.stopId && !goToStart)
|
||||||
{
|
{
|
||||||
//Start from current stop and get previous stop
|
// Start from current stop and get previous stop
|
||||||
q.prepare("SELECT s2.job_id, s1.id, MAX(s1.arrival), s1.station_id, c.seg_id,"
|
q.prepare("SELECT s2.job_id, s1.id, MAX(s1.arrival), s1.station_id, c.seg_id,"
|
||||||
"s2.departure, s2.station_id"
|
"s2.departure, s2.station_id"
|
||||||
" FROM stops s2"
|
" FROM stops s2"
|
||||||
|
@ -263,71 +266,72 @@ bool LineGraphSelectionHelper::requestCurrentJobPrevSegmentVisible(LineGraphScen
|
||||||
" WHERE s2.id=? AND s1.arrival < s2.arrival");
|
" WHERE s2.id=? AND s1.arrival < s2.arrival");
|
||||||
q.bind(1, selectedJob.stopId);
|
q.bind(1, selectedJob.stopId);
|
||||||
|
|
||||||
if(q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
if (q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
auto stop = q.getRows();
|
auto stop = q.getRows();
|
||||||
db_id jobId = stop.get<db_id>(0);
|
db_id jobId = stop.get<db_id>(0);
|
||||||
if(jobId == selectedJob.jobId)
|
if (jobId == selectedJob.jobId)
|
||||||
{
|
{
|
||||||
//Found stop and belongs to requested job
|
// Found stop and belongs to requested job
|
||||||
info.firstStopId = stop.get<db_id>(1);
|
info.firstStopId = stop.get<db_id>(1);
|
||||||
info.arrivalAndStart = stop.get<QTime>(2);
|
info.arrivalAndStart = stop.get<QTime>(2);
|
||||||
info.firstStationId = stop.get<db_id>(3);
|
info.firstStationId = stop.get<db_id>(3);
|
||||||
info.segmentId = stop.get<db_id>(4);
|
info.segmentId = stop.get<db_id>(4);
|
||||||
info.departure = stop.get<QTime>(5);
|
info.departure = stop.get<QTime>(5);
|
||||||
info.secondStationId = stop.get<db_id>(6);
|
info.secondStationId = stop.get<db_id>(6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!info.firstStopId)
|
if (!info.firstStopId)
|
||||||
{
|
{
|
||||||
//goToStart or failed to get previous stop so go to start anyway
|
// goToStart or failed to get previous stop so go to start anyway
|
||||||
|
|
||||||
if(!tryFindJobStopsAfter(selectedJob.jobId, info))
|
if (!tryFindJobStopsAfter(selectedJob.jobId, info))
|
||||||
return false; //No stops found, give up
|
return false; // No stops found, give up
|
||||||
}
|
}
|
||||||
|
|
||||||
db_id graphObjId = 0;
|
db_id graphObjId = 0;
|
||||||
LineGraphType graphType = LineGraphType::NoGraph;
|
LineGraphType graphType = LineGraphType::NoGraph;
|
||||||
|
|
||||||
if(!tryFindNewGraphForJob(selectedJob.jobId, info, graphObjId, graphType))
|
if (!tryFindNewGraphForJob(selectedJob.jobId, info, graphObjId, graphType))
|
||||||
{
|
{
|
||||||
//Could not find a suitable graph, abort
|
// Could not find a suitable graph, abort
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
// NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||||
//do not emit change because selection might be synced between all scenes
|
// do not emit change because selection might be synced between all scenes
|
||||||
//and because it's restored soon after
|
// and because it's restored soon after
|
||||||
scene->setSelectedJob(JobStopEntry{}, false); //Clear selection
|
scene->setSelectedJob(JobStopEntry{}, false); // Clear selection
|
||||||
|
|
||||||
//Select the graph
|
// Select the graph
|
||||||
scene->loadGraph(graphObjId, graphType);
|
scene->loadGraph(graphObjId, graphType);
|
||||||
|
|
||||||
//Restore selection
|
// Restore selection
|
||||||
selectedJob.stopId = info.firstStopId;
|
selectedJob.stopId = info.firstStopId;
|
||||||
scene->setSelectedJob(selectedJob); //This time emit
|
scene->setSelectedJob(selectedJob); // This time emit
|
||||||
|
|
||||||
return scene->requestShowZone(info.firstStationId, info.segmentId,
|
return scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart,
|
||||||
info.arrivalAndStart, info.departure);
|
info.departure);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphSelectionHelper::requestCurrentJobNextSegmentVisible(LineGraphScene *scene, bool goToEnd)
|
bool LineGraphSelectionHelper::requestCurrentJobNextSegmentVisible(LineGraphScene *scene,
|
||||||
|
bool goToEnd)
|
||||||
{
|
{
|
||||||
//TODO: maybe go to first segment AFTER last segment in current view.
|
// TODO: maybe go to first segment AFTER last segment in current view.
|
||||||
//So it may not be 'next' but maybe 2 or 3 segments after current.
|
// So it may not be 'next' but maybe 2 or 3 segments after current.
|
||||||
|
|
||||||
JobStopEntry selectedJob = scene->getSelectedJob();
|
JobStopEntry selectedJob = scene->getSelectedJob();
|
||||||
if(!selectedJob.jobId)
|
if (!selectedJob.jobId)
|
||||||
return false; //No job selected, nothing to do
|
return false; // No job selected, nothing to do
|
||||||
|
|
||||||
query q(mDb);
|
query q(mDb);
|
||||||
|
|
||||||
SegmentInfo info;
|
SegmentInfo info;
|
||||||
if(selectedJob.stopId && !goToEnd)
|
if (selectedJob.stopId && !goToEnd)
|
||||||
{
|
{
|
||||||
//Start from current stop and get next stop
|
// Start from current stop and get next stop
|
||||||
q.prepare("SELECT s2.job_id, s1.id, MIN(s1.arrival), s1.departure, s1.station_id, c.seg_id"
|
q.prepare("SELECT s2.job_id, s1.id, MIN(s1.arrival), s1.departure, s1.station_id, c.seg_id"
|
||||||
" FROM stops s2"
|
" FROM stops s2"
|
||||||
" JOIN stops s1 ON s1.job_id=s2.job_id"
|
" JOIN stops s1 ON s1.job_id=s2.job_id"
|
||||||
|
@ -335,64 +339,64 @@ bool LineGraphSelectionHelper::requestCurrentJobNextSegmentVisible(LineGraphScen
|
||||||
" WHERE s2.id=? AND s1.arrival > s2.arrival");
|
" WHERE s2.id=? AND s1.arrival > s2.arrival");
|
||||||
q.bind(1, selectedJob.stopId);
|
q.bind(1, selectedJob.stopId);
|
||||||
|
|
||||||
if(q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
if (q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
auto stop = q.getRows();
|
auto stop = q.getRows();
|
||||||
db_id jobId = stop.get<db_id>(0);
|
db_id jobId = stop.get<db_id>(0);
|
||||||
if(jobId == selectedJob.jobId)
|
if (jobId == selectedJob.jobId)
|
||||||
{
|
{
|
||||||
//Found stop and belongs to requested job
|
// Found stop and belongs to requested job
|
||||||
info.firstStopId = stop.get<db_id>(1);
|
info.firstStopId = stop.get<db_id>(1);
|
||||||
info.arrivalAndStart = stop.get<QTime>(2);
|
info.arrivalAndStart = stop.get<QTime>(2);
|
||||||
info.departure = stop.get<QTime>(3);
|
info.departure = stop.get<QTime>(3);
|
||||||
info.firstStationId = stop.get<db_id>(4);
|
info.firstStationId = stop.get<db_id>(4);
|
||||||
info.segmentId = stop.get<db_id>(5);
|
info.segmentId = stop.get<db_id>(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!info.firstStopId)
|
if (!info.firstStopId)
|
||||||
{
|
{
|
||||||
//goToEnd or failed to get next stop so go to end anyway
|
// goToEnd or failed to get next stop so go to end anyway
|
||||||
|
|
||||||
//Select last station, no segment
|
// Select last station, no segment
|
||||||
q.prepare("SELECT s1.id, MAX(s1.arrival), s1.departure, s1.station_id"
|
q.prepare("SELECT s1.id, MAX(s1.arrival), s1.departure, s1.station_id"
|
||||||
" FROM stops s1"
|
" FROM stops s1"
|
||||||
" WHERE s1.job_id=?");
|
" WHERE s1.job_id=?");
|
||||||
q.bind(1, selectedJob.jobId);
|
q.bind(1, selectedJob.jobId);
|
||||||
|
|
||||||
if(q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
if (q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
//Found stop and belongs to requested job
|
// Found stop and belongs to requested job
|
||||||
auto stop = q.getRows();
|
auto stop = q.getRows();
|
||||||
info.firstStopId = stop.get<db_id>(0);
|
info.firstStopId = stop.get<db_id>(0);
|
||||||
info.arrivalAndStart = stop.get<QTime>(1);
|
info.arrivalAndStart = stop.get<QTime>(1);
|
||||||
info.departure = stop.get<QTime>(2);
|
info.departure = stop.get<QTime>(2);
|
||||||
info.firstStationId = stop.get<db_id>(3);
|
info.firstStationId = stop.get<db_id>(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db_id graphObjId = 0;
|
db_id graphObjId = 0;
|
||||||
LineGraphType graphType = LineGraphType::NoGraph;
|
LineGraphType graphType = LineGraphType::NoGraph;
|
||||||
|
|
||||||
if(!tryFindNewGraphForJob(selectedJob.jobId, info, graphObjId, graphType))
|
if (!tryFindNewGraphForJob(selectedJob.jobId, info, graphObjId, graphType))
|
||||||
{
|
{
|
||||||
//Could not find a suitable graph, abort
|
// Could not find a suitable graph, abort
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
// NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||||
//do not emit change because selection might be synced between all scenes
|
// do not emit change because selection might be synced between all scenes
|
||||||
//and because it's restored soon after
|
// and because it's restored soon after
|
||||||
scene->setSelectedJob(JobStopEntry{}, false); //Clear selection
|
scene->setSelectedJob(JobStopEntry{}, false); // Clear selection
|
||||||
|
|
||||||
//Select the graph
|
// Select the graph
|
||||||
scene->loadGraph(graphObjId, graphType);
|
scene->loadGraph(graphObjId, graphType);
|
||||||
|
|
||||||
//Restore selection
|
// Restore selection
|
||||||
selectedJob.stopId = info.firstStopId;
|
selectedJob.stopId = info.firstStopId;
|
||||||
scene->setSelectedJob(selectedJob); //This time emit
|
scene->setSelectedJob(selectedJob); // This time emit
|
||||||
|
|
||||||
return scene->requestShowZone(info.firstStationId, info.segmentId,
|
return scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart,
|
||||||
info.arrivalAndStart, info.departure);
|
info.departure);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,16 +33,15 @@ class database;
|
||||||
class LineGraphSelectionHelper
|
class LineGraphSelectionHelper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The SegmentInfo struct
|
* \brief The SegmentInfo struct
|
||||||
*/
|
*/
|
||||||
struct SegmentInfo
|
struct SegmentInfo
|
||||||
{
|
{
|
||||||
db_id segmentId = 0;
|
db_id segmentId = 0;
|
||||||
db_id firstStationId = 0;
|
db_id firstStationId = 0;
|
||||||
db_id secondStationId = 0;
|
db_id secondStationId = 0;
|
||||||
db_id firstStopId = 0;
|
db_id firstStopId = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief arrival and start
|
* \brief arrival and start
|
||||||
|
@ -56,7 +55,7 @@ public:
|
||||||
|
|
||||||
LineGraphSelectionHelper(sqlite3pp::database &db);
|
LineGraphSelectionHelper(sqlite3pp::database &db);
|
||||||
|
|
||||||
//Low level API
|
// Low level API
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief find job in current graph
|
* \brief find job in current graph
|
||||||
|
@ -69,7 +68,7 @@ public:
|
||||||
* If scene has NoGraph or does not contain requested job then returns false
|
* If scene has NoGraph or does not contain requested job then returns false
|
||||||
* SegmentInfo::secondStId is always left empty
|
* SegmentInfo::secondStId is always left empty
|
||||||
*/
|
*/
|
||||||
bool tryFindJobStopInGraph(LineGraphScene *scene, db_id jobId, SegmentInfo& info);
|
bool tryFindJobStopInGraph(LineGraphScene *scene, db_id jobId, SegmentInfo &info);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief find 2 job stops after requested hour
|
* \brief find 2 job stops after requested hour
|
||||||
|
@ -93,10 +92,11 @@ public:
|
||||||
* Try to find a railway line containing the job. If not found try with a railway segment.
|
* Try to find a railway line containing the job. If not found try with a railway segment.
|
||||||
* If neither line nor segment are found try with first stop station.
|
* If neither line nor segment are found try with first stop station.
|
||||||
*/
|
*/
|
||||||
bool tryFindNewGraphForJob(db_id jobId, SegmentInfo &info, db_id &outGraphObjId, LineGraphType &outGraphType);
|
bool tryFindNewGraphForJob(db_id jobId, SegmentInfo &info, db_id &outGraphObjId,
|
||||||
|
LineGraphType &outGraphType);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//High level API
|
// High level API
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief request job selection
|
* \brief request job selection
|
||||||
|
|
|
@ -21,5 +21,4 @@
|
||||||
|
|
||||||
StationGraphObject::StationGraphObject()
|
StationGraphObject::StationGraphObject()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include "app/session.h"
|
#include "app/session.h"
|
||||||
|
|
||||||
#include "graph/model/linegraphscene.h"
|
#include "graph/model/linegraphscene.h"
|
||||||
#include "utils/jobcategorystrings.h"
|
#include "utils/jobcategorystrings.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
@ -31,9 +31,9 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF& rect)
|
void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF &rect)
|
||||||
{
|
{
|
||||||
//TODO: settings
|
// TODO: settings
|
||||||
QFont hourTextFont;
|
QFont hourTextFont;
|
||||||
setFontPointSizeDPI(hourTextFont, 15, painter);
|
setFontPointSizeDPI(hourTextFont, 15, painter);
|
||||||
|
|
||||||
|
@ -45,14 +45,14 @@ void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF& rect)
|
||||||
painter->setFont(hourTextFont);
|
painter->setFont(hourTextFont);
|
||||||
painter->setPen(hourTextPen);
|
painter->setPen(hourTextPen);
|
||||||
|
|
||||||
//qDebug() << "Drawing hours..." << rect << scroll;
|
// qDebug() << "Drawing hours..." << rect << scroll;
|
||||||
const QString fmt(QStringLiteral("%1:00"));
|
const QString fmt(QStringLiteral("%1:00"));
|
||||||
|
|
||||||
const qreal top = rect.top() - vertOffset;
|
const qreal top = rect.top() - vertOffset;
|
||||||
const qreal bottom = rect.bottom();
|
const qreal bottom = rect.bottom();
|
||||||
|
|
||||||
int h = qFloor(top / hourOffset);
|
int h = qFloor(top / hourOffset);
|
||||||
if(h < 0)
|
if (h < 0)
|
||||||
h = 0;
|
h = 0;
|
||||||
|
|
||||||
QRectF labelRect = rect;
|
QRectF labelRect = rect;
|
||||||
|
@ -60,9 +60,9 @@ void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF& rect)
|
||||||
labelRect.setHeight(hourOffset);
|
labelRect.setHeight(hourOffset);
|
||||||
labelRect.moveTop(h * hourOffset + vertOffset - hourOffset / 2);
|
labelRect.moveTop(h * hourOffset + vertOffset - hourOffset / 2);
|
||||||
|
|
||||||
for(; h <= 24 && labelRect.top() <= bottom; h++)
|
for (; h <= 24 && labelRect.top() <= bottom; h++)
|
||||||
{
|
{
|
||||||
//qDebug() << "Y:" << y << fmt.arg(h);
|
// qDebug() << "Y:" << y << fmt.arg(h);
|
||||||
painter->drawText(labelRect, fmt.arg(h), QTextOption(Qt::AlignVCenter | Qt::AlignRight));
|
painter->drawText(labelRect, fmt.arg(h), QTextOption(Qt::AlignVCenter | Qt::AlignRight));
|
||||||
labelRect.moveTop(labelRect.top() + hourOffset);
|
labelRect.moveTop(labelRect.top() + hourOffset);
|
||||||
}
|
}
|
||||||
|
@ -71,39 +71,38 @@ void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF& rect)
|
||||||
void BackgroundHelper::drawBackgroundHourLines(QPainter *painter, const QRectF &rect)
|
void BackgroundHelper::drawBackgroundHourLines(QPainter *painter, const QRectF &rect)
|
||||||
{
|
{
|
||||||
const double horizOffset = Session->horizOffset;
|
const double horizOffset = Session->horizOffset;
|
||||||
const double vertOffset = Session->vertOffset;
|
const double vertOffset = Session->vertOffset;
|
||||||
const double hourOffset = Session->hourOffset;
|
const double hourOffset = Session->hourOffset;
|
||||||
|
|
||||||
QPen hourLinePen(AppSettings.getHourLineColor(), AppSettings.getHourLineWidth());
|
QPen hourLinePen(AppSettings.getHourLineColor(), AppSettings.getHourLineWidth());
|
||||||
|
|
||||||
const qreal x1 = qMax(qreal(horizOffset), rect.left());
|
const qreal x1 = qMax(qreal(horizOffset), rect.left());
|
||||||
const qreal x2 = rect.right();
|
const qreal x2 = rect.right();
|
||||||
const qreal t = qMax(rect.top(), vertOffset);
|
const qreal t = qMax(rect.top(), vertOffset);
|
||||||
const qreal b = rect.bottom();
|
const qreal b = rect.bottom();
|
||||||
|
|
||||||
|
if (x1 > x2 || b < vertOffset || t > b)
|
||||||
if(x1 > x2 || b < vertOffset || t > b)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int firstH = qCeil((t - vertOffset) / hourOffset);
|
int firstH = qCeil((t - vertOffset) / hourOffset);
|
||||||
int lastH = qFloor((b - vertOffset) / hourOffset);
|
int lastH = qFloor((b - vertOffset) / hourOffset);
|
||||||
|
|
||||||
if(firstH > 24 || lastH < 0)
|
if (firstH > 24 || lastH < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(firstH < 0)
|
if (firstH < 0)
|
||||||
firstH = 0;
|
firstH = 0;
|
||||||
if(lastH > 24)
|
if (lastH > 24)
|
||||||
lastH = 24;
|
lastH = 24;
|
||||||
|
|
||||||
const int n = lastH - firstH + 1;
|
const int n = lastH - firstH + 1;
|
||||||
if(n <= 0)
|
if (n <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qreal y = vertOffset + firstH * hourOffset;
|
qreal y = vertOffset + firstH * hourOffset;
|
||||||
|
|
||||||
QLineF *arr = new QLineF[n];
|
QLineF *arr = new QLineF[n];
|
||||||
for(int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
arr[i] = QLineF(x1, y, x2, y);
|
arr[i] = QLineF(x1, y, x2, y);
|
||||||
y += hourOffset;
|
y += hourOffset;
|
||||||
|
@ -111,10 +110,11 @@ void BackgroundHelper::drawBackgroundHourLines(QPainter *painter, const QRectF &
|
||||||
|
|
||||||
painter->setPen(hourLinePen);
|
painter->setPen(hourLinePen);
|
||||||
painter->drawLines(arr, n);
|
painter->drawLines(arr, n);
|
||||||
delete [] arr;
|
delete[] arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundHelper::drawStationHeader(QPainter *painter, LineGraphScene *scene, const QRectF &rect)
|
void BackgroundHelper::drawStationHeader(QPainter *painter, LineGraphScene *scene,
|
||||||
|
const QRectF &rect)
|
||||||
{
|
{
|
||||||
QFont stationFont;
|
QFont stationFont;
|
||||||
stationFont.setBold(true);
|
stationFont.setBold(true);
|
||||||
|
@ -132,23 +132,23 @@ void BackgroundHelper::drawStationHeader(QPainter *painter, LineGraphScene *scen
|
||||||
QPen nonElectricPlatfPen(Qt::black);
|
QPen nonElectricPlatfPen(Qt::black);
|
||||||
|
|
||||||
const qreal platformOffset = Session->platformOffset;
|
const qreal platformOffset = Session->platformOffset;
|
||||||
const int stationOffset = Session->stationOffset;
|
const int stationOffset = Session->stationOffset;
|
||||||
|
|
||||||
//On left go back by half station offset to center station label
|
// On left go back by half station offset to center station label
|
||||||
//and center platform label by going a back of half platformOffset
|
// and center platform label by going a back of half platformOffset
|
||||||
const int leftOffset = -stationOffset/2 - platformOffset /2;
|
const int leftOffset = -stationOffset / 2 - platformOffset / 2;
|
||||||
|
|
||||||
const double margin = stationOffset * 0.1;
|
const double margin = stationOffset * 0.1;
|
||||||
|
|
||||||
QRectF r = rect;
|
QRectF r = rect;
|
||||||
|
|
||||||
for(auto st : qAsConst(scene->stations))
|
for (auto st : qAsConst(scene->stations))
|
||||||
{
|
{
|
||||||
const double left = st.xPos + leftOffset;
|
const double left = st.xPos + leftOffset;
|
||||||
const double right = left + st.platforms.count() * platformOffset + stationOffset;
|
const double right = left + st.platforms.count() * platformOffset + stationOffset;
|
||||||
|
|
||||||
if(right < r.left() || left >= r.right())
|
if (right < r.left() || left >= r.right())
|
||||||
continue; //Skip station, it's not visible
|
continue; // Skip station, it's not visible
|
||||||
|
|
||||||
QRectF labelRect = r;
|
QRectF labelRect = r;
|
||||||
labelRect.setLeft(left + margin);
|
labelRect.setLeft(left + margin);
|
||||||
|
@ -160,20 +160,20 @@ void BackgroundHelper::drawStationHeader(QPainter *painter, LineGraphScene *scen
|
||||||
painter->drawText(labelRect, Qt::AlignVCenter | Qt::AlignCenter, st.stationName);
|
painter->drawText(labelRect, Qt::AlignVCenter | Qt::AlignCenter, st.stationName);
|
||||||
|
|
||||||
labelRect = r;
|
labelRect = r;
|
||||||
labelRect.setTop(r.top() + r.height() * 2/3);
|
labelRect.setTop(r.top() + r.height() * 2 / 3);
|
||||||
|
|
||||||
//Go to start of station (first platform)
|
// Go to start of station (first platform)
|
||||||
//We need to compensate the half stationOffset used to center station label
|
// We need to compensate the half stationOffset used to center station label
|
||||||
double xPos = left + stationOffset/2;
|
double xPos = left + stationOffset / 2;
|
||||||
labelRect.setWidth(platformOffset);
|
labelRect.setWidth(platformOffset);
|
||||||
for(const StationGraphObject::PlatformGraph& platf : qAsConst(st.platforms))
|
for (const StationGraphObject::PlatformGraph &platf : qAsConst(st.platforms))
|
||||||
{
|
{
|
||||||
if(platf.platformType.testFlag(utils::StationTrackType::Electrified))
|
if (platf.platformType.testFlag(utils::StationTrackType::Electrified))
|
||||||
painter->setPen(electricPlatfPen);
|
painter->setPen(electricPlatfPen);
|
||||||
else
|
else
|
||||||
painter->setPen(nonElectricPlatfPen);
|
painter->setPen(nonElectricPlatfPen);
|
||||||
|
|
||||||
if(platf.platformType.testFlag(utils::StationTrackType::Through))
|
if (platf.platformType.testFlag(utils::StationTrackType::Through))
|
||||||
painter->setFont(platfBoldFont);
|
painter->setFont(platfBoldFont);
|
||||||
else
|
else
|
||||||
painter->setFont(platfNormalFont);
|
painter->setFont(platfNormalFont);
|
||||||
|
@ -191,33 +191,33 @@ void BackgroundHelper::drawStations(QPainter *painter, LineGraphScene *scene, co
|
||||||
{
|
{
|
||||||
const QRgb white = qRgb(255, 255, 255);
|
const QRgb white = qRgb(255, 255, 255);
|
||||||
|
|
||||||
//const int horizOffset = Session->horizOffset;
|
// const int horizOffset = Session->horizOffset;
|
||||||
const int vertOffset = Session->vertOffset;
|
const int vertOffset = Session->vertOffset;
|
||||||
//const int stationOffset = Session->stationOffset;
|
// const int stationOffset = Session->stationOffset;
|
||||||
const double platfOffset = Session->platformOffset;
|
const double platfOffset = Session->platformOffset;
|
||||||
const int lastY = vertOffset + Session->hourOffset * 24 + 10;
|
const int lastY = vertOffset + Session->hourOffset * 24 + 10;
|
||||||
|
|
||||||
const int width = AppSettings.getPlatformLineWidth();
|
const int width = AppSettings.getPlatformLineWidth();
|
||||||
const QColor mainPlatfColor = AppSettings.getMainPlatfColor();
|
const QColor mainPlatfColor = AppSettings.getMainPlatfColor();
|
||||||
|
|
||||||
QPen platfPen (mainPlatfColor, width);
|
QPen platfPen(mainPlatfColor, width);
|
||||||
|
|
||||||
QPointF top(0, vertOffset);
|
QPointF top(0, vertOffset);
|
||||||
QPointF bottom(0, lastY);
|
QPointF bottom(0, lastY);
|
||||||
|
|
||||||
for(const StationGraphObject &st : qAsConst(scene->stations))
|
for (const StationGraphObject &st : qAsConst(scene->stations))
|
||||||
{
|
{
|
||||||
const double left = st.xPos;
|
const double left = st.xPos;
|
||||||
const double right = left + st.platforms.count() * platfOffset;
|
const double right = left + st.platforms.count() * platfOffset;
|
||||||
|
|
||||||
if(left > rect.right() || right < rect.left())
|
if (left > rect.right() || right < rect.left())
|
||||||
continue; //Skip station, it's not visible
|
continue; // Skip station, it's not visible
|
||||||
|
|
||||||
top.rx() = bottom.rx() = st.xPos;
|
top.rx() = bottom.rx() = st.xPos;
|
||||||
|
|
||||||
for(const StationGraphObject::PlatformGraph& platf : st.platforms)
|
for (const StationGraphObject::PlatformGraph &platf : st.platforms)
|
||||||
{
|
{
|
||||||
if(platf.color == white)
|
if (platf.color == white)
|
||||||
platfPen.setColor(mainPlatfColor);
|
platfPen.setColor(mainPlatfColor);
|
||||||
else
|
else
|
||||||
platfPen.setColor(platf.color);
|
platfPen.setColor(platf.color);
|
||||||
|
@ -232,9 +232,10 @@ void BackgroundHelper::drawStations(QPainter *painter, LineGraphScene *scene, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, const QRectF &rect, bool drawSelection)
|
void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, const QRectF &rect,
|
||||||
|
bool drawSelection)
|
||||||
{
|
{
|
||||||
const double platfOffset = Session->platformOffset;
|
const double platfOffset = Session->platformOffset;
|
||||||
const double stationOffset = Session->stationOffset;
|
const double stationOffset = Session->stationOffset;
|
||||||
|
|
||||||
QFont jobNameFont;
|
QFont jobNameFont;
|
||||||
|
@ -249,7 +250,7 @@ void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, co
|
||||||
QPen selectedJobPen;
|
QPen selectedJobPen;
|
||||||
|
|
||||||
const JobStopEntry selectedJob = scene->getSelectedJob();
|
const JobStopEntry selectedJob = scene->getSelectedJob();
|
||||||
if(drawSelection && selectedJob.jobId)
|
if (drawSelection && selectedJob.jobId)
|
||||||
{
|
{
|
||||||
selectedJobPen.setWidthF(jobPen.widthF() * SelectedJobWidthFactor);
|
selectedJobPen.setWidthF(jobPen.widthF() * SelectedJobWidthFactor);
|
||||||
selectedJobPen.setCapStyle(Qt::RoundCap);
|
selectedJobPen.setCapStyle(Qt::RoundCap);
|
||||||
|
@ -266,48 +267,48 @@ void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, co
|
||||||
JobCategory lastJobCategory = JobCategory::NCategories;
|
JobCategory lastJobCategory = JobCategory::NCategories;
|
||||||
QTextOption textOption(Qt::AlignTop | Qt::AlignLeft);
|
QTextOption textOption(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
|
||||||
for(const StationGraphObject &st : qAsConst(scene->stations))
|
for (const StationGraphObject &st : qAsConst(scene->stations))
|
||||||
{
|
{
|
||||||
const double left = st.xPos;
|
const double left = st.xPos;
|
||||||
const double right = left + st.platforms.count() * platfOffset;
|
const double right = left + st.platforms.count() * platfOffset;
|
||||||
|
|
||||||
//Set a maximum right edge to Job labels
|
// Set a maximum right edge to Job labels
|
||||||
//This allows to determine if they have to be drawn
|
// This allows to determine if they have to be drawn
|
||||||
const double maxJobLabelX = right + stationOffset;
|
const double maxJobLabelX = right + stationOffset;
|
||||||
|
|
||||||
if(left > rect.right() || maxJobLabelX < rect.left())
|
if (left > rect.right() || maxJobLabelX < rect.left())
|
||||||
continue; //Skip station, it's not visible
|
continue; // Skip station, it's not visible
|
||||||
|
|
||||||
top.rx() = bottom.rx() = st.xPos;
|
top.rx() = bottom.rx() = st.xPos;
|
||||||
|
|
||||||
for(const StationGraphObject::PlatformGraph& platf : st.platforms)
|
for (const StationGraphObject::PlatformGraph &platf : st.platforms)
|
||||||
{
|
{
|
||||||
for(const StationGraphObject::JobStopGraph& jobStop : platf.jobStops)
|
for (const StationGraphObject::JobStopGraph &jobStop : platf.jobStops)
|
||||||
{
|
{
|
||||||
//NOTE: departure comes AFTER arrival in time, opposite than job segment
|
// NOTE: departure comes AFTER arrival in time, opposite than job segment
|
||||||
if(jobStop.arrivalY > rect.bottom() || jobStop.departureY < rect.top())
|
if (jobStop.arrivalY > rect.bottom() || jobStop.departureY < rect.top())
|
||||||
continue; //Skip, job not visible
|
continue; // Skip, job not visible
|
||||||
|
|
||||||
top.setY(jobStop.arrivalY);
|
top.setY(jobStop.arrivalY);
|
||||||
bottom.setY(jobStop.departureY);
|
bottom.setY(jobStop.departureY);
|
||||||
|
|
||||||
const bool nullStopDuration = qFuzzyCompare(top.y(), bottom.y());
|
const bool nullStopDuration = qFuzzyCompare(top.y(), bottom.y());
|
||||||
|
|
||||||
if(drawSelection && selectedJob.jobId == jobStop.stop.jobId)
|
if (drawSelection && selectedJob.jobId == jobStop.stop.jobId)
|
||||||
{
|
{
|
||||||
//Draw selection around segment
|
// Draw selection around segment
|
||||||
painter->setPen(selectedJobPen);
|
painter->setPen(selectedJobPen);
|
||||||
|
|
||||||
if(nullStopDuration)
|
if (nullStopDuration)
|
||||||
painter->drawPoint(top);
|
painter->drawPoint(top);
|
||||||
else
|
else
|
||||||
painter->drawLine(top, bottom);
|
painter->drawLine(top, bottom);
|
||||||
|
|
||||||
//Reset pen
|
// Reset pen
|
||||||
painter->setPen(jobPen);
|
painter->setPen(jobPen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lastJobCategory != jobStop.stop.category)
|
if (lastJobCategory != jobStop.stop.category)
|
||||||
{
|
{
|
||||||
QColor color = Session->colorForCat(jobStop.stop.category);
|
QColor color = Session->colorForCat(jobStop.stop.category);
|
||||||
jobPen.setColor(color);
|
jobPen.setColor(color);
|
||||||
|
@ -315,17 +316,18 @@ void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, co
|
||||||
lastJobCategory = jobStop.stop.category;
|
lastJobCategory = jobStop.stop.category;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nullStopDuration)
|
if (nullStopDuration)
|
||||||
painter->drawPoint(top);
|
painter->drawPoint(top);
|
||||||
else
|
else
|
||||||
painter->drawLine(top, bottom);
|
painter->drawLine(top, bottom);
|
||||||
|
|
||||||
if(jobStop.drawLabel)
|
if (jobStop.drawLabel)
|
||||||
{
|
{
|
||||||
const QString jobName = JobCategoryName::jobName(jobStop.stop.jobId, jobStop.stop.category);
|
const QString jobName =
|
||||||
|
JobCategoryName::jobName(jobStop.stop.jobId, jobStop.stop.category);
|
||||||
|
|
||||||
//Put label a bit to the left in respect to the stop arrival point
|
// Put label a bit to the left in respect to the stop arrival point
|
||||||
//Calculate width so it doesn't go after maxJobLabelX
|
// Calculate width so it doesn't go after maxJobLabelX
|
||||||
const qreal topWithMargin = top.x() + platfOffset / 2;
|
const qreal topWithMargin = top.x() + platfOffset / 2;
|
||||||
QRectF r(topWithMargin, top.y(), maxJobLabelX - topWithMargin, 25);
|
QRectF r(topWithMargin, top.y(), maxJobLabelX - topWithMargin, 25);
|
||||||
painter->drawText(r, jobName, textOption);
|
painter->drawText(r, jobName, textOption);
|
||||||
|
@ -338,7 +340,8 @@ void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundHelper::drawJobSegments(QPainter *painter, LineGraphScene *scene, const QRectF &rect, bool drawSelection)
|
void BackgroundHelper::drawJobSegments(QPainter *painter, LineGraphScene *scene, const QRectF &rect,
|
||||||
|
bool drawSelection)
|
||||||
{
|
{
|
||||||
const double stationOffset = Session->stationOffset;
|
const double stationOffset = Session->stationOffset;
|
||||||
|
|
||||||
|
@ -357,7 +360,7 @@ void BackgroundHelper::drawJobSegments(QPainter *painter, LineGraphScene *scene,
|
||||||
QPen selectedJobPen;
|
QPen selectedJobPen;
|
||||||
|
|
||||||
const JobStopEntry selectedJob = scene->getSelectedJob();
|
const JobStopEntry selectedJob = scene->getSelectedJob();
|
||||||
if(drawSelection && selectedJob.jobId)
|
if (drawSelection && selectedJob.jobId)
|
||||||
{
|
{
|
||||||
selectedJobPen.setWidthF(jobPen.widthF() * SelectedJobWidthFactor);
|
selectedJobPen.setWidthF(jobPen.widthF() * SelectedJobWidthFactor);
|
||||||
selectedJobPen.setCapStyle(Qt::RoundCap);
|
selectedJobPen.setCapStyle(Qt::RoundCap);
|
||||||
|
@ -371,47 +374,47 @@ void BackgroundHelper::drawJobSegments(QPainter *painter, LineGraphScene *scene,
|
||||||
JobCategory lastJobCategory = JobCategory::NCategories;
|
JobCategory lastJobCategory = JobCategory::NCategories;
|
||||||
QTextOption textOption(Qt::AlignCenter);
|
QTextOption textOption(Qt::AlignCenter);
|
||||||
|
|
||||||
//Iterate until one but last
|
// Iterate until one but last
|
||||||
//This way we can always acces next station
|
// This way we can always acces next station
|
||||||
for(int i = 0; i < scene->stationPositions.size() - 1; i++)
|
for (int i = 0; i < scene->stationPositions.size() - 1; i++)
|
||||||
{
|
{
|
||||||
const LineGraphScene::StationPosEntry& stPos = scene->stationPositions.at(i);
|
const LineGraphScene::StationPosEntry &stPos = scene->stationPositions.at(i);
|
||||||
|
|
||||||
const double left = stPos.xPos;
|
const double left = stPos.xPos;
|
||||||
double right = 0;
|
double right = 0;
|
||||||
|
|
||||||
if(i < scene->stationPositions.size() - 2)
|
if (i < scene->stationPositions.size() - 2)
|
||||||
{
|
{
|
||||||
const LineGraphScene::StationPosEntry& afterNextPos = scene->stationPositions.at(i + 2);
|
const LineGraphScene::StationPosEntry &afterNextPos = scene->stationPositions.at(i + 2);
|
||||||
right = afterNextPos.xPos - stationOffset;
|
right = afterNextPos.xPos - stationOffset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
right = rect.right(); //Last station, use all space on right side
|
right = rect.right(); // Last station, use all space on right side
|
||||||
}
|
}
|
||||||
|
|
||||||
if(left > rect.right() || right < rect.left())
|
if (left > rect.right() || right < rect.left())
|
||||||
continue; //Skip station, it's not visible
|
continue; // Skip station, it's not visible
|
||||||
|
|
||||||
for(const LineGraphScene::JobSegmentGraph& job : stPos.nextSegmentJobGraphs)
|
for (const LineGraphScene::JobSegmentGraph &job : stPos.nextSegmentJobGraphs)
|
||||||
{
|
{
|
||||||
//NOTE: departure comes BEFORE arrival in time, opposite than job stop
|
// NOTE: departure comes BEFORE arrival in time, opposite than job stop
|
||||||
if(job.fromDeparture.y() > rect.bottom() || job.toArrival.y() < rect.top())
|
if (job.fromDeparture.y() > rect.bottom() || job.toArrival.y() < rect.top())
|
||||||
continue; //Skip, job not visible
|
continue; // Skip, job not visible
|
||||||
|
|
||||||
const QLineF line(job.fromDeparture, job.toArrival);
|
const QLineF line(job.fromDeparture, job.toArrival);
|
||||||
|
|
||||||
if(drawSelection && selectedJob.jobId == job.jobId)
|
if (drawSelection && selectedJob.jobId == job.jobId)
|
||||||
{
|
{
|
||||||
//Draw selection around segment
|
// Draw selection around segment
|
||||||
painter->setPen(selectedJobPen);
|
painter->setPen(selectedJobPen);
|
||||||
painter->drawLine(line);
|
painter->drawLine(line);
|
||||||
|
|
||||||
//Reset pen
|
// Reset pen
|
||||||
painter->setPen(jobPen);
|
painter->setPen(jobPen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lastJobCategory != job.category)
|
if (lastJobCategory != job.category)
|
||||||
{
|
{
|
||||||
QColor color = Session->colorForCat(job.category);
|
QColor color = Session->colorForCat(job.category);
|
||||||
jobPen.setColor(color);
|
jobPen.setColor(color);
|
||||||
|
@ -423,35 +426,35 @@ void BackgroundHelper::drawJobSegments(QPainter *painter, LineGraphScene *scene,
|
||||||
|
|
||||||
const QString jobName = JobCategoryName::jobName(job.jobId, job.category);
|
const QString jobName = JobCategoryName::jobName(job.jobId, job.category);
|
||||||
|
|
||||||
//Save old transformation to reset it after drawing text
|
// Save old transformation to reset it after drawing text
|
||||||
const QTransform oldTransf = painter->transform();
|
const QTransform oldTransf = painter->transform();
|
||||||
|
|
||||||
//Move to line center, it will be rotation pivot
|
// Move to line center, it will be rotation pivot
|
||||||
painter->translate(line.center());
|
painter->translate(line.center());
|
||||||
|
|
||||||
//Rotate by line angle
|
// Rotate by line angle
|
||||||
qreal angle = line.angle();
|
qreal angle = line.angle();
|
||||||
if(job.fromDeparture.x() > job.toArrival.x())
|
if (job.fromDeparture.x() > job.toArrival.x())
|
||||||
angle += 180.0; //Prevent flipping text
|
angle += 180.0; // Prevent flipping text
|
||||||
|
|
||||||
painter->rotate(-angle); //minus because QPainter wants clockwise angle
|
painter->rotate(-angle); // minus because QPainter wants clockwise angle
|
||||||
|
|
||||||
const double lineLength = line.length();
|
const double lineLength = line.length();
|
||||||
QRectF textRect(-lineLength / 2, -30, lineLength, 25);
|
QRectF textRect(-lineLength / 2, -30, lineLength, 25);
|
||||||
|
|
||||||
//Try to avoid overlapping text of crossing jobs, move text towards arrival
|
// Try to avoid overlapping text of crossing jobs, move text towards arrival
|
||||||
if(job.toArrival.x() > job.fromDeparture.x())
|
if (job.toArrival.x() > job.fromDeparture.x())
|
||||||
textRect.moveLeft(textRect.left() + lineLength / 5);
|
textRect.moveLeft(textRect.left() + lineLength / 5);
|
||||||
else
|
else
|
||||||
textRect.moveLeft(textRect.left() - lineLength / 5);
|
textRect.moveLeft(textRect.left() - lineLength / 5);
|
||||||
|
|
||||||
textRect = painter->boundingRect(textRect, jobName, textOption);
|
textRect = painter->boundingRect(textRect, jobName, textOption);
|
||||||
|
|
||||||
//Draw a semi transparent background to ease text reading
|
// Draw a semi transparent background to ease text reading
|
||||||
painter->fillRect(textRect, textBackground);
|
painter->fillRect(textRect, textBackground);
|
||||||
painter->drawText(textRect, jobName, textOption);
|
painter->drawText(textRect, jobName, textOption);
|
||||||
|
|
||||||
//Reset to old transformation
|
// Reset to old transformation
|
||||||
painter->setTransform(oldTransf);
|
painter->setTransform(oldTransf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,21 +36,23 @@ class LineGraphScene;
|
||||||
class BackgroundHelper
|
class BackgroundHelper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void drawHourPanel(QPainter *painter, const QRectF& rect);
|
static void drawHourPanel(QPainter *painter, const QRectF &rect);
|
||||||
|
|
||||||
static void drawBackgroundHourLines(QPainter *painter, const QRectF& rect);
|
static void drawBackgroundHourLines(QPainter *painter, const QRectF &rect);
|
||||||
|
|
||||||
static void drawStationHeader(QPainter *painter, LineGraphScene *scene, const QRectF& rect);
|
static void drawStationHeader(QPainter *painter, LineGraphScene *scene, const QRectF &rect);
|
||||||
|
|
||||||
static void drawStations(QPainter *painter, LineGraphScene *scene, const QRectF& rect);
|
static void drawStations(QPainter *painter, LineGraphScene *scene, const QRectF &rect);
|
||||||
|
|
||||||
static void drawJobStops(QPainter *painter, LineGraphScene *scene, const QRectF& rect, bool drawSelection);
|
static void drawJobStops(QPainter *painter, LineGraphScene *scene, const QRectF &rect,
|
||||||
|
bool drawSelection);
|
||||||
|
|
||||||
static void drawJobSegments(QPainter *painter, LineGraphScene *scene, const QRectF &rect, bool drawSelection);
|
static void drawJobSegments(QPainter *painter, LineGraphScene *scene, const QRectF &rect,
|
||||||
|
bool drawSelection);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr double SelectedJobWidthFactor = 3.0;
|
static constexpr double SelectedJobWidthFactor = 3.0;
|
||||||
static constexpr int SelectedJobAlphaFactor = 127;
|
static constexpr int SelectedJobAlphaFactor = 127;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BACKGROUNDHELPER_H
|
#endif // BACKGROUNDHELPER_H
|
||||||
|
|
|
@ -49,20 +49,22 @@ LineGraphSelectionWidget::LineGraphSelectionWidget(QWidget *parent) :
|
||||||
|
|
||||||
QStringList items;
|
QStringList items;
|
||||||
items.reserve(int(LineGraphType::NTypes));
|
items.reserve(int(LineGraphType::NTypes));
|
||||||
for(int i = 0; i < int(LineGraphType::NTypes); i++)
|
for (int i = 0; i < int(LineGraphType::NTypes); i++)
|
||||||
items.append(utils::getLineGraphTypeName(LineGraphType(i)));
|
items.append(utils::getLineGraphTypeName(LineGraphType(i)));
|
||||||
graphTypeCombo->addItems(items);
|
graphTypeCombo->addItems(items);
|
||||||
graphTypeCombo->setCurrentIndex(0);
|
graphTypeCombo->setCurrentIndex(0);
|
||||||
|
|
||||||
connect(graphTypeCombo, qOverload<int>(&QComboBox::activated), this, &LineGraphSelectionWidget::onTypeComboActivated);
|
connect(graphTypeCombo, qOverload<int>(&QComboBox::activated), this,
|
||||||
connect(objectCombo, &CustomCompletionLineEdit::completionDone, this, &LineGraphSelectionWidget::onCompletionDone);
|
&LineGraphSelectionWidget::onTypeComboActivated);
|
||||||
|
connect(objectCombo, &CustomCompletionLineEdit::completionDone, this,
|
||||||
|
&LineGraphSelectionWidget::onCompletionDone);
|
||||||
|
|
||||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||||
}
|
}
|
||||||
|
|
||||||
LineGraphSelectionWidget::~LineGraphSelectionWidget()
|
LineGraphSelectionWidget::~LineGraphSelectionWidget()
|
||||||
{
|
{
|
||||||
if(matchModel)
|
if (matchModel)
|
||||||
{
|
{
|
||||||
objectCombo->setModel(nullptr);
|
objectCombo->setModel(nullptr);
|
||||||
delete matchModel;
|
delete matchModel;
|
||||||
|
@ -77,7 +79,7 @@ LineGraphType LineGraphSelectionWidget::getGraphType() const
|
||||||
|
|
||||||
void LineGraphSelectionWidget::setGraphType(LineGraphType type)
|
void LineGraphSelectionWidget::setGraphType(LineGraphType type)
|
||||||
{
|
{
|
||||||
if(getGraphType() == type)
|
if (getGraphType() == type)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
graphTypeCombo->setCurrentIndex(int(type));
|
graphTypeCombo->setCurrentIndex(int(type));
|
||||||
|
@ -98,16 +100,16 @@ const QString &LineGraphSelectionWidget::getObjectName() const
|
||||||
|
|
||||||
void LineGraphSelectionWidget::setObjectId(db_id objectId, const QString &name)
|
void LineGraphSelectionWidget::setObjectId(db_id objectId, const QString &name)
|
||||||
{
|
{
|
||||||
if(m_graphType == LineGraphType::NoGraph)
|
if (m_graphType == LineGraphType::NoGraph)
|
||||||
return; //Object ID must be null
|
return; // Object ID must be null
|
||||||
|
|
||||||
m_name = name;
|
m_name = name;
|
||||||
if(!objectId)
|
if (!objectId)
|
||||||
m_name.clear();
|
m_name.clear();
|
||||||
|
|
||||||
objectCombo->setData(objectId, name);
|
objectCombo->setData(objectId, name);
|
||||||
|
|
||||||
if(m_objectId != objectId)
|
if (m_objectId != objectId)
|
||||||
emit graphChanged(int(m_graphType), m_objectId);
|
emit graphChanged(int(m_graphType), m_objectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +121,7 @@ void LineGraphSelectionWidget::onTypeComboActivated(int index)
|
||||||
|
|
||||||
void LineGraphSelectionWidget::onCompletionDone()
|
void LineGraphSelectionWidget::onCompletionDone()
|
||||||
{
|
{
|
||||||
if(!objectCombo->getData(m_objectId, m_name))
|
if (!objectCombo->getData(m_objectId, m_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
emit graphChanged(int(m_graphType), m_objectId);
|
emit graphChanged(int(m_graphType), m_objectId);
|
||||||
|
@ -127,17 +129,17 @@ void LineGraphSelectionWidget::onCompletionDone()
|
||||||
|
|
||||||
void LineGraphSelectionWidget::setupModel(LineGraphType type)
|
void LineGraphSelectionWidget::setupModel(LineGraphType type)
|
||||||
{
|
{
|
||||||
if(type != m_graphType)
|
if (type != m_graphType)
|
||||||
{
|
{
|
||||||
//Clear old model
|
// Clear old model
|
||||||
if(matchModel)
|
if (matchModel)
|
||||||
{
|
{
|
||||||
objectCombo->setModel(nullptr);
|
objectCombo->setModel(nullptr);
|
||||||
delete matchModel;
|
delete matchModel;
|
||||||
matchModel = nullptr;
|
matchModel = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Manually clear line edit
|
// Manually clear line edit
|
||||||
m_objectId = 0;
|
m_objectId = 0;
|
||||||
m_name.clear();
|
m_name.clear();
|
||||||
objectCombo->setData(m_objectId, m_name);
|
objectCombo->setData(m_objectId, m_name);
|
||||||
|
@ -147,7 +149,7 @@ void LineGraphSelectionWidget::setupModel(LineGraphType type)
|
||||||
case LineGraphType::NoGraph:
|
case LineGraphType::NoGraph:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
//Prevent recursion on loadGraph() calling back to us
|
// Prevent recursion on loadGraph() calling back to us
|
||||||
type = LineGraphType::NoGraph;
|
type = LineGraphType::NoGraph;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -168,14 +170,13 @@ void LineGraphSelectionWidget::setupModel(LineGraphType type)
|
||||||
case LineGraphType::RailwayLine:
|
case LineGraphType::RailwayLine:
|
||||||
{
|
{
|
||||||
LinesMatchModel *m = new LinesMatchModel(Session->m_Db, true, this);
|
LinesMatchModel *m = new LinesMatchModel(Session->m_Db, true, this);
|
||||||
matchModel = m;
|
matchModel = m;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(matchModel)
|
if (matchModel)
|
||||||
objectCombo->setModel(matchModel);
|
objectCombo->setModel(matchModel);
|
||||||
}
|
}
|
||||||
m_graphType = type;
|
m_graphType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
|
|
||||||
db_id getObjectId() const;
|
db_id getObjectId() const;
|
||||||
const QString &getObjectName() const;
|
const QString &getObjectName() const;
|
||||||
void setObjectId(db_id objectId, const QString& name);
|
void setObjectId(db_id objectId, const QString &name);
|
||||||
|
|
||||||
void setName(const QString &newName);
|
void setName(const QString &newName);
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,8 @@ LineGraphToolbar::LineGraphToolbar(QWidget *parent) :
|
||||||
lay->setContentsMargins(0, 0, 0, 0);
|
lay->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
selectionWidget = new LineGraphSelectionWidget;
|
selectionWidget = new LineGraphSelectionWidget;
|
||||||
connect(selectionWidget, &LineGraphSelectionWidget::graphChanged, this, &LineGraphToolbar::onWidgetGraphChanged);
|
connect(selectionWidget, &LineGraphSelectionWidget::graphChanged, this,
|
||||||
|
&LineGraphToolbar::onWidgetGraphChanged);
|
||||||
lay->addWidget(selectionWidget);
|
lay->addWidget(selectionWidget);
|
||||||
|
|
||||||
redrawBut = new QPushButton(tr("Redraw"));
|
redrawBut = new QPushButton(tr("Redraw"));
|
||||||
|
@ -70,57 +71,59 @@ LineGraphToolbar::LineGraphToolbar(QWidget *parent) :
|
||||||
zoomSpinBox->setRange(25, 400);
|
zoomSpinBox->setRange(25, 400);
|
||||||
zoomSpinBox->setValue(mZoom);
|
zoomSpinBox->setValue(mZoom);
|
||||||
zoomSpinBox->setSuffix(QChar('%'));
|
zoomSpinBox->setSuffix(QChar('%'));
|
||||||
connect(zoomSpinBox, qOverload<int>(&QSpinBox::valueChanged), this, &LineGraphToolbar::updateZoomLevel);
|
connect(zoomSpinBox, qOverload<int>(&QSpinBox::valueChanged), this,
|
||||||
|
&LineGraphToolbar::updateZoomLevel);
|
||||||
lay->addWidget(zoomSpinBox);
|
lay->addWidget(zoomSpinBox);
|
||||||
|
|
||||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||||
|
|
||||||
//Accept focus events by click
|
// Accept focus events by click
|
||||||
setFocusPolicy(Qt::ClickFocus);
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
|
|
||||||
//Install event filter to catch focus events on children widgets
|
// Install event filter to catch focus events on children widgets
|
||||||
for(QObject *child : selectionWidget->children())
|
for (QObject *child : selectionWidget->children())
|
||||||
{
|
{
|
||||||
if(child->isWidgetType())
|
if (child->isWidgetType())
|
||||||
child->installEventFilter(this);
|
child->installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Install event filter on Zoom Slider to catch double click
|
// Install event filter on Zoom Slider to catch double click
|
||||||
zoomSlider->installEventFilter(this);
|
zoomSlider->installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
LineGraphToolbar::~LineGraphToolbar()
|
LineGraphToolbar::~LineGraphToolbar()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphToolbar::setScene(LineGraphScene *scene)
|
void LineGraphToolbar::setScene(LineGraphScene *scene)
|
||||||
{
|
{
|
||||||
if(m_scene)
|
if (m_scene)
|
||||||
{
|
{
|
||||||
disconnect(m_scene, &LineGraphScene::graphChanged, this, &LineGraphToolbar::onSceneGraphChanged);
|
disconnect(m_scene, &LineGraphScene::graphChanged, this,
|
||||||
|
&LineGraphToolbar::onSceneGraphChanged);
|
||||||
disconnect(m_scene, &QObject::destroyed, this, &LineGraphToolbar::onSceneDestroyed);
|
disconnect(m_scene, &QObject::destroyed, this, &LineGraphToolbar::onSceneDestroyed);
|
||||||
}
|
}
|
||||||
m_scene = scene;
|
m_scene = scene;
|
||||||
if(m_scene)
|
if (m_scene)
|
||||||
{
|
{
|
||||||
connect(m_scene, &LineGraphScene::graphChanged, this, &LineGraphToolbar::onSceneGraphChanged);
|
connect(m_scene, &LineGraphScene::graphChanged, this,
|
||||||
|
&LineGraphToolbar::onSceneGraphChanged);
|
||||||
connect(m_scene, &QObject::destroyed, this, &LineGraphToolbar::onSceneDestroyed);
|
connect(m_scene, &QObject::destroyed, this, &LineGraphToolbar::onSceneDestroyed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphToolbar::eventFilter(QObject *watched, QEvent *ev)
|
bool LineGraphToolbar::eventFilter(QObject *watched, QEvent *ev)
|
||||||
{
|
{
|
||||||
if(ev->type() == QEvent::FocusIn)
|
if (ev->type() == QEvent::FocusIn)
|
||||||
{
|
{
|
||||||
//If any of our child widgets receives focus, activate our scene
|
// If any of our child widgets receives focus, activate our scene
|
||||||
if(m_scene)
|
if (m_scene)
|
||||||
m_scene->activateScene();
|
m_scene->activateScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(watched == zoomSlider && ev->type() == QEvent::MouseButtonDblClick)
|
if (watched == zoomSlider && ev->type() == QEvent::MouseButtonDblClick)
|
||||||
{
|
{
|
||||||
//Zoom Slider was double clicked, reset zoom level to 100
|
// Zoom Slider was double clicked, reset zoom level to 100
|
||||||
updateZoomLevel(100);
|
updateZoomLevel(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,14 +133,14 @@ bool LineGraphToolbar::eventFilter(QObject *watched, QEvent *ev)
|
||||||
void LineGraphToolbar::resetToolbarToScene()
|
void LineGraphToolbar::resetToolbarToScene()
|
||||||
{
|
{
|
||||||
LineGraphType type = LineGraphType::NoGraph;
|
LineGraphType type = LineGraphType::NoGraph;
|
||||||
db_id objectId = 0;
|
db_id objectId = 0;
|
||||||
QString name;
|
QString name;
|
||||||
|
|
||||||
if(m_scene)
|
if (m_scene)
|
||||||
{
|
{
|
||||||
type = m_scene->getGraphType();
|
type = m_scene->getGraphType();
|
||||||
objectId = m_scene->getGraphObjectId();
|
objectId = m_scene->getGraphObjectId();
|
||||||
name = m_scene->getGraphObjectName();
|
name = m_scene->getGraphObjectName();
|
||||||
}
|
}
|
||||||
|
|
||||||
selectionWidget->setGraphType(type);
|
selectionWidget->setGraphType(type);
|
||||||
|
@ -146,7 +149,7 @@ void LineGraphToolbar::resetToolbarToScene()
|
||||||
|
|
||||||
void LineGraphToolbar::updateZoomLevel(int zoom)
|
void LineGraphToolbar::updateZoomLevel(int zoom)
|
||||||
{
|
{
|
||||||
if(mZoom == zoom)
|
if (mZoom == zoom)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mZoom = zoom;
|
mZoom = zoom;
|
||||||
|
@ -160,13 +163,13 @@ void LineGraphToolbar::updateZoomLevel(int zoom)
|
||||||
void LineGraphToolbar::onWidgetGraphChanged(int type, db_id objectId)
|
void LineGraphToolbar::onWidgetGraphChanged(int type, db_id objectId)
|
||||||
{
|
{
|
||||||
LineGraphType graphType = LineGraphType(type);
|
LineGraphType graphType = LineGraphType(type);
|
||||||
if(graphType == LineGraphType::NoGraph)
|
if (graphType == LineGraphType::NoGraph)
|
||||||
objectId = 0;
|
objectId = 0;
|
||||||
|
|
||||||
if(graphType != LineGraphType::NoGraph && !objectId)
|
if (graphType != LineGraphType::NoGraph && !objectId)
|
||||||
return; //User is still selecting an object
|
return; // User is still selecting an object
|
||||||
|
|
||||||
if(m_scene)
|
if (m_scene)
|
||||||
m_scene->loadGraph(objectId, graphType);
|
m_scene->loadGraph(objectId, graphType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +178,7 @@ void LineGraphToolbar::onSceneGraphChanged(int type, db_id objectId)
|
||||||
selectionWidget->setGraphType(LineGraphType(type));
|
selectionWidget->setGraphType(LineGraphType(type));
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
if(m_scene && m_scene->getGraphObjectId() == objectId)
|
if (m_scene && m_scene->getGraphObjectId() == objectId)
|
||||||
name = m_scene->getGraphObjectName();
|
name = m_scene->getGraphObjectName();
|
||||||
selectionWidget->setObjectId(objectId, name);
|
selectionWidget->setObjectId(objectId, name);
|
||||||
}
|
}
|
||||||
|
@ -183,12 +186,12 @@ void LineGraphToolbar::onSceneGraphChanged(int type, db_id objectId)
|
||||||
void LineGraphToolbar::onSceneDestroyed()
|
void LineGraphToolbar::onSceneDestroyed()
|
||||||
{
|
{
|
||||||
m_scene = nullptr;
|
m_scene = nullptr;
|
||||||
resetToolbarToScene(); //Clear UI
|
resetToolbarToScene(); // Clear UI
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineGraphToolbar::focusInEvent(QFocusEvent *e)
|
void LineGraphToolbar::focusInEvent(QFocusEvent *e)
|
||||||
{
|
{
|
||||||
if(m_scene)
|
if (m_scene)
|
||||||
m_scene->activateScene();
|
m_scene->activateScene();
|
||||||
|
|
||||||
QWidget::focusInEvent(e);
|
QWidget::focusInEvent(e);
|
||||||
|
|
|
@ -31,27 +31,28 @@
|
||||||
LineGraphView::LineGraphView(QWidget *parent) :
|
LineGraphView::LineGraphView(QWidget *parent) :
|
||||||
BasicGraphView(parent)
|
BasicGraphView(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineGraphView::viewportEvent(QEvent *e)
|
bool LineGraphView::viewportEvent(QEvent *e)
|
||||||
{
|
{
|
||||||
LineGraphScene *lineScene = qobject_cast<LineGraphScene *>(scene());
|
LineGraphScene *lineScene = qobject_cast<LineGraphScene *>(scene());
|
||||||
|
|
||||||
if(e->type() == QEvent::ToolTip && lineScene && lineScene->getGraphType() != LineGraphType::NoGraph)
|
if (e->type() == QEvent::ToolTip && lineScene
|
||||||
|
&& lineScene->getGraphType() != LineGraphType::NoGraph)
|
||||||
{
|
{
|
||||||
QHelpEvent *ev = static_cast<QHelpEvent *>(e);
|
QHelpEvent *ev = static_cast<QHelpEvent *>(e);
|
||||||
|
|
||||||
const QPointF scenePos = mapToScene(ev->pos());
|
const QPointF scenePos = mapToScene(ev->pos());
|
||||||
|
|
||||||
JobStopEntry job = lineScene->getJobAt(scenePos, Session->platformOffset / 2);
|
JobStopEntry job = lineScene->getJobAt(scenePos, Session->platformOffset / 2);
|
||||||
|
|
||||||
if(job.jobId)
|
if (job.jobId)
|
||||||
{
|
{
|
||||||
QToolTip::showText(ev->globalPos(),
|
QToolTip::showText(ev->globalPos(), JobCategoryName::jobName(job.jobId, job.category),
|
||||||
JobCategoryName::jobName(job.jobId, job.category),
|
|
||||||
viewport());
|
viewport());
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
QToolTip::hideText();
|
QToolTip::hideText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +72,11 @@ void LineGraphView::mouseDoubleClickEvent(QMouseEvent *e)
|
||||||
{
|
{
|
||||||
LineGraphScene *lineScene = qobject_cast<LineGraphScene *>(scene());
|
LineGraphScene *lineScene = qobject_cast<LineGraphScene *>(scene());
|
||||||
|
|
||||||
if(!lineScene || lineScene->getGraphType() == LineGraphType::NoGraph)
|
if (!lineScene || lineScene->getGraphType() == LineGraphType::NoGraph)
|
||||||
return; //Nothing to select
|
return; // Nothing to select
|
||||||
|
|
||||||
const QPointF scenePos = mapToScene(e->pos());
|
const QPointF scenePos = mapToScene(e->pos());
|
||||||
|
|
||||||
JobStopEntry job = lineScene->getJobAt(scenePos, Session->platformOffset / 2);
|
JobStopEntry job = lineScene->getJobAt(scenePos, Session->platformOffset / 2);
|
||||||
lineScene->setSelectedJob(job);
|
lineScene->setSelectedJob(job);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ LineGraphWidget::LineGraphWidget(QWidget *parent) :
|
||||||
{
|
{
|
||||||
QVBoxLayout *lay = new QVBoxLayout(this);
|
QVBoxLayout *lay = new QVBoxLayout(this);
|
||||||
|
|
||||||
toolBar = new LineGraphToolbar(this);
|
toolBar = new LineGraphToolbar(this);
|
||||||
|
|
||||||
lay->addWidget(toolBar);
|
lay->addWidget(toolBar);
|
||||||
|
|
||||||
|
@ -45,12 +45,13 @@ LineGraphWidget::LineGraphWidget(QWidget *parent) :
|
||||||
|
|
||||||
m_scene = new LineGraphScene(Session->m_Db, this);
|
m_scene = new LineGraphScene(Session->m_Db, this);
|
||||||
|
|
||||||
//Subscribe to notifications and to session managment
|
// Subscribe to notifications and to session managment
|
||||||
Session->getViewManager()->getLineGraphMgr()->registerScene(m_scene);
|
Session->getViewManager()->getLineGraphMgr()->registerScene(m_scene);
|
||||||
view->setScene(m_scene);
|
view->setScene(m_scene);
|
||||||
toolBar->setScene(m_scene);
|
toolBar->setScene(m_scene);
|
||||||
|
|
||||||
connect(view, &LineGraphView::syncToolbarToScene, toolBar, &LineGraphToolbar::resetToolbarToScene);
|
connect(view, &LineGraphView::syncToolbarToScene, toolBar,
|
||||||
|
&LineGraphToolbar::resetToolbarToScene);
|
||||||
connect(toolBar, &LineGraphToolbar::requestRedraw, m_scene, &LineGraphScene::reload);
|
connect(toolBar, &LineGraphToolbar::requestRedraw, m_scene, &LineGraphScene::reload);
|
||||||
|
|
||||||
connect(toolBar, &LineGraphToolbar::requestZoom, view, &LineGraphView::setZoomLevel);
|
connect(toolBar, &LineGraphToolbar::requestZoom, view, &LineGraphView::setZoomLevel);
|
||||||
|
@ -59,7 +60,7 @@ LineGraphWidget::LineGraphWidget(QWidget *parent) :
|
||||||
|
|
||||||
bool LineGraphWidget::tryLoadGraph(db_id graphObjId, LineGraphType type)
|
bool LineGraphWidget::tryLoadGraph(db_id graphObjId, LineGraphType type)
|
||||||
{
|
{
|
||||||
if(!m_scene)
|
if (!m_scene)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return m_scene->loadGraph(graphObjId, type);
|
return m_scene->loadGraph(graphObjId, type);
|
||||||
|
|
|
@ -46,9 +46,20 @@ class LineGraphWidget : public QWidget
|
||||||
public:
|
public:
|
||||||
explicit LineGraphWidget(QWidget *parent = nullptr);
|
explicit LineGraphWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
inline LineGraphScene *getScene() const { return m_scene; }
|
inline LineGraphScene *getScene() const
|
||||||
inline LineGraphView *getView() const { return view; }
|
{
|
||||||
inline LineGraphToolbar *getToolbar() const { return toolBar; }
|
return m_scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline LineGraphView *getView() const
|
||||||
|
{
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline LineGraphToolbar *getToolbar() const
|
||||||
|
{
|
||||||
|
return toolBar;
|
||||||
|
}
|
||||||
|
|
||||||
bool tryLoadGraph(db_id graphObjId, LineGraphType type);
|
bool tryLoadGraph(db_id graphObjId, LineGraphType type);
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@
|
||||||
|
|
||||||
#include "app/scopedebug.h"
|
#include "app/scopedebug.h"
|
||||||
|
|
||||||
|
|
||||||
EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::EditStopDialog),
|
ui(new Ui::EditStopDialog),
|
||||||
|
@ -57,12 +56,13 @@ EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
//Stop
|
// Stop
|
||||||
helper = new StopEditingHelper(Session->m_Db, stopModel,
|
helper = new StopEditingHelper(Session->m_Db, stopModel, ui->outGateTrackSpin,
|
||||||
ui->outGateTrackSpin, ui->arrivalTimeEdit, ui->departureTimeEdit,
|
ui->arrivalTimeEdit, ui->departureTimeEdit, this);
|
||||||
this);
|
connect(helper, &StopEditingHelper::nextSegmentChosen, this,
|
||||||
connect(helper, &StopEditingHelper::nextSegmentChosen, this, &EditStopDialog::updateAdditionalNotes);
|
&EditStopDialog::updateAdditionalNotes);
|
||||||
connect(helper, &StopEditingHelper::stationTrackChosen, this, &EditStopDialog::updateAdditionalNotes);
|
connect(helper, &StopEditingHelper::stationTrackChosen, this,
|
||||||
|
&EditStopDialog::updateAdditionalNotes);
|
||||||
|
|
||||||
CustomCompletionLineEdit *mStationEdit = helper->getStationEdit();
|
CustomCompletionLineEdit *mStationEdit = helper->getStationEdit();
|
||||||
CustomCompletionLineEdit *mStTrackEdit = helper->getStTrackEdit();
|
CustomCompletionLineEdit *mStTrackEdit = helper->getStTrackEdit();
|
||||||
|
@ -72,17 +72,17 @@ EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
||||||
ui->curStopLay->setWidget(2, QFormLayout::FieldRole, mStTrackEdit);
|
ui->curStopLay->setWidget(2, QFormLayout::FieldRole, mStTrackEdit);
|
||||||
ui->curStopLay->setWidget(3, QFormLayout::FieldRole, mOutGateEdit);
|
ui->curStopLay->setWidget(3, QFormLayout::FieldRole, mOutGateEdit);
|
||||||
|
|
||||||
//Coupling
|
// Coupling
|
||||||
couplingMgr = new RSCouplingInterface(Session->m_Db, this);
|
couplingMgr = new RSCouplingInterface(Session->m_Db, this);
|
||||||
|
|
||||||
coupledModel = new StopCouplingModel(Session->m_Db, this);
|
coupledModel = new StopCouplingModel(Session->m_Db, this);
|
||||||
auto ps = new ModelPageSwitcher(true, this);
|
auto ps = new ModelPageSwitcher(true, this);
|
||||||
ps->setModel(coupledModel);
|
ps->setModel(coupledModel);
|
||||||
ui->coupledView->setModel(coupledModel);
|
ui->coupledView->setModel(coupledModel);
|
||||||
ui->coupledLayout->insertWidget(1, ps);
|
ui->coupledLayout->insertWidget(1, ps);
|
||||||
|
|
||||||
uncoupledModel = new StopCouplingModel(Session->m_Db, this);
|
uncoupledModel = new StopCouplingModel(Session->m_Db, this);
|
||||||
ps = new ModelPageSwitcher(true, this);
|
ps = new ModelPageSwitcher(true, this);
|
||||||
ps->setModel(uncoupledModel);
|
ps->setModel(uncoupledModel);
|
||||||
ui->uncoupledView->setModel(uncoupledModel);
|
ui->uncoupledView->setModel(uncoupledModel);
|
||||||
ui->uncoupledLayout->insertWidget(1, ps);
|
ui->uncoupledLayout->insertWidget(1, ps);
|
||||||
|
@ -93,28 +93,32 @@ EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
||||||
|
|
||||||
ui->coupledView->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->coupledView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
ui->uncoupledView->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->uncoupledView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(ui->coupledView, &QAbstractItemView::customContextMenuRequested, this, &EditStopDialog::couplingCustomContextMenuRequested);
|
connect(ui->coupledView, &QAbstractItemView::customContextMenuRequested, this,
|
||||||
connect(ui->uncoupledView, &QAbstractItemView::customContextMenuRequested, this, &EditStopDialog::couplingCustomContextMenuRequested);
|
&EditStopDialog::couplingCustomContextMenuRequested);
|
||||||
|
connect(ui->uncoupledView, &QAbstractItemView::customContextMenuRequested, this,
|
||||||
|
&EditStopDialog::couplingCustomContextMenuRequested);
|
||||||
|
|
||||||
//Setup train asset models
|
// Setup train asset models
|
||||||
trainAssetModelBefore = new TrainAssetModel(Session->m_Db, this);
|
trainAssetModelBefore = new TrainAssetModel(Session->m_Db, this);
|
||||||
ps = new ModelPageSwitcher(true, this);
|
ps = new ModelPageSwitcher(true, this);
|
||||||
ps->setModel(trainAssetModelBefore);
|
ps->setModel(trainAssetModelBefore);
|
||||||
ui->assetBeforeView->setModel(trainAssetModelBefore);
|
ui->assetBeforeView->setModel(trainAssetModelBefore);
|
||||||
ui->trainAssetGridLayout->addWidget(ps, 2, 0);
|
ui->trainAssetGridLayout->addWidget(ps, 2, 0);
|
||||||
|
|
||||||
trainAssetModelAfter = new TrainAssetModel(Session->m_Db, this);
|
trainAssetModelAfter = new TrainAssetModel(Session->m_Db, this);
|
||||||
ps = new ModelPageSwitcher(true, this);
|
ps = new ModelPageSwitcher(true, this);
|
||||||
ps->setModel(trainAssetModelAfter);
|
ps->setModel(trainAssetModelAfter);
|
||||||
ui->assetAfterView->setModel(trainAssetModelAfter);
|
ui->assetAfterView->setModel(trainAssetModelAfter);
|
||||||
ui->trainAssetGridLayout->addWidget(ps, 2, 1);
|
ui->trainAssetGridLayout->addWidget(ps, 2, 1);
|
||||||
|
|
||||||
ui->assetBeforeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->assetBeforeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
ui->assetAfterView->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->assetAfterView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(ui->assetBeforeView, &QAbstractItemView::customContextMenuRequested, this, &EditStopDialog::couplingCustomContextMenuRequested);
|
connect(ui->assetBeforeView, &QAbstractItemView::customContextMenuRequested, this,
|
||||||
connect(ui->assetAfterView, &QAbstractItemView::customContextMenuRequested, this, &EditStopDialog::couplingCustomContextMenuRequested);
|
&EditStopDialog::couplingCustomContextMenuRequested);
|
||||||
|
connect(ui->assetAfterView, &QAbstractItemView::customContextMenuRequested, this,
|
||||||
|
&EditStopDialog::couplingCustomContextMenuRequested);
|
||||||
|
|
||||||
//Setup Crossings/Passings
|
// Setup Crossings/Passings
|
||||||
passingsModel = new JobPassingsModel(this);
|
passingsModel = new JobPassingsModel(this);
|
||||||
ui->passingsView->setModel(passingsModel);
|
ui->passingsView->setModel(passingsModel);
|
||||||
|
|
||||||
|
@ -123,13 +127,15 @@ EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
||||||
|
|
||||||
connect(ui->calcPassingsBut, &QPushButton::clicked, this, &EditStopDialog::calcPassings);
|
connect(ui->calcPassingsBut, &QPushButton::clicked, this, &EditStopDialog::calcPassings);
|
||||||
|
|
||||||
//BIG TODO: temporarily disable option to Cancel dialog
|
// BIG TODO: temporarily disable option to Cancel dialog
|
||||||
//This is because at the moment it doesn't seem Coupling are canceled
|
// This is because at the moment it doesn't seem Coupling are canceled
|
||||||
//So you get a mixed state: Arrival/Departure/Descriptio ecc changes are canceled but Coupling changes are still applied
|
// So you get a mixed state: Arrival/Departure/Descriptio ecc changes are canceled but Coupling
|
||||||
|
// changes are still applied
|
||||||
ui->buttonBox->setStandardButtons(QDialogButtonBox::Ok);
|
ui->buttonBox->setStandardButtons(QDialogButtonBox::Ok);
|
||||||
|
|
||||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setToolTip(tr("Press SHIFT modifier and click to save changes"
|
ui->buttonBox->button(QDialogButtonBox::Ok)
|
||||||
" without recalculating travel times."));
|
->setToolTip(tr("Press SHIFT modifier and click to save changes"
|
||||||
|
" without recalculating travel times."));
|
||||||
|
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
@ -149,15 +155,15 @@ void EditStopDialog::clearUi()
|
||||||
{
|
{
|
||||||
helper->stopOutTrackTimer();
|
helper->stopOutTrackTimer();
|
||||||
|
|
||||||
stopIdx = QModelIndex();
|
stopIdx = QModelIndex();
|
||||||
|
|
||||||
m_jobId = 0;
|
m_jobId = 0;
|
||||||
m_jobCat = JobCategory::FREIGHT;
|
m_jobCat = JobCategory::FREIGHT;
|
||||||
|
|
||||||
trainAssetModelBefore->setStop(0, QTime(), TrainAssetModel::BeforeStop);
|
trainAssetModelBefore->setStop(0, QTime(), TrainAssetModel::BeforeStop);
|
||||||
trainAssetModelAfter->setStop(0, QTime(), TrainAssetModel::AfterStop);
|
trainAssetModelAfter->setStop(0, QTime(), TrainAssetModel::AfterStop);
|
||||||
|
|
||||||
//TODO: clear UI properly
|
// TODO: clear UI properly
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditStopDialog::showBeforeAsset(bool val)
|
void EditStopDialog::showBeforeAsset(bool val)
|
||||||
|
@ -172,78 +178,79 @@ void EditStopDialog::showAfterAsset(bool val)
|
||||||
ui->assetAfterLabel->setVisible(val);
|
ui->assetAfterLabel->setVisible(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditStopDialog::setStop(const QModelIndex& idx)
|
void EditStopDialog::setStop(const QModelIndex &idx)
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
if(!idx.isValid())
|
if (!idx.isValid())
|
||||||
{
|
{
|
||||||
clearUi();
|
clearUi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_jobId = stopModel->getJobId();
|
m_jobId = stopModel->getJobId();
|
||||||
m_jobCat = stopModel->getCategory();
|
m_jobCat = stopModel->getCategory();
|
||||||
|
|
||||||
stopIdx = idx;
|
stopIdx = idx;
|
||||||
|
|
||||||
const StopItem& curStop = stopModel->getItemAt(idx.row());
|
const StopItem &curStop = stopModel->getItemAt(idx.row());
|
||||||
StopItem prevStop;
|
StopItem prevStop;
|
||||||
if(idx.row() == 0)
|
if (idx.row() == 0)
|
||||||
prevStop = StopItem(); //First stop has no previous stop
|
prevStop = StopItem(); // First stop has no previous stop
|
||||||
else
|
else
|
||||||
prevStop = stopModel->getItemAt(idx.row() - 1);
|
prevStop = stopModel->getItemAt(idx.row() - 1);
|
||||||
|
|
||||||
helper->setStop(curStop, prevStop);
|
helper->setStop(curStop, prevStop);
|
||||||
|
|
||||||
//Setup Train Asset
|
// Setup Train Asset
|
||||||
trainAssetModelBefore->setStop(m_jobId, curStop.arrival, TrainAssetModel::BeforeStop);
|
trainAssetModelBefore->setStop(m_jobId, curStop.arrival, TrainAssetModel::BeforeStop);
|
||||||
trainAssetModelAfter->setStop(m_jobId, curStop.arrival, TrainAssetModel::AfterStop);
|
trainAssetModelAfter->setStop(m_jobId, curStop.arrival, TrainAssetModel::AfterStop);
|
||||||
|
|
||||||
//Hide train asset before stop on First stop
|
// Hide train asset before stop on First stop
|
||||||
showBeforeAsset(curStop.type != StopType::First);
|
showBeforeAsset(curStop.type != StopType::First);
|
||||||
|
|
||||||
//Hide train asset after stop on Last stop
|
// Hide train asset after stop on Last stop
|
||||||
showAfterAsset(curStop.type != StopType::Last);
|
showAfterAsset(curStop.type != StopType::Last);
|
||||||
|
|
||||||
//Coupling operations
|
// Coupling operations
|
||||||
coupledModel->setStop(curStop.stopId, RsOp::Coupled);
|
coupledModel->setStop(curStop.stopId, RsOp::Coupled);
|
||||||
uncoupledModel->setStop(curStop.stopId, RsOp::Uncoupled);
|
uncoupledModel->setStop(curStop.stopId, RsOp::Uncoupled);
|
||||||
|
|
||||||
//Update UI
|
// Update UI
|
||||||
updateInfo();
|
updateInfo();
|
||||||
|
|
||||||
//Calc passings
|
// Calc passings
|
||||||
calcPassings();
|
calcPassings();
|
||||||
|
|
||||||
//Update Title
|
// Update Title
|
||||||
const QString jobName = JobCategoryName::jobName(m_jobId, m_jobCat);
|
const QString jobName = JobCategoryName::jobName(m_jobId, m_jobCat);
|
||||||
setWindowTitle(jobName);
|
setWindowTitle(jobName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditStopDialog::updateInfo()
|
void EditStopDialog::updateInfo()
|
||||||
{
|
{
|
||||||
const StopItem& curStop = helper->getCurItem();
|
const StopItem &curStop = helper->getCurItem();
|
||||||
const StopItem& prevStop = helper->getPrevItem();
|
const StopItem &prevStop = helper->getPrevItem();
|
||||||
|
|
||||||
const QString inGateStr = helper->getGateString(curStop.fromGate.gateId,
|
const QString inGateStr =
|
||||||
prevStop.nextSegment.reversed);
|
helper->getGateString(curStop.fromGate.gateId, prevStop.nextSegment.reversed);
|
||||||
ui->inGateEdit->setText(inGateStr);
|
ui->inGateEdit->setText(inGateStr);
|
||||||
|
|
||||||
if(curStop.type == StopType::First)
|
if (curStop.type == StopType::First)
|
||||||
{
|
{
|
||||||
//Hide box of previous stop
|
// Hide box of previous stop
|
||||||
ui->prevStopBox->setVisible(false);
|
ui->prevStopBox->setVisible(false);
|
||||||
ui->curStopBox->setTitle(tr("First Stop"));
|
ui->curStopBox->setTitle(tr("First Stop"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Show box of previous stop
|
// Show box of previous stop
|
||||||
ui->prevStopBox->setVisible(true);
|
ui->prevStopBox->setVisible(true);
|
||||||
ui->curStopBox->setTitle(curStop.type == StopType::Last ? tr("Last Stop") : tr("Current Stop"));
|
ui->curStopBox->setTitle(curStop.type == StopType::Last ? tr("Last Stop")
|
||||||
|
: tr("Current Stop"));
|
||||||
|
|
||||||
QString prevStName;
|
QString prevStName;
|
||||||
if(prevStop.stationId)
|
if (prevStop.stationId)
|
||||||
{
|
{
|
||||||
query q(Session->m_Db, "SELECT name FROM stations WHERE id=?");
|
query q(Session->m_Db, "SELECT name FROM stations WHERE id=?");
|
||||||
q.bind(1, prevStop.stationId);
|
q.bind(1, prevStop.stationId);
|
||||||
|
@ -252,17 +259,17 @@ void EditStopDialog::updateInfo()
|
||||||
}
|
}
|
||||||
ui->prevStEdit->setText(prevStName);
|
ui->prevStEdit->setText(prevStName);
|
||||||
|
|
||||||
const QString outGateStr = helper->getGateString(prevStop.toGate.gateId,
|
const QString outGateStr =
|
||||||
prevStop.nextSegment.reversed);
|
helper->getGateString(prevStop.toGate.gateId, prevStop.nextSegment.reversed);
|
||||||
ui->prevOutGateEdit->setText(outGateStr);
|
ui->prevOutGateEdit->setText(outGateStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString descr = stopModel->getDescription(curStop);
|
const QString descr = stopModel->getDescription(curStop);
|
||||||
ui->descriptionEdit->setPlainText(descr);
|
ui->descriptionEdit->setPlainText(descr);
|
||||||
|
|
||||||
if(curStop.type == StopType::Transit)
|
if (curStop.type == StopType::Transit)
|
||||||
{
|
{
|
||||||
//On transit you cannot couple/uncouple rollingstock
|
// On transit you cannot couple/uncouple rollingstock
|
||||||
ui->editCoupledBut->setEnabled(false);
|
ui->editCoupledBut->setEnabled(false);
|
||||||
ui->editUncoupledBut->setEnabled(false);
|
ui->editUncoupledBut->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
@ -276,13 +283,12 @@ void EditStopDialog::saveDataToModel()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
const StopItem& curStop = helper->getCurItem();
|
const StopItem &curStop = helper->getCurItem();
|
||||||
const StopItem& prevStop = helper->getPrevItem();
|
const StopItem &prevStop = helper->getPrevItem();
|
||||||
|
|
||||||
if(ui->descriptionEdit->document()->isModified())
|
if (ui->descriptionEdit->document()->isModified())
|
||||||
{
|
{
|
||||||
stopModel->setDescription(stopIdx,
|
stopModel->setDescription(stopIdx, ui->descriptionEdit->toPlainText());
|
||||||
ui->descriptionEdit->toPlainText());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool avoidTimeRecalc = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
bool avoidTimeRecalc = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||||
|
@ -291,8 +297,8 @@ void EditStopDialog::saveDataToModel()
|
||||||
|
|
||||||
void EditStopDialog::importJobRS()
|
void EditStopDialog::importJobRS()
|
||||||
{
|
{
|
||||||
const StopItem& curStop = helper->getCurItem();
|
const StopItem &curStop = helper->getCurItem();
|
||||||
if(!curStop.stationId)
|
if (!curStop.stationId)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Import Error"),
|
QMessageBox::warning(this, tr("Import Error"),
|
||||||
tr("In order to import rollingstock from other<br>"
|
tr("In order to import rollingstock from other<br>"
|
||||||
|
@ -305,48 +311,49 @@ void EditStopDialog::importJobRS()
|
||||||
jobsMatch.setDefaultId(JobMatchModel::StopId);
|
jobsMatch.setDefaultId(JobMatchModel::StopId);
|
||||||
jobsMatch.setFilter(m_jobId, curStop.stationId, curStop.departure);
|
jobsMatch.setFilter(m_jobId, curStop.stationId, curStop.departure);
|
||||||
|
|
||||||
QString stName = helper->getStationEdit()->text();
|
QString stName = helper->getStationEdit()->text();
|
||||||
|
|
||||||
OwningQPointer<ChooseItemDlg> dlg = new ChooseItemDlg(&jobsMatch, this);
|
OwningQPointer<ChooseItemDlg> dlg = new ChooseItemDlg(&jobsMatch, this);
|
||||||
dlg->setDescription(tr("Please choose a Job among the ones stopping at <b>%1</b> before <b>%2</b>.<br>"
|
dlg->setDescription(
|
||||||
"All rollingstock uncoupled by selected Job at current station<br>"
|
tr("Please choose a Job among the ones stopping at <b>%1</b> before <b>%2</b>.<br>"
|
||||||
"will be coupled to current Job.")
|
"All rollingstock uncoupled by selected Job at current station<br>"
|
||||||
.arg(stName,
|
"will be coupled to current Job.")
|
||||||
curStop.departure.toString("HH:mm")));
|
.arg(stName, curStop.departure.toString("HH:mm")));
|
||||||
dlg->setPlaceholder(tr("Job number without category"));
|
dlg->setPlaceholder(tr("Job number without category"));
|
||||||
|
|
||||||
//Select model
|
// Select model
|
||||||
int ret = dlg->exec();
|
int ret = dlg->exec();
|
||||||
if(ret != QDialog::Accepted || !dlg)
|
if (ret != QDialog::Accepted || !dlg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
db_id otherJobStopId = dlg->getItemId();
|
db_id otherJobStopId = dlg->getItemId();
|
||||||
if(!otherJobStopId)
|
if (!otherJobStopId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Import rollingstock
|
// Import rollingstock
|
||||||
int count = couplingMgr->importRSFromJob(otherJobStopId);
|
int count = couplingMgr->importRSFromJob(otherJobStopId);
|
||||||
|
|
||||||
//Refresh views
|
// Refresh views
|
||||||
coupledModel->refreshData(true);
|
coupledModel->refreshData(true);
|
||||||
trainAssetModelAfter->refreshData(true);
|
trainAssetModelAfter->refreshData(true);
|
||||||
|
|
||||||
//Tell user it's completed
|
// Tell user it's completed
|
||||||
QMessageBox::information(this, tr("Importation Finished"),
|
QMessageBox::information(
|
||||||
tr("<b>%1</b> rollingstock items were successfully imported")
|
this, tr("Importation Finished"),
|
||||||
.arg(count));
|
tr("<b>%1</b> rollingstock items were successfully imported").arg(count));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditStopDialog::editCoupled()
|
void EditStopDialog::editCoupled()
|
||||||
{
|
{
|
||||||
const StopItem& curStop = helper->getCurItem();
|
const StopItem &curStop = helper->getCurItem();
|
||||||
|
|
||||||
coupledModel->clearCache();
|
coupledModel->clearCache();
|
||||||
trainAssetModelAfter->clearCache();
|
trainAssetModelAfter->clearCache();
|
||||||
|
|
||||||
OwningQPointer<RSCoupleDialog> dlg = new RSCoupleDialog(couplingMgr, RsOp::Coupled, this);
|
OwningQPointer<RSCoupleDialog> dlg = new RSCoupleDialog(couplingMgr, RsOp::Coupled, this);
|
||||||
dlg->setWindowTitle(tr("Couple"));
|
dlg->setWindowTitle(tr("Couple"));
|
||||||
dlg->loadProxyModels(Session->m_Db, m_jobId, curStop.stopId, curStop.stationId, curStop.arrival);
|
dlg->loadProxyModels(Session->m_Db, m_jobId, curStop.stopId, curStop.stationId,
|
||||||
|
curStop.arrival);
|
||||||
|
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
|
|
||||||
|
@ -356,14 +363,15 @@ void EditStopDialog::editCoupled()
|
||||||
|
|
||||||
void EditStopDialog::editUncoupled()
|
void EditStopDialog::editUncoupled()
|
||||||
{
|
{
|
||||||
const StopItem& curStop = helper->getCurItem();
|
const StopItem &curStop = helper->getCurItem();
|
||||||
|
|
||||||
uncoupledModel->clearCache();
|
uncoupledModel->clearCache();
|
||||||
trainAssetModelAfter->clearCache();
|
trainAssetModelAfter->clearCache();
|
||||||
|
|
||||||
OwningQPointer<RSCoupleDialog> dlg = new RSCoupleDialog(couplingMgr, RsOp::Uncoupled, this);
|
OwningQPointer<RSCoupleDialog> dlg = new RSCoupleDialog(couplingMgr, RsOp::Uncoupled, this);
|
||||||
dlg->setWindowTitle(tr("Uncouple"));
|
dlg->setWindowTitle(tr("Uncouple"));
|
||||||
dlg->loadProxyModels(Session->m_Db, m_jobId, curStop.stopId, curStop.stationId, curStop.arrival);
|
dlg->loadProxyModels(Session->m_Db, m_jobId, curStop.stopId, curStop.stationId,
|
||||||
|
curStop.arrival);
|
||||||
|
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
|
|
||||||
|
@ -381,20 +389,21 @@ void EditStopDialog::calcPassings()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
const StopItem& curStop = helper->getCurItem();
|
const StopItem &curStop = helper->getCurItem();
|
||||||
|
|
||||||
JobStopDirectionHelper dirHelper(Session->m_Db);
|
JobStopDirectionHelper dirHelper(Session->m_Db);
|
||||||
utils::Side myDirection = dirHelper.getStopOutSide(curStop.stopId);
|
utils::Side myDirection = dirHelper.getStopOutSide(curStop.stopId);
|
||||||
|
|
||||||
query q(Session->m_Db, "SELECT s.id, s.job_id, jobs.category, s.arrival, s.departure,"
|
query q(Session->m_Db,
|
||||||
"t1.name,t2.name"
|
"SELECT s.id, s.job_id, jobs.category, s.arrival, s.departure,"
|
||||||
" FROM stops s"
|
"t1.name,t2.name"
|
||||||
" JOIN jobs ON jobs.id=s.job_id"
|
" FROM stops s"
|
||||||
" LEFT JOIN station_gate_connections g1 ON g1.id=s.in_gate_conn"
|
" JOIN jobs ON jobs.id=s.job_id"
|
||||||
" LEFT JOIN station_gate_connections g2 ON g2.id=s.out_gate_conn"
|
" LEFT JOIN station_gate_connections g1 ON g1.id=s.in_gate_conn"
|
||||||
" LEFT JOIN station_tracks t1 ON t1.id=g1.track_id"
|
" LEFT JOIN station_gate_connections g2 ON g2.id=s.out_gate_conn"
|
||||||
" LEFT JOIN station_tracks t2 ON t2.id=g2.track_id"
|
" LEFT JOIN station_tracks t1 ON t1.id=g1.track_id"
|
||||||
" WHERE s.station_id=? AND s.departure >=? AND s.arrival<=? AND s.job_id <> ?");
|
" LEFT JOIN station_tracks t2 ON t2.id=g2.track_id"
|
||||||
|
" WHERE s.station_id=? AND s.departure >=? AND s.arrival<=? AND s.job_id <> ?");
|
||||||
|
|
||||||
q.bind(1, curStop.stationId);
|
q.bind(1, curStop.stationId);
|
||||||
q.bind(2, curStop.arrival);
|
q.bind(2, curStop.arrival);
|
||||||
|
@ -403,27 +412,27 @@ void EditStopDialog::calcPassings()
|
||||||
|
|
||||||
QVector<JobPassingsModel::Entry> passings, crossings;
|
QVector<JobPassingsModel::Entry> passings, crossings;
|
||||||
|
|
||||||
for(auto r : q)
|
for (auto r : q)
|
||||||
{
|
{
|
||||||
JobPassingsModel::Entry e;
|
JobPassingsModel::Entry e;
|
||||||
|
|
||||||
db_id otherStopId = r.get<db_id>(0);
|
db_id otherStopId = r.get<db_id>(0);
|
||||||
e.jobId = r.get<db_id>(1);
|
e.jobId = r.get<db_id>(1);
|
||||||
e.category = JobCategory(r.get<int>(2));
|
e.category = JobCategory(r.get<int>(2));
|
||||||
e.arrival = r.get<QTime>(3);
|
e.arrival = r.get<QTime>(3);
|
||||||
e.departure = r.get<QTime>(4);
|
e.departure = r.get<QTime>(4);
|
||||||
e.platform = r.get<int>(5);
|
e.platform = r.get<int>(5);
|
||||||
|
|
||||||
e.platform = r.get<QString>(6);
|
e.platform = r.get<QString>(6);
|
||||||
if(e.platform.isEmpty())
|
if (e.platform.isEmpty())
|
||||||
e.platform = r.get<QString>(7); //Use out gate to get track name
|
e.platform = r.get<QString>(7); // Use out gate to get track name
|
||||||
|
|
||||||
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
||||||
|
|
||||||
if(myDirection == otherDir)
|
if (myDirection == otherDir)
|
||||||
passings.append(e); //Same direction -> Passing
|
passings.append(e); // Same direction -> Passing
|
||||||
else
|
else
|
||||||
crossings.append(e); //Opposite direction -> Crossing
|
crossings.append(e); // Opposite direction -> Crossing
|
||||||
}
|
}
|
||||||
|
|
||||||
q.reset();
|
q.reset();
|
||||||
|
@ -435,20 +444,21 @@ void EditStopDialog::calcPassings()
|
||||||
ui->crossingsView->resizeColumnsToContents();
|
ui->crossingsView->resizeColumnsToContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditStopDialog::couplingCustomContextMenuRequested(const QPoint& pos)
|
void EditStopDialog::couplingCustomContextMenuRequested(const QPoint &pos)
|
||||||
{
|
{
|
||||||
OwningQPointer<QMenu> menu = new QMenu(this);
|
OwningQPointer<QMenu> menu = new QMenu(this);
|
||||||
QAction *act = menu->addAction(tr("Refresh"));
|
QAction *act = menu->addAction(tr("Refresh"));
|
||||||
|
|
||||||
//HACK: could be ui->coupledView or ui->uncoupledView or ui->assetBeforeView or ui->assetAfterView
|
// HACK: could be ui->coupledView or ui->uncoupledView or ui->assetBeforeView or
|
||||||
|
// ui->assetAfterView
|
||||||
QAbstractItemView *view = qobject_cast<QAbstractItemView *>(sender());
|
QAbstractItemView *view = qobject_cast<QAbstractItemView *>(sender());
|
||||||
if(!view)
|
if (!view)
|
||||||
return; //Error: not called by the view?
|
return; // Error: not called by the view?
|
||||||
|
|
||||||
if(menu->exec(view->viewport()->mapToGlobal(pos)) != act)
|
if (menu->exec(view->viewport()->mapToGlobal(pos)) != act)
|
||||||
return; //User didn't select 'Refresh' action
|
return; // User didn't select 'Refresh' action
|
||||||
|
|
||||||
//Refresh data
|
// Refresh data
|
||||||
coupledModel->refreshData(true);
|
coupledModel->refreshData(true);
|
||||||
uncoupledModel->refreshData(true);
|
uncoupledModel->refreshData(true);
|
||||||
trainAssetModelBefore->refreshData(true);
|
trainAssetModelBefore->refreshData(true);
|
||||||
|
@ -457,7 +467,7 @@ void EditStopDialog::couplingCustomContextMenuRequested(const QPoint& pos)
|
||||||
|
|
||||||
int EditStopDialog::getTrainSpeedKmH(bool afterStop)
|
int EditStopDialog::getTrainSpeedKmH(bool afterStop)
|
||||||
{
|
{
|
||||||
const StopItem& curStop = helper->getCurItem();
|
const StopItem &curStop = helper->getCurItem();
|
||||||
|
|
||||||
query q(Session->m_Db, "SELECT MIN(rs_models.max_speed), rs_id FROM("
|
query q(Session->m_Db, "SELECT MIN(rs_models.max_speed), rs_id FROM("
|
||||||
"SELECT coupling.rs_id AS rs_id, MAX(stops.arrival)"
|
"SELECT coupling.rs_id AS rs_id, MAX(stops.arrival)"
|
||||||
|
@ -468,11 +478,11 @@ int EditStopDialog::getTrainSpeedKmH(bool afterStop)
|
||||||
" HAVING coupling.operation=1)"
|
" HAVING coupling.operation=1)"
|
||||||
" JOIN rs_list ON rs_list.id=rs_id"
|
" JOIN rs_list ON rs_list.id=rs_id"
|
||||||
" JOIN rs_models ON rs_models.id=rs_list.model_id");
|
" JOIN rs_models ON rs_models.id=rs_list.model_id");
|
||||||
q.bind(1, m_jobId); //TODO: maybe move to model
|
q.bind(1, m_jobId); // TODO: maybe move to model
|
||||||
|
|
||||||
//HACK: 1 minute is the min interval between stops,
|
// HACK: 1 minute is the min interval between stops,
|
||||||
//by adding 1 minute we include the current stop but leave out the next one
|
// by adding 1 minute we include the current stop but leave out the next one
|
||||||
if(afterStop)
|
if (afterStop)
|
||||||
q.bind(2, curStop.arrival.addSecs(60));
|
q.bind(2, curStop.arrival.addSecs(60));
|
||||||
else
|
else
|
||||||
q.bind(2, curStop.arrival);
|
q.bind(2, curStop.arrival);
|
||||||
|
@ -483,48 +493,48 @@ int EditStopDialog::getTrainSpeedKmH(bool afterStop)
|
||||||
|
|
||||||
void EditStopDialog::updateAdditionalNotes()
|
void EditStopDialog::updateAdditionalNotes()
|
||||||
{
|
{
|
||||||
const StopItem& curStop = helper->getCurItem();
|
const StopItem &curStop = helper->getCurItem();
|
||||||
|
|
||||||
QString msg;
|
QString msg;
|
||||||
|
|
||||||
//Check direction
|
// Check direction
|
||||||
if(curStop.fromGate.gateConnId && curStop.toGate.gateConnId
|
if (curStop.fromGate.gateConnId && curStop.toGate.gateConnId && curStop.type != StopType::First
|
||||||
&& curStop.type != StopType::First && curStop.type != StopType::Last)
|
&& curStop.type != StopType::Last)
|
||||||
{
|
{
|
||||||
//Ignore First and Last stop (sometimes they have fake in/out gates set which might trigger this message)
|
// Ignore First and Last stop (sometimes they have fake in/out gates set which might trigger
|
||||||
//Both entry and exit path are set, check direction
|
// this message) Both entry and exit path are set, check direction
|
||||||
if(curStop.fromGate.stationTrackSide == curStop.toGate.stationTrackSide)
|
if (curStop.fromGate.stationTrackSide == curStop.toGate.stationTrackSide)
|
||||||
{
|
{
|
||||||
//Train leaves station track from same side of entrance
|
// Train leaves station track from same side of entrance
|
||||||
msg = tr("Train reverses direction.");
|
msg = tr("Train reverses direction.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check line traction
|
// Check line traction
|
||||||
if(curStop.type != StopType::Last && curStop.nextSegment.segmentId)
|
if (curStop.type != StopType::Last && curStop.nextSegment.segmentId)
|
||||||
{
|
{
|
||||||
//Last has no next segment so do not show traction type
|
// Last has no next segment so do not show traction type
|
||||||
|
|
||||||
bool nextSegmentElectrified = stopModel->isRailwayElectrifiedAfterRow(stopIdx.row());
|
bool nextSegmentElectrified = stopModel->isRailwayElectrifiedAfterRow(stopIdx.row());
|
||||||
bool prevSegmentElectrified = !nextSegmentElectrified; //Trigger change on First stop
|
bool prevSegmentElectrified = !nextSegmentElectrified; // Trigger change on First stop
|
||||||
|
|
||||||
if(curStop.type != StopType::First && stopIdx.row() >= 0)
|
if (curStop.type != StopType::First && stopIdx.row() >= 0)
|
||||||
{
|
{
|
||||||
//Get real previous railway type
|
// Get real previous railway type
|
||||||
prevSegmentElectrified = stopModel->isRailwayElectrifiedAfterRow(stopIdx.row() - 1);
|
prevSegmentElectrified = stopModel->isRailwayElectrifiedAfterRow(stopIdx.row() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!msg.isEmpty())
|
if (!msg.isEmpty())
|
||||||
msg.append("\n\n"); //Separate from previous message
|
msg.append("\n\n"); // Separate from previous message
|
||||||
|
|
||||||
if(nextSegmentElectrified)
|
if (nextSegmentElectrified)
|
||||||
msg.append(tr("Electric traction is ALLOWED."));
|
msg.append(tr("Electric traction is ALLOWED."));
|
||||||
else
|
else
|
||||||
msg.append(tr("Electric traction is NOT ALLOWED."));
|
msg.append(tr("Electric traction is NOT ALLOWED."));
|
||||||
|
|
||||||
if(nextSegmentElectrified != prevSegmentElectrified && curStop.type != StopType::First)
|
if (nextSegmentElectrified != prevSegmentElectrified && curStop.type != StopType::First)
|
||||||
{
|
{
|
||||||
//Railway type changed
|
// Railway type changed
|
||||||
msg.append('\n');
|
msg.append('\n');
|
||||||
msg.append(tr("(Different traction then previous line!)"));
|
msg.append(tr("(Different traction then previous line!)"));
|
||||||
}
|
}
|
||||||
|
@ -536,7 +546,7 @@ void EditStopDialog::updateAdditionalNotes()
|
||||||
|
|
||||||
void EditStopDialog::setReadOnly(bool value)
|
void EditStopDialog::setReadOnly(bool value)
|
||||||
{
|
{
|
||||||
readOnly = value;
|
readOnly = value;
|
||||||
|
|
||||||
CustomCompletionLineEdit *mStationEdit = helper->getStationEdit();
|
CustomCompletionLineEdit *mStationEdit = helper->getStationEdit();
|
||||||
CustomCompletionLineEdit *mStTrackEdit = helper->getStTrackEdit();
|
CustomCompletionLineEdit *mStTrackEdit = helper->getStTrackEdit();
|
||||||
|
@ -557,73 +567,78 @@ void EditStopDialog::setReadOnly(bool value)
|
||||||
|
|
||||||
void EditStopDialog::done(int val)
|
void EditStopDialog::done(int val)
|
||||||
{
|
{
|
||||||
if(val == QDialog::Accepted)
|
if (val == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
if(stopIdx.row() < stopModel->rowCount() - 2)
|
if (stopIdx.row() < stopModel->rowCount() - 2)
|
||||||
{
|
{
|
||||||
//We are not last stop
|
// We are not last stop
|
||||||
|
|
||||||
//Check if train has at least one engine after this stop
|
// Check if train has at least one engine after this stop
|
||||||
//But not if we are Last stop (size - 1 - AddHere)
|
// But not if we are Last stop (size - 1 - AddHere)
|
||||||
//because the train doesn't have to leave the station
|
// because the train doesn't have to leave the station
|
||||||
bool electricOnNonElectrifiedLine = false;
|
bool electricOnNonElectrifiedLine = false;
|
||||||
if(!couplingMgr->hasEngineAfterStop(&electricOnNonElectrifiedLine) || electricOnNonElectrifiedLine)
|
if (!couplingMgr->hasEngineAfterStop(&electricOnNonElectrifiedLine)
|
||||||
|
|| electricOnNonElectrifiedLine)
|
||||||
{
|
{
|
||||||
int ret = QMessageBox::warning(this,
|
int ret = QMessageBox::warning(
|
||||||
tr("No Engine Left"),
|
this, tr("No Engine Left"),
|
||||||
electricOnNonElectrifiedLine ?
|
electricOnNonElectrifiedLine
|
||||||
tr("It seems you have uncoupled all job engines except for electric ones "
|
? tr("It seems you have uncoupled all job engines except for electric ones "
|
||||||
"but the line is not electrified\n"
|
"but the line is not electrified\n"
|
||||||
"(The train isn't able to move)\n"
|
"(The train isn't able to move)\n"
|
||||||
"Do you want to couple a non electric engine?") :
|
"Do you want to couple a non electric engine?")
|
||||||
tr("It seems you have uncoupled all job engines\n"
|
: tr("It seems you have uncoupled all job engines\n"
|
||||||
"(The train isn't able to move)\n"
|
"(The train isn't able to move)\n"
|
||||||
"Do you want to couple an engine?"),
|
"Do you want to couple an engine?"),
|
||||||
QMessageBox::Yes | QMessageBox::No);
|
QMessageBox::Yes | QMessageBox::No);
|
||||||
|
|
||||||
if(ret == QMessageBox::Yes)
|
if (ret == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
return; //Second chance to edit couplings
|
return; // Second chance to edit couplings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_AUTO_TIME_RECALC
|
#ifdef ENABLE_AUTO_TIME_RECALC
|
||||||
if(originalSpeedAfterStop != newSpeedAfterStop)
|
if (originalSpeedAfterStop != newSpeedAfterStop)
|
||||||
{
|
{
|
||||||
int speedBefore = originalSpeedAfterStop;
|
int speedBefore = originalSpeedAfterStop;
|
||||||
int speedAfter = newSpeedAfterStop;
|
int speedAfter = newSpeedAfterStop;
|
||||||
|
|
||||||
LinesModel *linesModel = stopModel->getLinesModel();
|
LinesModel *linesModel = stopModel->getLinesModel();
|
||||||
db_id lineId = curLine ? curLine : stopIdx.data(NEXT_LINE_ROLE).toLongLong();
|
db_id lineId = curLine ? curLine : stopIdx.data(NEXT_LINE_ROLE).toLongLong();
|
||||||
int lineSpeed = linesModel->getLineSpeed(lineId);
|
int lineSpeed = linesModel->getLineSpeed(lineId);
|
||||||
if(speedBefore == 0)
|
if (speedBefore == 0)
|
||||||
{
|
{
|
||||||
//If speed is null (likely because there weren't RS coupled before)
|
// If speed is null (likely because there weren't RS coupled before)
|
||||||
//Fall back to line max speed
|
// Fall back to line max speed
|
||||||
speedBefore = lineSpeed;
|
speedBefore = lineSpeed;
|
||||||
}
|
}
|
||||||
if(speedAfter == 0)
|
if (speedAfter == 0)
|
||||||
{
|
{
|
||||||
//If speed is null (likely because there isn't RS coupled after this stop)
|
// If speed is null (likely because there isn't RS coupled after this stop)
|
||||||
//Fall back to line max speed
|
// Fall back to line max speed
|
||||||
speedAfter = lineSpeed;
|
speedAfter = lineSpeed;
|
||||||
}
|
}
|
||||||
int ret = QMessageBox::question(this,
|
int ret = QMessageBox::question(
|
||||||
tr("Train Speed Changed"),
|
this, tr("Train Speed Changed"),
|
||||||
tr("Train speed after this stop has changed from a value of %1 km/h to <b>%2 km/h</b><br>"
|
tr("Train speed after this stop has changed from a value of %1 km/h to <b>%2 "
|
||||||
"Do you want to rebase travel times to this new speed?<br>"
|
"km/h</b><br>"
|
||||||
"NOTE: this doesn't affect stop times but you will lose manual adjustments to travel times")
|
"Do you want to rebase travel times to this new speed?<br>"
|
||||||
.arg(speedBefore).arg(speedAfter),
|
"NOTE: this doesn't affect stop times but you will lose manual adjustments to "
|
||||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
|
"travel times")
|
||||||
|
.arg(speedBefore)
|
||||||
|
.arg(speedAfter),
|
||||||
|
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
|
||||||
|
|
||||||
if(ret == QMessageBox::Cancel)
|
if (ret == QMessageBox::Cancel)
|
||||||
{
|
{
|
||||||
return; //Second chance to edit couplings
|
return; // Second chance to edit couplings
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ret == QMessageBox::Yes)
|
if (ret == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
stopModel->rebaseTimesToSpeed(stopIdx.row(), ui->arrivalTimeEdit->time(), ui->departureTimeEdit->time());
|
stopModel->rebaseTimesToSpeed(stopIdx.row(), ui->arrivalTimeEdit->time(),
|
||||||
|
ui->departureTimeEdit->time());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -95,11 +95,11 @@ private:
|
||||||
StopCouplingModel *coupledModel;
|
StopCouplingModel *coupledModel;
|
||||||
StopCouplingModel *uncoupledModel;
|
StopCouplingModel *uncoupledModel;
|
||||||
|
|
||||||
TrainAssetModel *trainAssetModelBefore;
|
TrainAssetModel *trainAssetModelBefore;
|
||||||
TrainAssetModel *trainAssetModelAfter;
|
TrainAssetModel *trainAssetModelAfter;
|
||||||
|
|
||||||
JobPassingsModel *passingsModel;
|
JobPassingsModel *passingsModel;
|
||||||
JobPassingsModel *crossingsModel;
|
JobPassingsModel *crossingsModel;
|
||||||
|
|
||||||
bool readOnly;
|
bool readOnly;
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
#include "utils/delegates/sql/customcompletionlineedit.h"
|
#include "utils/delegates/sql/customcompletionlineedit.h"
|
||||||
#include "shifts/shiftcombomodel.h"
|
#include "shifts/shiftcombomodel.h"
|
||||||
|
|
||||||
|
|
||||||
#include "utils/owningqpointer.h"
|
#include "utils/owningqpointer.h"
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -55,7 +54,6 @@
|
||||||
|
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
|
|
||||||
|
|
||||||
JobPathEditor::JobPathEditor(QWidget *parent) :
|
JobPathEditor::JobPathEditor(QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::JobPathEditor),
|
ui(new Ui::JobPathEditor),
|
||||||
|
@ -69,7 +67,7 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
||||||
|
|
||||||
QStringList catNames;
|
QStringList catNames;
|
||||||
catNames.reserve(int(JobCategory::NCategories));
|
catNames.reserve(int(JobCategory::NCategories));
|
||||||
for(int cat = 0; cat < int(JobCategory::NCategories); cat++)
|
for (int cat = 0; cat < int(JobCategory::NCategories); cat++)
|
||||||
{
|
{
|
||||||
catNames.append(JobCategoryName::fullName(JobCategory(cat)));
|
catNames.append(JobCategoryName::fullName(JobCategory(cat)));
|
||||||
}
|
}
|
||||||
|
@ -79,17 +77,18 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
||||||
ui->categoryCombo->setCurrentIndex(-1);
|
ui->categoryCombo->setCurrentIndex(-1);
|
||||||
|
|
||||||
ShiftComboModel *shiftComboModel = new ShiftComboModel(Session->m_Db, this);
|
ShiftComboModel *shiftComboModel = new ShiftComboModel(Session->m_Db, this);
|
||||||
shiftCombo = new CustomCompletionLineEdit(shiftComboModel);
|
shiftCombo = new CustomCompletionLineEdit(shiftComboModel);
|
||||||
|
|
||||||
//Get Catecory combo position and insert shift below
|
// Get Catecory combo position and insert shift below
|
||||||
int categoryRow = 0;
|
int categoryRow = 0;
|
||||||
QFormLayout::ItemRole unusedRole;
|
QFormLayout::ItemRole unusedRole;
|
||||||
ui->formLayout->getWidgetPosition(ui->categoryCombo, &categoryRow, &unusedRole);
|
ui->formLayout->getWidgetPosition(ui->categoryCombo, &categoryRow, &unusedRole);
|
||||||
ui->formLayout->insertRow(categoryRow + 1, tr("Shift:"), shiftCombo);
|
ui->formLayout->insertRow(categoryRow + 1, tr("Shift:"), shiftCombo);
|
||||||
|
|
||||||
//Stops
|
// Stops
|
||||||
stopModel = new StopModel(Session->m_Db, this);
|
stopModel = new StopModel(Session->m_Db, this);
|
||||||
connect(shiftCombo, &CustomCompletionLineEdit::dataIdChanged, stopModel, &StopModel::setNewShiftId);
|
connect(shiftCombo, &CustomCompletionLineEdit::dataIdChanged, stopModel,
|
||||||
|
&StopModel::setNewShiftId);
|
||||||
ui->stopsView->setModel(stopModel);
|
ui->stopsView->setModel(stopModel);
|
||||||
|
|
||||||
delegate = new StopDelegate(Session->m_Db, this);
|
delegate = new StopDelegate(Session->m_Db, this);
|
||||||
|
@ -99,7 +98,7 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
||||||
ui->stopsView->setMovement(QListView::Static);
|
ui->stopsView->setMovement(QListView::Static);
|
||||||
ui->stopsView->setSelectionMode(QListView::ContiguousSelection);
|
ui->stopsView->setSelectionMode(QListView::ContiguousSelection);
|
||||||
|
|
||||||
//Next/Prev Jobs
|
// Next/Prev Jobs
|
||||||
prevJobsModel = new NextPrevRSJobsModel(Session->m_Db, this);
|
prevJobsModel = new NextPrevRSJobsModel(Session->m_Db, this);
|
||||||
prevJobsModel->setMode(NextPrevRSJobsModel::PrevJobs);
|
prevJobsModel->setMode(NextPrevRSJobsModel::PrevJobs);
|
||||||
ui->prevJobsView->setModel(prevJobsModel);
|
ui->prevJobsView->setModel(prevJobsModel);
|
||||||
|
@ -108,11 +107,12 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
||||||
nextJobsModel->setMode(NextPrevRSJobsModel::NextJobs);
|
nextJobsModel->setMode(NextPrevRSJobsModel::NextJobs);
|
||||||
ui->nextJobsView->setModel(nextJobsModel);
|
ui->nextJobsView->setModel(nextJobsModel);
|
||||||
|
|
||||||
|
connect(ui->categoryCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
|
||||||
connect(ui->categoryCombo, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated), stopModel, &StopModel::setCategory);
|
stopModel, &StopModel::setCategory);
|
||||||
connect(stopModel, &StopModel::categoryChanged, this, &JobPathEditor::onCategoryChanged);
|
connect(stopModel, &StopModel::categoryChanged, this, &JobPathEditor::onCategoryChanged);
|
||||||
|
|
||||||
connect(ui->jobIdSpin, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &JobPathEditor::startJobNumberTimer);
|
connect(ui->jobIdSpin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||||
|
&JobPathEditor::startJobNumberTimer);
|
||||||
connect(stopModel, &StopModel::jobIdChanged, this, &JobPathEditor::onJobIdChanged);
|
connect(stopModel, &StopModel::jobIdChanged, this, &JobPathEditor::onJobIdChanged);
|
||||||
|
|
||||||
connect(stopModel, &StopModel::edited, this, &JobPathEditor::setEdited);
|
connect(stopModel, &StopModel::edited, this, &JobPathEditor::setEdited);
|
||||||
|
@ -123,14 +123,17 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
||||||
connect(ui->sheetBut, &QPushButton::clicked, this, &JobPathEditor::onSaveSheet);
|
connect(ui->sheetBut, &QPushButton::clicked, this, &JobPathEditor::onSaveSheet);
|
||||||
|
|
||||||
ui->stopsView->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->stopsView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(ui->stopsView, &QListView::customContextMenuRequested, this, &JobPathEditor::showStopsContextMenu);
|
connect(ui->stopsView, &QListView::customContextMenuRequested, this,
|
||||||
|
&JobPathEditor::showStopsContextMenu);
|
||||||
connect(ui->stopsView, &QListView::clicked, this, &JobPathEditor::onStopIndexClicked);
|
connect(ui->stopsView, &QListView::clicked, this, &JobPathEditor::onStopIndexClicked);
|
||||||
|
|
||||||
ui->prevJobsView->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->prevJobsView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(ui->prevJobsView, &QListView::customContextMenuRequested, this, &JobPathEditor::showJobContextMenu);
|
connect(ui->prevJobsView, &QListView::customContextMenuRequested, this,
|
||||||
|
&JobPathEditor::showJobContextMenu);
|
||||||
|
|
||||||
ui->nextJobsView->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->nextJobsView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(ui->nextJobsView, &QListView::customContextMenuRequested, this, &JobPathEditor::showJobContextMenu);
|
connect(ui->nextJobsView, &QListView::customContextMenuRequested, this,
|
||||||
|
&JobPathEditor::showJobContextMenu);
|
||||||
|
|
||||||
connect(Session, &MeetingSession::jobRemoved, this, &JobPathEditor::onJobRemoved);
|
connect(Session, &MeetingSession::jobRemoved, this, &JobPathEditor::onJobRemoved);
|
||||||
connect(&AppSettings, &MRTPSettings::jobColorsChanged, this, &JobPathEditor::updateSpinColor);
|
connect(&AppSettings, &MRTPSettings::jobColorsChanged, this, &JobPathEditor::updateSpinColor);
|
||||||
|
@ -149,16 +152,16 @@ JobPathEditor::~JobPathEditor()
|
||||||
|
|
||||||
bool JobPathEditor::setJob(db_id jobId)
|
bool JobPathEditor::setJob(db_id jobId)
|
||||||
{
|
{
|
||||||
if(!canSetJob)
|
if (!canSetJob)
|
||||||
return false; //We are busy - (Avoid nested loop calls from inside 'saveChanges()')
|
return false; // We are busy - (Avoid nested loop calls from inside 'saveChanges()')
|
||||||
|
|
||||||
if(!isClear && stopModel->getJobId() == jobId)
|
if (!isClear && stopModel->getJobId() == jobId)
|
||||||
return true; //Fake return, we already set this job
|
return true; // Fake return, we already set this job
|
||||||
|
|
||||||
if(isEdited())
|
if (isEdited())
|
||||||
{
|
{
|
||||||
if(!maybeSave())
|
if (!maybeSave())
|
||||||
return false; //User still wants to edit the current job
|
return false; // User still wants to edit the current job
|
||||||
}
|
}
|
||||||
|
|
||||||
return setJob_internal(jobId);
|
return setJob_internal(jobId);
|
||||||
|
@ -168,32 +171,32 @@ bool JobPathEditor::setJob_internal(db_id jobId)
|
||||||
{
|
{
|
||||||
DEBUG_IMPORTANT_ENTRY;
|
DEBUG_IMPORTANT_ENTRY;
|
||||||
|
|
||||||
if(!canSetJob)
|
if (!canSetJob)
|
||||||
return false; //We are busy - (Avoid nested loop calls from inside 'saveChanges()')
|
return false; // We are busy - (Avoid nested loop calls from inside 'saveChanges()')
|
||||||
|
|
||||||
if(!isClear && stopModel->getJobId() == jobId)
|
if (!isClear && stopModel->getJobId() == jobId)
|
||||||
return true; //Fake return, we already set this job
|
return true; // Fake return, we already set this job
|
||||||
|
|
||||||
isClear = false;
|
isClear = false;
|
||||||
|
|
||||||
stopJobNumberTimer();
|
stopJobNumberTimer();
|
||||||
|
|
||||||
//Load from database
|
// Load from database
|
||||||
if(!stopModel->loadJobStops(jobId))
|
if (!stopModel->loadJobStops(jobId))
|
||||||
{
|
{
|
||||||
//Error: job could not be loaded, maybe invalid jobId
|
// Error: job could not be loaded, maybe invalid jobId
|
||||||
clearJob();
|
clearJob();
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
|
|
||||||
QMessageBox::warning(this, tr("Error Loading Job"),
|
QMessageBox::warning(this, tr("Error Loading Job"),
|
||||||
tr("<b>Job %1</b> could not be loaded.<br>"
|
tr("<b>Job %1</b> could not be loaded.<br>"
|
||||||
"Maybe it's number was changed or maybe it doesn't exist at all.")
|
"Maybe it's number was changed or maybe it doesn't exist at all.")
|
||||||
.arg(jobId));
|
.arg(jobId));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If read-only hide 'AddHere' row (last one)
|
// If read-only hide 'AddHere' row (last one)
|
||||||
ui->stopsView->setRowHidden(stopModel->rowCount() - 1, m_readOnly);
|
ui->stopsView->setRowHidden(stopModel->rowCount() - 1, m_readOnly);
|
||||||
|
|
||||||
prevJobsModel->setJobId(jobId);
|
prevJobsModel->setJobId(jobId);
|
||||||
|
@ -204,16 +207,16 @@ bool JobPathEditor::setJob_internal(db_id jobId)
|
||||||
|
|
||||||
void JobPathEditor::startJobNumberTimer()
|
void JobPathEditor::startJobNumberTimer()
|
||||||
{
|
{
|
||||||
//Give user a small time to scroll values in ID QSpinBox
|
// Give user a small time to scroll values in ID QSpinBox
|
||||||
//This will skip eventual non available IDs (already existent)
|
// This will skip eventual non available IDs (already existent)
|
||||||
//On timeout check ID and reset to old value if not available
|
// On timeout check ID and reset to old value if not available
|
||||||
stopJobNumberTimer();
|
stopJobNumberTimer();
|
||||||
jobNumberTimerId = startTimer(700);
|
jobNumberTimerId = startTimer(700);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobPathEditor::stopJobNumberTimer()
|
void JobPathEditor::stopJobNumberTimer()
|
||||||
{
|
{
|
||||||
if(jobNumberTimerId)
|
if (jobNumberTimerId)
|
||||||
{
|
{
|
||||||
killTimer(jobNumberTimerId);
|
killTimer(jobNumberTimerId);
|
||||||
jobNumberTimerId = 0;
|
jobNumberTimerId = 0;
|
||||||
|
@ -222,15 +225,16 @@ void JobPathEditor::stopJobNumberTimer()
|
||||||
|
|
||||||
void JobPathEditor::checkJobNumberValid()
|
void JobPathEditor::checkJobNumberValid()
|
||||||
{
|
{
|
||||||
//Kill timer
|
// Kill timer
|
||||||
stopJobNumberTimer();
|
stopJobNumberTimer();
|
||||||
|
|
||||||
db_id jobId = ui->jobIdSpin->value();
|
db_id jobId = ui->jobIdSpin->value();
|
||||||
if(!stopModel->setNewJobId(jobId))
|
if (!stopModel->setNewJobId(jobId))
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Invalid"),
|
QMessageBox::warning(this, tr("Invalid"),
|
||||||
tr("Job number <b>%1</b> is already exists.<br>"
|
tr("Job number <b>%1</b> is already exists.<br>"
|
||||||
"Please choose a different number.").arg(jobId));
|
"Please choose a different number.")
|
||||||
|
.arg(jobId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,43 +253,43 @@ bool JobPathEditor::createNewJob(db_id *out)
|
||||||
* or if user doesn't add at least 2 stops to the job
|
* or if user doesn't add at least 2 stops to the job
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(out)
|
if (out)
|
||||||
*out = 0;
|
*out = 0;
|
||||||
|
|
||||||
if(!clearJob())
|
if (!clearJob())
|
||||||
return false; //Busy JobPathEditor
|
return false; // Busy JobPathEditor
|
||||||
|
|
||||||
db_id jobId = 0;
|
db_id jobId = 0;
|
||||||
if(!JobsHelper::createNewJob(Session->m_Db, jobId) || jobId == 0)
|
if (!JobsHelper::createNewJob(Session->m_Db, jobId) || jobId == 0)
|
||||||
{
|
{
|
||||||
return false; //An error occurred in database, abort
|
return false; // An error occurred in database, abort
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!setJob_internal(jobId))
|
if (!setJob_internal(jobId))
|
||||||
{
|
{
|
||||||
//If we fail opening JobPathEditor remove the job
|
// If we fail opening JobPathEditor remove the job
|
||||||
JobsHelper::removeJob(Session->m_Db, jobId);
|
JobsHelper::removeJob(Session->m_Db, jobId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(out)
|
if (out)
|
||||||
*out = jobId;
|
*out = jobId;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobPathEditor::showStopsContextMenu(const QPoint& pos)
|
void JobPathEditor::showStopsContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
QModelIndex index = ui->stopsView->indexAt(pos);
|
QModelIndex index = ui->stopsView->indexAt(pos);
|
||||||
if(!index.isValid() || index.row()>= stopModel->rowCount() || stopModel->isAddHere(index))
|
if (!index.isValid() || index.row() >= stopModel->rowCount() || stopModel->isAddHere(index))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OwningQPointer<QMenu> menu = new QMenu(this);
|
OwningQPointer<QMenu> menu = new QMenu(this);
|
||||||
QAction *toggleTransitAct = menu->addAction(tr("Toggle transit"));
|
QAction *toggleTransitAct = menu->addAction(tr("Toggle transit"));
|
||||||
QAction *setToTransitAct = menu->addAction(tr("Set transit"));
|
QAction *setToTransitAct = menu->addAction(tr("Set transit"));
|
||||||
QAction *unsetTransit = menu->addAction(tr("Unset transit"));
|
QAction *unsetTransit = menu->addAction(tr("Unset transit"));
|
||||||
menu->insertSeparator(unsetTransit);
|
menu->insertSeparator(unsetTransit);
|
||||||
QAction *editStopAct = menu->addAction(tr("Edit stop"));
|
QAction *editStopAct = menu->addAction(tr("Edit stop"));
|
||||||
QAction *showStationSVG = menu->addAction(tr("Station SVG Plan"));
|
QAction *showStationSVG = menu->addAction(tr("Station SVG Plan"));
|
||||||
menu->insertSeparator(editStopAct);
|
menu->insertSeparator(editStopAct);
|
||||||
QAction *removeStopAct = menu->addAction(tr("Remove"));
|
QAction *removeStopAct = menu->addAction(tr("Remove"));
|
||||||
|
@ -296,24 +300,24 @@ void JobPathEditor::showStopsContextMenu(const QPoint& pos)
|
||||||
removeStopAct->setEnabled(!m_readOnly);
|
removeStopAct->setEnabled(!m_readOnly);
|
||||||
|
|
||||||
const StopItem stop = stopModel->getItemAt(index.row());
|
const StopItem stop = stopModel->getItemAt(index.row());
|
||||||
showStationSVG->setEnabled(stop.stationId != 0); //Enable only if station is set
|
showStationSVG->setEnabled(stop.stationId != 0); // Enable only if station is set
|
||||||
|
|
||||||
QAction *act = menu->exec(ui->stopsView->viewport()->mapToGlobal(pos));
|
QAction *act = menu->exec(ui->stopsView->viewport()->mapToGlobal(pos));
|
||||||
|
|
||||||
QItemSelectionModel *sm = ui->stopsView->selectionModel();
|
QItemSelectionModel *sm = ui->stopsView->selectionModel();
|
||||||
|
|
||||||
QItemSelectionRange range;
|
QItemSelectionRange range;
|
||||||
QItemSelection s = ui->stopsView->selectionModel()->selection();
|
QItemSelection s = ui->stopsView->selectionModel()->selection();
|
||||||
if(s.count() > 0)
|
if (s.count() > 0)
|
||||||
{
|
{
|
||||||
//Take the first range only
|
// Take the first range only
|
||||||
range = s.at(0); //Save range for later
|
range = s.at(0); // Save range for later
|
||||||
}
|
}
|
||||||
|
|
||||||
//Select only 1 index
|
// Select only 1 index
|
||||||
sm->select(index, QItemSelectionModel::ClearAndSelect);
|
sm->select(index, QItemSelectionModel::ClearAndSelect);
|
||||||
|
|
||||||
if(act == editStopAct)
|
if (act == editStopAct)
|
||||||
{
|
{
|
||||||
OwningQPointer<EditStopDialog> dlg = new EditStopDialog(stopModel, this);
|
OwningQPointer<EditStopDialog> dlg = new EditStopDialog(stopModel, this);
|
||||||
dlg->setReadOnly(m_readOnly);
|
dlg->setReadOnly(m_readOnly);
|
||||||
|
@ -322,86 +326,87 @@ void JobPathEditor::showStopsContextMenu(const QPoint& pos)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(act == showStationSVG)
|
if (act == showStationSVG)
|
||||||
{
|
{
|
||||||
Session->getViewManager()->requestStSVGPlan(stop.stationId, true, stop.arrival);
|
Session->getViewManager()->requestStSVGPlan(stop.stationId, true, stop.arrival);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_readOnly)
|
if (m_readOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(range.isValid())
|
if (range.isValid())
|
||||||
{
|
{
|
||||||
StopType type = StopType::ToggleType;
|
StopType type = StopType::ToggleType;
|
||||||
bool useRange = true;
|
bool useRange = true;
|
||||||
if(act == toggleTransitAct)
|
if (act == toggleTransitAct)
|
||||||
type = StopType::ToggleType;
|
type = StopType::ToggleType;
|
||||||
else if(act == setToTransitAct)
|
else if (act == setToTransitAct)
|
||||||
type = StopType::Transit;
|
type = StopType::Transit;
|
||||||
else if(act == unsetTransit)
|
else if (act == unsetTransit)
|
||||||
type = StopType::Normal;
|
type = StopType::Normal;
|
||||||
else
|
else
|
||||||
useRange = false;
|
useRange = false;
|
||||||
|
|
||||||
if(useRange)
|
if (useRange)
|
||||||
{
|
{
|
||||||
stopModel->setStopTypeRange(range.top(), range.bottom(), type);
|
stopModel->setStopTypeRange(range.top(), range.bottom(), type);
|
||||||
//Select only the range we changed (unselect possible other indexes)
|
// Select only the range we changed (unselect possible other indexes)
|
||||||
sm->select(QItemSelection(range.topLeft(), range.bottomRight()), QItemSelectionModel::ClearAndSelect);
|
sm->select(QItemSelection(range.topLeft(), range.bottomRight()),
|
||||||
|
QItemSelectionModel::ClearAndSelect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(act == removeStopAct)
|
if (act == removeStopAct)
|
||||||
{
|
{
|
||||||
stopModel->removeStop(index);
|
stopModel->removeStop(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobPathEditor::showJobContextMenu(const QPoint& pos)
|
void JobPathEditor::showJobContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
QTableView *jobView = qobject_cast<QTableView *>(sender());
|
QTableView *jobView = qobject_cast<QTableView *>(sender());
|
||||||
NextPrevRSJobsModel *jobModel = nextJobsModel;
|
NextPrevRSJobsModel *jobModel = nextJobsModel;
|
||||||
|
|
||||||
if(jobView == ui->prevJobsView)
|
if (jobView == ui->prevJobsView)
|
||||||
jobModel = prevJobsModel;
|
jobModel = prevJobsModel;
|
||||||
|
|
||||||
QModelIndex index = jobView->indexAt(pos);
|
QModelIndex index = jobView->indexAt(pos);
|
||||||
|
|
||||||
NextPrevRSJobsModel::Item item = jobModel->getItemAtRow(index.row());
|
NextPrevRSJobsModel::Item item = jobModel->getItemAtRow(index.row());
|
||||||
|
|
||||||
OwningQPointer<QMenu> menu = new QMenu(this);
|
OwningQPointer<QMenu> menu = new QMenu(this);
|
||||||
QAction *goToStop = menu->addAction(tr("Go to Stop"));
|
QAction *goToStop = menu->addAction(tr("Go to Stop"));
|
||||||
QAction *goToJob = menu->addAction(tr("Show Job"));
|
QAction *goToJob = menu->addAction(tr("Show Job"));
|
||||||
QAction *showRSPlan = menu->addAction(tr("Show RS Plan"));
|
QAction *showRSPlan = menu->addAction(tr("Show RS Plan"));
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
QAction *refreshViews = menu->addAction(tr("Refresh"));
|
QAction *refreshViews = menu->addAction(tr("Refresh"));
|
||||||
|
|
||||||
//Enable only if RS is not going to depot
|
// Enable only if RS is not going to depot
|
||||||
goToStop->setEnabled(index.isValid());
|
goToStop->setEnabled(index.isValid());
|
||||||
goToJob->setEnabled(index.isValid() && item.otherJobId != 0);
|
goToJob->setEnabled(index.isValid() && item.otherJobId != 0);
|
||||||
showRSPlan->setEnabled(index.isValid());
|
showRSPlan->setEnabled(index.isValid());
|
||||||
|
|
||||||
QAction *act = menu->exec(jobView->viewport()->mapToGlobal(pos));
|
QAction *act = menu->exec(jobView->viewport()->mapToGlobal(pos));
|
||||||
|
|
||||||
if(act == goToStop)
|
if (act == goToStop)
|
||||||
{
|
{
|
||||||
selectStop(item.stopId);
|
selectStop(item.stopId);
|
||||||
}
|
}
|
||||||
else if(act == goToJob)
|
else if (act == goToJob)
|
||||||
{
|
{
|
||||||
if(isEdited()) //Prevent selecting other job before saving
|
if (isEdited()) // Prevent selecting other job before saving
|
||||||
{
|
{
|
||||||
if(!maybeSave())
|
if (!maybeSave())
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Session->getViewManager()->requestJobSelection(item.otherJobId, true, true);
|
Session->getViewManager()->requestJobSelection(item.otherJobId, true, true);
|
||||||
}
|
}
|
||||||
else if(act == showRSPlan)
|
else if (act == showRSPlan)
|
||||||
{
|
{
|
||||||
Session->getViewManager()->requestRSInfo(item.rsId);
|
Session->getViewManager()->requestRSInfo(item.rsId);
|
||||||
}
|
}
|
||||||
else if(act == refreshViews)
|
else if (act == refreshViews)
|
||||||
{
|
{
|
||||||
prevJobsModel->refreshData();
|
prevJobsModel->refreshData();
|
||||||
nextJobsModel->refreshData();
|
nextJobsModel->refreshData();
|
||||||
|
@ -412,18 +417,18 @@ bool JobPathEditor::clearJob()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
if(!canSetJob)
|
if (!canSetJob)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(isEdited())
|
if (isEdited())
|
||||||
{
|
{
|
||||||
if(!maybeSave())
|
if (!maybeSave())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
isClear = true;
|
isClear = true;
|
||||||
|
|
||||||
//Reset color
|
// Reset color
|
||||||
ui->jobIdSpin->setPalette(QPalette());
|
ui->jobIdSpin->setPalette(QPalette());
|
||||||
|
|
||||||
stopModel->clearJob();
|
stopModel->clearJob();
|
||||||
|
@ -438,23 +443,23 @@ bool JobPathEditor::clearJob()
|
||||||
|
|
||||||
void JobPathEditor::done(int res)
|
void JobPathEditor::done(int res)
|
||||||
{
|
{
|
||||||
if(res == Accepted)
|
if (res == Accepted)
|
||||||
{
|
{
|
||||||
//Accepted: save changes
|
// Accepted: save changes
|
||||||
if(!saveChanges())
|
if (!saveChanges())
|
||||||
return; //Give user a second chance to edit job
|
return; // Give user a second chance to edit job
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Rejected: discard changes
|
// Rejected: discard changes
|
||||||
discardChanges();
|
discardChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: if we call QDialog::done() the dialog is closed and QDockWidget remains open but empty
|
// NOTE: if we call QDialog::done() the dialog is closed and QDockWidget remains open but empty
|
||||||
setResult(res);
|
setResult(res);
|
||||||
if(res == QDialog::Accepted)
|
if (res == QDialog::Accepted)
|
||||||
emit accepted();
|
emit accepted();
|
||||||
else if(res == QDialog::Rejected)
|
else if (res == QDialog::Rejected)
|
||||||
emit rejected();
|
emit rejected();
|
||||||
emit finished(res);
|
emit finished(res);
|
||||||
}
|
}
|
||||||
|
@ -463,7 +468,7 @@ bool JobPathEditor::saveChanges()
|
||||||
{
|
{
|
||||||
DEBUG_IMPORTANT_ENTRY;
|
DEBUG_IMPORTANT_ENTRY;
|
||||||
|
|
||||||
if(!canSetJob)
|
if (!canSetJob)
|
||||||
return false;
|
return false;
|
||||||
canSetJob = false;
|
canSetJob = false;
|
||||||
|
|
||||||
|
@ -474,15 +479,14 @@ bool JobPathEditor::saveChanges()
|
||||||
stopModel->removeLastIfEmpty();
|
stopModel->removeLastIfEmpty();
|
||||||
stopModel->uncoupleStillCoupledAtLastStop();
|
stopModel->uncoupleStillCoupledAtLastStop();
|
||||||
|
|
||||||
if(stopModel->rowCount() < 3) //At least 2 stops + AddHere
|
if (stopModel->rowCount() < 3) // At least 2 stops + AddHere
|
||||||
{
|
{
|
||||||
int res = QMessageBox::warning(this,
|
int res = QMessageBox::warning(this, tr("Error"),
|
||||||
tr("Error"),
|
|
||||||
tr("You must register at least 2 stops.\n"
|
tr("You must register at least 2 stops.\n"
|
||||||
"Do you want to delete this job?"),
|
"Do you want to delete this job?"),
|
||||||
QMessageBox::Yes | QMessageBox::No);
|
QMessageBox::Yes | QMessageBox::No);
|
||||||
|
|
||||||
if(res == QMessageBox::Yes)
|
if (res == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
qDebug() << "User wants to delete job:" << stopModel->getJobId();
|
qDebug() << "User wants to delete job:" << stopModel->getJobId();
|
||||||
stopModel->commitChanges();
|
stopModel->commitChanges();
|
||||||
|
@ -494,19 +498,18 @@ bool JobPathEditor::saveChanges()
|
||||||
}
|
}
|
||||||
canSetJob = true;
|
canSetJob = true;
|
||||||
|
|
||||||
return false; //Give user a second chance
|
return false; // Give user a second chance
|
||||||
}
|
}
|
||||||
|
|
||||||
//Re-check shift because user may have added stops so this job could last longer!
|
// Re-check shift because user may have added stops so this job could last longer!
|
||||||
if(stopModel->getNewShiftId())
|
if (stopModel->getNewShiftId())
|
||||||
{
|
{
|
||||||
auto times = stopModel->getFirstLastTimes();
|
auto times = stopModel->getFirstLastTimes();
|
||||||
|
|
||||||
ShiftBusyModel model(Session->m_Db);
|
ShiftBusyModel model(Session->m_Db);
|
||||||
model.loadData(stopModel->getNewShiftId(),
|
model.loadData(stopModel->getNewShiftId(), stopModel->getJobId(), times.first,
|
||||||
stopModel->getJobId(),
|
times.second);
|
||||||
times.first, times.second);
|
if (model.hasConcurrentJobs())
|
||||||
if(model.hasConcurrentJobs())
|
|
||||||
{
|
{
|
||||||
OwningQPointer<ShiftBusyDlg> dlg = new ShiftBusyDlg(this);
|
OwningQPointer<ShiftBusyDlg> dlg = new ShiftBusyDlg(this);
|
||||||
dlg->setModel(&model);
|
dlg->setModel(&model);
|
||||||
|
@ -525,7 +528,7 @@ bool JobPathEditor::saveChanges()
|
||||||
prevJobsModel->setJobId(newJobId);
|
prevJobsModel->setJobId(newJobId);
|
||||||
nextJobsModel->setJobId(newJobId);
|
nextJobsModel->setJobId(newJobId);
|
||||||
|
|
||||||
//When updating the path selection gets cleared so we restore it
|
// When updating the path selection gets cleared so we restore it
|
||||||
Session->getViewManager()->requestJobSelection(newJobId, true, true);
|
Session->getViewManager()->requestJobSelection(newJobId, true, true);
|
||||||
|
|
||||||
canSetJob = true;
|
canSetJob = true;
|
||||||
|
@ -536,28 +539,29 @@ void JobPathEditor::discardChanges()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
if(!canSetJob)
|
if (!canSetJob)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canSetJob = false;
|
canSetJob = false;
|
||||||
|
|
||||||
closeStopEditor(); //Close before rolling savepoint
|
closeStopEditor(); // Close before rolling savepoint
|
||||||
|
|
||||||
stopJobNumberTimer();
|
stopJobNumberTimer();
|
||||||
|
|
||||||
stopModel->revertChanges(); //Re-load old job from db
|
stopModel->revertChanges(); // Re-load old job from db
|
||||||
|
|
||||||
//After re-load but before possible 'clearJob()' (Below)
|
// After re-load but before possible 'clearJob()' (Below)
|
||||||
//Because this hides 'AddHere' so after 'loadJobStops()'
|
// Because this hides 'AddHere' so after 'loadJobStops()'
|
||||||
//Before 'clearJob()' because sets isEdited = false and
|
// Before 'clearJob()' because sets isEdited = false and
|
||||||
//'maybeSave()' doesn't be called in an infinite loop
|
//'maybeSave()' doesn't be called in an infinite loop
|
||||||
|
|
||||||
canSetJob = true;
|
canSetJob = true;
|
||||||
|
|
||||||
if(stopModel->rowCount() < 3) //At least 2 stops + AddHere
|
if (stopModel->rowCount() < 3) // At least 2 stops + AddHere
|
||||||
{
|
{
|
||||||
//User discarded an invalid job so we delete it
|
// User discarded an invalid job so we delete it
|
||||||
//This usually happens when you create a new job but then you change your mind and press 'Discard'
|
// This usually happens when you create a new job but then you change your mind and press
|
||||||
|
// 'Discard'
|
||||||
qDebug() << "User wants to delete job:" << stopModel->getJobId();
|
qDebug() << "User wants to delete job:" << stopModel->getJobId();
|
||||||
stopModel->commitChanges();
|
stopModel->commitChanges();
|
||||||
JobsHelper::removeJob(Session->m_Db, stopModel->getJobId());
|
JobsHelper::removeJob(Session->m_Db, stopModel->getJobId());
|
||||||
|
@ -574,11 +578,9 @@ db_id JobPathEditor::currentJobId() const
|
||||||
bool JobPathEditor::maybeSave()
|
bool JobPathEditor::maybeSave()
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
QMessageBox::StandardButton ret = QMessageBox::question(this,
|
QMessageBox::StandardButton ret = QMessageBox::question(
|
||||||
tr("Save?"),
|
this, tr("Save?"), tr("Do you want to save changes to job %1").arg(stopModel->getJobId()),
|
||||||
tr("Do you want to save changes to job %1")
|
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||||
.arg(stopModel->getJobId()),
|
|
||||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
|
||||||
switch (ret)
|
switch (ret)
|
||||||
{
|
{
|
||||||
case QMessageBox::Yes:
|
case QMessageBox::Yes:
|
||||||
|
@ -594,7 +596,7 @@ bool JobPathEditor::maybeSave()
|
||||||
|
|
||||||
void JobPathEditor::updateSpinColor()
|
void JobPathEditor::updateSpinColor()
|
||||||
{
|
{
|
||||||
if(!isClear)
|
if (!isClear)
|
||||||
{
|
{
|
||||||
QColor col = Session->colorForCat(stopModel->getCategory());
|
QColor col = Session->colorForCat(stopModel->getCategory());
|
||||||
setSpinColor(col);
|
setSpinColor(col);
|
||||||
|
@ -603,7 +605,7 @@ void JobPathEditor::updateSpinColor()
|
||||||
|
|
||||||
void JobPathEditor::timerEvent(QTimerEvent *e)
|
void JobPathEditor::timerEvent(QTimerEvent *e)
|
||||||
{
|
{
|
||||||
if(e->timerId() == jobNumberTimerId)
|
if (e->timerId() == jobNumberTimerId)
|
||||||
{
|
{
|
||||||
checkJobNumberValid();
|
checkJobNumberValid();
|
||||||
return;
|
return;
|
||||||
|
@ -614,10 +616,10 @@ void JobPathEditor::timerEvent(QTimerEvent *e)
|
||||||
|
|
||||||
void JobPathEditor::onJobRemoved(db_id jobId)
|
void JobPathEditor::onJobRemoved(db_id jobId)
|
||||||
{
|
{
|
||||||
//If the job shown is about to be removed clear JobPathEditor
|
// If the job shown is about to be removed clear JobPathEditor
|
||||||
if(stopModel->getJobId() == jobId)
|
if (stopModel->getJobId() == jobId)
|
||||||
{
|
{
|
||||||
if(clearJob())
|
if (clearJob())
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -627,7 +629,7 @@ void JobPathEditor::onJobIdChanged(db_id jobId)
|
||||||
ui->jobIdSpin->setValue(int(jobId));
|
ui->jobIdSpin->setValue(int(jobId));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobPathEditor::setSpinColor(const QColor& col)
|
void JobPathEditor::setSpinColor(const QColor &col)
|
||||||
{
|
{
|
||||||
QPalette pal = ui->jobIdSpin->palette();
|
QPalette pal = ui->jobIdSpin->palette();
|
||||||
pal.setColor(QPalette::Text, col);
|
pal.setColor(QPalette::Text, col);
|
||||||
|
@ -644,15 +646,13 @@ void JobPathEditor::onJobShiftChanged(db_id shiftId)
|
||||||
{
|
{
|
||||||
shiftCombo->setData(shiftId);
|
shiftCombo->setData(shiftId);
|
||||||
|
|
||||||
if(shiftId)
|
if (shiftId)
|
||||||
{
|
{
|
||||||
auto times = stopModel->getFirstLastTimes();
|
auto times = stopModel->getFirstLastTimes();
|
||||||
|
|
||||||
ShiftBusyModel model(Session->m_Db);
|
ShiftBusyModel model(Session->m_Db);
|
||||||
model.loadData(shiftId,
|
model.loadData(shiftId, stopModel->getJobId(), times.first, times.second);
|
||||||
stopModel->getJobId(),
|
if (model.hasConcurrentJobs())
|
||||||
times.first, times.second);
|
|
||||||
if(model.hasConcurrentJobs())
|
|
||||||
{
|
{
|
||||||
OwningQPointer<ShiftBusyDlg> dlg = new ShiftBusyDlg(this);
|
OwningQPointer<ShiftBusyDlg> dlg = new ShiftBusyDlg(this);
|
||||||
dlg->setModel(&model);
|
dlg->setModel(&model);
|
||||||
|
@ -667,8 +667,7 @@ void JobPathEditor::onJobShiftChanged(db_id shiftId)
|
||||||
|
|
||||||
void JobPathEditor::onShiftError()
|
void JobPathEditor::onShiftError()
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this,
|
QMessageBox::warning(this, tr("Empty Job"),
|
||||||
tr("Empty Job"),
|
|
||||||
tr("Before setting a shift you should add stops to this job"),
|
tr("Before setting a shift you should add stops to this job"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
}
|
}
|
||||||
|
@ -686,7 +685,7 @@ void JobPathEditor::setEdited(bool val)
|
||||||
|
|
||||||
void JobPathEditor::setReadOnly(bool readOnly)
|
void JobPathEditor::setReadOnly(bool readOnly)
|
||||||
{
|
{
|
||||||
if(m_readOnly == readOnly)
|
if (m_readOnly == readOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_readOnly = readOnly;
|
m_readOnly = readOnly;
|
||||||
|
@ -697,12 +696,12 @@ void JobPathEditor::setReadOnly(bool readOnly)
|
||||||
|
|
||||||
ui->buttonBox->setVisible(!m_readOnly);
|
ui->buttonBox->setVisible(!m_readOnly);
|
||||||
|
|
||||||
//If read-only hide 'AddHere' row (last one)
|
// If read-only hide 'AddHere' row (last one)
|
||||||
int size = stopModel->rowCount();
|
int size = stopModel->rowCount();
|
||||||
if(size > 0)
|
if (size > 0)
|
||||||
ui->stopsView->setRowHidden(size - 1, m_readOnly);
|
ui->stopsView->setRowHidden(size - 1, m_readOnly);
|
||||||
|
|
||||||
if(m_readOnly)
|
if (m_readOnly)
|
||||||
{
|
{
|
||||||
ui->stopsView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
ui->stopsView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
}
|
}
|
||||||
|
@ -716,7 +715,7 @@ void JobPathEditor::onSaveSheet()
|
||||||
{
|
{
|
||||||
const QLatin1String job_sheet_key = QLatin1String("job_sheet_dir");
|
const QLatin1String job_sheet_key = QLatin1String("job_sheet_dir");
|
||||||
|
|
||||||
OwningQPointer<QFileDialog> dlg = new QFileDialog(this, tr("Save Job Sheet"));
|
OwningQPointer<QFileDialog> dlg = new QFileDialog(this, tr("Save Job Sheet"));
|
||||||
dlg->setFileMode(QFileDialog::AnyFile);
|
dlg->setFileMode(QFileDialog::AnyFile);
|
||||||
dlg->setAcceptMode(QFileDialog::AcceptSave);
|
dlg->setAcceptMode(QFileDialog::AcceptSave);
|
||||||
dlg->setDirectory(RecentDirStore::getDir(job_sheet_key, RecentDirStore::Documents));
|
dlg->setDirectory(RecentDirStore::getDir(job_sheet_key, RecentDirStore::Documents));
|
||||||
|
@ -726,12 +725,12 @@ void JobPathEditor::onSaveSheet()
|
||||||
filters << FileFormats::tr(FileFormats::odtFormat);
|
filters << FileFormats::tr(FileFormats::odtFormat);
|
||||||
dlg->setNameFilters(filters);
|
dlg->setNameFilters(filters);
|
||||||
|
|
||||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||||
|
|
||||||
if(fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RecentDirStore::setPath(job_sheet_key, fileName);
|
RecentDirStore::setPath(job_sheet_key, fileName);
|
||||||
|
@ -743,14 +742,14 @@ void JobPathEditor::onSaveSheet()
|
||||||
utils::OpenFileInFolderDlg::askUser(tr("Job Sheet Saved"), fileName, this);
|
utils::OpenFileInFolderDlg::askUser(tr("Job Sheet Saved"), fileName, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobPathEditor::onStopIndexClicked(const QModelIndex& index)
|
void JobPathEditor::onStopIndexClicked(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
DEBUG_ENTRY;
|
DEBUG_ENTRY;
|
||||||
|
|
||||||
if(m_readOnly)
|
if (m_readOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(stopModel->isAddHere(index))
|
if (stopModel->isAddHere(index))
|
||||||
{
|
{
|
||||||
qDebug() << index << "AddHere";
|
qDebug() << index << "AddHere";
|
||||||
|
|
||||||
|
@ -758,22 +757,22 @@ void JobPathEditor::onStopIndexClicked(const QModelIndex& index)
|
||||||
|
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
|
|
||||||
if(row > 0)
|
if (row > 0)
|
||||||
{
|
{
|
||||||
//idx - 1 is former Last Stop (now it became a normal Stop)
|
// idx - 1 is former Last Stop (now it became a normal Stop)
|
||||||
//idx is new Last Stop (former AddHere)
|
// idx is new Last Stop (former AddHere)
|
||||||
//idx + 1 is the new AddHere
|
// idx + 1 is the new AddHere
|
||||||
|
|
||||||
//Edit former Last Stop
|
// Edit former Last Stop
|
||||||
QModelIndex prev = stopModel->index(row - 1, 0);
|
QModelIndex prev = stopModel->index(row - 1, 0);
|
||||||
ui->stopsView->setCurrentIndex(prev);
|
ui->stopsView->setCurrentIndex(prev);
|
||||||
ui->stopsView->scrollTo(prev);
|
ui->stopsView->scrollTo(prev);
|
||||||
ui->stopsView->edit(prev);
|
ui->stopsView->edit(prev);
|
||||||
|
|
||||||
//Tell editor to popup lines combo
|
// Tell editor to popup lines combo
|
||||||
//QAbstractItemView::edit doesn't let you pass additional arguments
|
// QAbstractItemView::edit doesn't let you pass additional arguments
|
||||||
//So we work around by emitting a signal
|
// So we work around by emitting a signal
|
||||||
//See 'StopDelegate::createEditor()'
|
// See 'StopDelegate::createEditor()'
|
||||||
emit delegate->popupEditorSegmentCombo();
|
emit delegate->popupEditorSegmentCombo();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -794,8 +793,8 @@ bool JobPathEditor::getCanSetJob() const
|
||||||
void JobPathEditor::closeStopEditor()
|
void JobPathEditor::closeStopEditor()
|
||||||
{
|
{
|
||||||
QModelIndex idx = ui->stopsView->currentIndex();
|
QModelIndex idx = ui->stopsView->currentIndex();
|
||||||
QWidget *ed = ui->stopsView->indexWidget(idx);
|
QWidget *ed = ui->stopsView->indexWidget(idx);
|
||||||
if(ed == nullptr)
|
if (ed == nullptr)
|
||||||
return;
|
return;
|
||||||
emit delegate->commitData(ed);
|
emit delegate->commitData(ed);
|
||||||
emit delegate->closeEditor(ed);
|
emit delegate->closeEditor(ed);
|
||||||
|
@ -803,10 +802,10 @@ void JobPathEditor::closeStopEditor()
|
||||||
|
|
||||||
void JobPathEditor::closeEvent(QCloseEvent *e)
|
void JobPathEditor::closeEvent(QCloseEvent *e)
|
||||||
{
|
{
|
||||||
//TODO: prevent QDockWidget closing even if we ignore this event
|
// TODO: prevent QDockWidget closing even if we ignore this event
|
||||||
if(isEdited())
|
if (isEdited())
|
||||||
{
|
{
|
||||||
if(maybeSave())
|
if (maybeSave())
|
||||||
e->accept();
|
e->accept();
|
||||||
else
|
else
|
||||||
e->ignore();
|
e->ignore();
|
||||||
|
@ -820,7 +819,7 @@ void JobPathEditor::closeEvent(QCloseEvent *e)
|
||||||
void JobPathEditor::selectStop(db_id stopId)
|
void JobPathEditor::selectStop(db_id stopId)
|
||||||
{
|
{
|
||||||
int row = stopModel->getStopRow(stopId);
|
int row = stopModel->getStopRow(stopId);
|
||||||
if(row >= 0)
|
if (row >= 0)
|
||||||
{
|
{
|
||||||
QModelIndex idx = stopModel->index(row, 0);
|
QModelIndex idx = stopModel->index(row, 0);
|
||||||
ui->stopsView->setCurrentIndex(idx);
|
ui->stopsView->setCurrentIndex(idx);
|
||||||
|
|
|
@ -48,7 +48,7 @@ class JobPathEditor : public QDialog
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit JobPathEditor(QWidget *parent = nullptr);
|
explicit JobPathEditor(QWidget *parent = nullptr);
|
||||||
~JobPathEditor()override;
|
~JobPathEditor() override;
|
||||||
|
|
||||||
bool setJob(db_id jobId);
|
bool setJob(db_id jobId);
|
||||||
bool createNewJob(db_id *out = nullptr);
|
bool createNewJob(db_id *out = nullptr);
|
||||||
|
@ -122,10 +122,10 @@ private:
|
||||||
|
|
||||||
int jobNumberTimerId;
|
int jobNumberTimerId;
|
||||||
|
|
||||||
//TODO: there are too many bools
|
// TODO: there are too many bools
|
||||||
bool isClear;
|
bool isClear;
|
||||||
|
|
||||||
bool canSetJob; //TODO: better name
|
bool canSetJob; // TODO: better name
|
||||||
bool m_readOnly;
|
bool m_readOnly;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ JobPassingsModel::JobPassingsModel(QObject *parent) :
|
||||||
|
|
||||||
QVariant JobPassingsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant JobPassingsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
{
|
{
|
||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
|
@ -71,7 +71,7 @@ QVariant JobPassingsModel::data(const QModelIndex &idx, int role) const
|
||||||
if (!idx.isValid() || idx.row() >= m_data.size() || idx.column() >= NCols)
|
if (!idx.isValid() || idx.row() >= m_data.size() || idx.column() >= NCols)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
const Entry& e = m_data.at(idx.row());
|
const Entry &e = m_data.at(idx.row());
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
|
@ -97,7 +97,7 @@ QVariant JobPassingsModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
QFont f;
|
QFont f;
|
||||||
f.setPointSize(10);
|
f.setPointSize(10);
|
||||||
if(idx.column() == JobNameCol)
|
if (idx.column() == JobNameCol)
|
||||||
f.setBold(true);
|
f.setBold(true);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@ class JobPassingsModel : public QAbstractTableModel
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Columns {
|
enum Columns
|
||||||
|
{
|
||||||
JobNameCol = 0,
|
JobNameCol = 0,
|
||||||
ArrivalCol,
|
ArrivalCol,
|
||||||
DepartureCol,
|
DepartureCol,
|
||||||
|
@ -60,7 +61,7 @@ public:
|
||||||
|
|
||||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
void setJobs(const QVector<Entry>& vec);
|
void setJobs(const QVector<Entry> &vec);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<Entry> m_data;
|
QVector<Entry> m_data;
|
||||||
|
|
|
@ -34,7 +34,7 @@ NextPrevRSJobsModel::NextPrevRSJobsModel(sqlite3pp::database &db, QObject *paren
|
||||||
|
|
||||||
QVariant NextPrevRSJobsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant NextPrevRSJobsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
{
|
{
|
||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ QVariant NextPrevRSJobsModel::data(const QModelIndex &idx, int role) const
|
||||||
if (!idx.isValid() || idx.row() >= m_data.size() || idx.column() >= NCols)
|
if (!idx.isValid() || idx.row() >= m_data.size() || idx.column() >= NCols)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
const Item& item = m_data.at(idx.row());
|
const Item &item = m_data.at(idx.row());
|
||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
|
@ -77,8 +77,8 @@ QVariant NextPrevRSJobsModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
case JobIdCol:
|
case JobIdCol:
|
||||||
{
|
{
|
||||||
if(item.otherJobCat == JobCategory::NCategories)
|
if (item.otherJobCat == JobCategory::NCategories)
|
||||||
return tr("Depot"); //Rollingstock item taken from/released to depot
|
return tr("Depot"); // Rollingstock item taken from/released to depot
|
||||||
return JobCategoryName::jobName(item.otherJobId, item.otherJobCat);
|
return JobCategoryName::jobName(item.otherJobId, item.otherJobCat);
|
||||||
}
|
}
|
||||||
case RsNameCol:
|
case RsNameCol:
|
||||||
|
@ -90,9 +90,9 @@ QVariant NextPrevRSJobsModel::data(const QModelIndex &idx, int role) const
|
||||||
}
|
}
|
||||||
case Qt::FontRole:
|
case Qt::FontRole:
|
||||||
{
|
{
|
||||||
if(idx.column() == JobIdCol && item.otherJobCat == JobCategory::NCategories)
|
if (idx.column() == JobIdCol && item.otherJobCat == JobCategory::NCategories)
|
||||||
{
|
{
|
||||||
//Rollingstock item taken from/released to depot, distinguish font from job names
|
// Rollingstock item taken from/released to depot, distinguish font from job names
|
||||||
QFont f;
|
QFont f;
|
||||||
f.setItalic(true);
|
f.setItalic(true);
|
||||||
return f;
|
return f;
|
||||||
|
@ -108,34 +108,38 @@ QVariant NextPrevRSJobsModel::data(const QModelIndex &idx, int role) const
|
||||||
|
|
||||||
void NextPrevRSJobsModel::refreshData()
|
void NextPrevRSJobsModel::refreshData()
|
||||||
{
|
{
|
||||||
//GROUP by rollingstock
|
// GROUP by rollingstock
|
||||||
QByteArray sql = "SELECT c.id, c.rs_id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type, stops.%time0,"
|
QByteArray sql =
|
||||||
" %min(s1.%time0), stops.id, s1.job_id AS job_id, j1.category"
|
"SELECT c.id, c.rs_id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type, "
|
||||||
" FROM stops"
|
"stops.%time0,"
|
||||||
" JOIN coupling c ON c.stop_id=stops.id"
|
" %min(s1.%time0), stops.id, s1.job_id AS job_id, j1.category"
|
||||||
" JOIN rs_list ON rs_list.id=c.rs_id"
|
" FROM stops"
|
||||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
" JOIN coupling c ON c.stop_id=stops.id"
|
||||||
" LEFT JOIN coupling c1 ON c1.rs_id=c.rs_id"
|
" JOIN rs_list ON rs_list.id=c.rs_id"
|
||||||
" LEFT JOIN stops s1 ON s1.id=c1.stop_id"
|
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||||
" LEFT JOIN jobs j1 ON j1.id=s1.job_id"
|
" LEFT JOIN coupling c1 ON c1.rs_id=c.rs_id"
|
||||||
" WHERE stops.job_id=?1 AND c.operation=%rem AND c1.operation=%add AND s1.%time0 %gt stops.%time1"
|
" LEFT JOIN stops s1 ON s1.id=c1.stop_id"
|
||||||
" GROUP BY c.rs_id"
|
" LEFT JOIN jobs j1 ON j1.id=s1.job_id"
|
||||||
" UNION ALL "
|
" WHERE stops.job_id=?1 AND c.operation=%rem AND c1.operation=%add AND s1.%time0 %gt "
|
||||||
"SELECT c.id, c.rs_id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type, stops.%time0,"
|
"stops.%time1"
|
||||||
" %max(s1.%time0), stops.id, NULL AS job_id, NULL"
|
" GROUP BY c.rs_id"
|
||||||
" FROM stops"
|
" UNION ALL "
|
||||||
" JOIN coupling c ON c.stop_id=stops.id"
|
"SELECT c.id, c.rs_id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type, "
|
||||||
" JOIN rs_list ON rs_list.id=c.rs_id"
|
"stops.%time0,"
|
||||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
" %max(s1.%time0), stops.id, NULL AS job_id, NULL"
|
||||||
" LEFT JOIN coupling c1 ON c1.rs_id=c.rs_id"
|
" FROM stops"
|
||||||
" LEFT JOIN stops s1 ON s1.id=c1.stop_id"
|
" JOIN coupling c ON c.stop_id=stops.id"
|
||||||
" WHERE stops.job_id=?1 AND c.operation=%rem AND c1.operation=%add"
|
" JOIN rs_list ON rs_list.id=c.rs_id"
|
||||||
" GROUP BY c.rs_id"
|
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||||
" HAVING s1.%time1 %lt stops.%time0"
|
" LEFT JOIN coupling c1 ON c1.rs_id=c.rs_id"
|
||||||
" ORDER BY stops.%time0, job_id, rs_models.type, rs_models.name, rs_list.number"
|
" LEFT JOIN stops s1 ON s1.id=c1.stop_id"
|
||||||
" LIMIT 100";
|
" WHERE stops.job_id=?1 AND c.operation=%rem AND c1.operation=%add"
|
||||||
|
" GROUP BY c.rs_id"
|
||||||
|
" HAVING s1.%time1 %lt stops.%time0"
|
||||||
|
" ORDER BY stops.%time0, job_id, rs_models.type, rs_models.name, rs_list.number"
|
||||||
|
" LIMIT 100";
|
||||||
|
|
||||||
if(m_mode == NextJobs)
|
if (m_mode == NextJobs)
|
||||||
{
|
{
|
||||||
sql.replace("%time0", "arrival");
|
sql.replace("%time0", "arrival");
|
||||||
sql.replace("%time1", "departure");
|
sql.replace("%time1", "departure");
|
||||||
|
@ -148,7 +152,7 @@ void NextPrevRSJobsModel::refreshData()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Invert all
|
// Invert all
|
||||||
sql.replace("%time0", "departure");
|
sql.replace("%time0", "departure");
|
||||||
sql.replace("%time1", "arrival");
|
sql.replace("%time1", "arrival");
|
||||||
sql.replace("%min", "MAX");
|
sql.replace("%min", "MAX");
|
||||||
|
@ -194,33 +198,29 @@ void NextPrevRSJobsModel::refreshData()
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_data.clear();
|
m_data.clear();
|
||||||
|
|
||||||
for(auto row : q)
|
for (auto row : q)
|
||||||
{
|
{
|
||||||
Item item;
|
Item item;
|
||||||
item.couplingId = row.get<db_id>(0);
|
item.couplingId = row.get<db_id>(0);
|
||||||
item.rsId = row.get<db_id>(1);
|
item.rsId = row.get<db_id>(1);
|
||||||
|
|
||||||
int number = row.get<int>(2);
|
int number = row.get<int>(2);
|
||||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 3);
|
int modelNameLen = sqlite3_column_bytes(q.stmt(), 3);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 3));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 3));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 4);
|
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 4);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 4));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 4));
|
||||||
RsType rsType = RsType(row.get<int>(5));
|
RsType rsType = RsType(row.get<int>(5));
|
||||||
|
|
||||||
item.rsName = rs_utils::formatNameRef(modelName,
|
item.rsName = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||||
modelNameLen,
|
modelSuffixLen, rsType);
|
||||||
number,
|
|
||||||
modelSuffix,
|
|
||||||
modelSuffixLen,
|
|
||||||
rsType);
|
|
||||||
|
|
||||||
item.opTime = row.get<QTime>(6);
|
item.opTime = row.get<QTime>(6);
|
||||||
//Ignore column 7, which is used just for MIN/MAX
|
// Ignore column 7, which is used just for MIN/MAX
|
||||||
item.stopId = row.get<db_id>(8);
|
item.stopId = row.get<db_id>(8);
|
||||||
item.otherJobId = row.get<db_id>(9);
|
item.otherJobId = row.get<db_id>(9);
|
||||||
item.otherJobCat = JobCategory(row.get<int>(10));
|
item.otherJobCat = JobCategory(row.get<int>(10));
|
||||||
if(row.column_type(10) == SQLITE_NULL)
|
if (row.column_type(10) == SQLITE_NULL)
|
||||||
item.otherJobCat = JobCategory::NCategories;
|
item.otherJobCat = JobCategory::NCategories;
|
||||||
|
|
||||||
m_data.append(item);
|
m_data.append(item);
|
||||||
|
@ -245,7 +245,7 @@ db_id NextPrevRSJobsModel::jobId() const
|
||||||
void NextPrevRSJobsModel::setJobId(db_id newJobId)
|
void NextPrevRSJobsModel::setJobId(db_id newJobId)
|
||||||
{
|
{
|
||||||
m_jobId = newJobId;
|
m_jobId = newJobId;
|
||||||
if(m_jobId)
|
if (m_jobId)
|
||||||
refreshData();
|
refreshData();
|
||||||
else
|
else
|
||||||
clearData();
|
clearData();
|
||||||
|
@ -259,7 +259,7 @@ NextPrevRSJobsModel::Mode NextPrevRSJobsModel::mode() const
|
||||||
void NextPrevRSJobsModel::setMode(Mode newMode)
|
void NextPrevRSJobsModel::setMode(Mode newMode)
|
||||||
{
|
{
|
||||||
m_mode = newMode;
|
m_mode = newMode;
|
||||||
if(m_jobId)
|
if (m_jobId)
|
||||||
refreshData();
|
refreshData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,8 @@ public:
|
||||||
{
|
{
|
||||||
db_id otherJobId = 0;
|
db_id otherJobId = 0;
|
||||||
db_id couplingId = 0;
|
db_id couplingId = 0;
|
||||||
db_id rsId = 0;
|
db_id rsId = 0;
|
||||||
db_id stopId = 0;
|
db_id stopId = 0;
|
||||||
|
|
||||||
QString rsName;
|
QString rsName;
|
||||||
QTime opTime;
|
QTime opTime;
|
||||||
|
@ -73,7 +73,8 @@ public:
|
||||||
NextPrevRSJobsModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
NextPrevRSJobsModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||||
|
|
||||||
// Header:
|
// Header:
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
// Basic functionality:
|
// Basic functionality:
|
||||||
int rowCount(const QModelIndex &p = QModelIndex()) const override;
|
int rowCount(const QModelIndex &p = QModelIndex()) const override;
|
||||||
|
@ -93,7 +94,6 @@ public:
|
||||||
Item getItemAtRow(int row) const;
|
Item getItemAtRow(int row) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
sqlite3pp::database &mDb;
|
sqlite3pp::database &mDb;
|
||||||
|
|
||||||
db_id m_jobId = 0;
|
db_id m_jobId = 0;
|
||||||
|
|
|
@ -39,16 +39,15 @@ RSCouplingInterface::RSCouplingInterface(database &db, QObject *parent) :
|
||||||
" coupling(stop_id,rs_id,operation)"
|
" coupling(stop_id,rs_id,operation)"
|
||||||
" VALUES(?, ?, ?)")
|
" VALUES(?, ?, ?)")
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSCouplingInterface::loadCouplings(StopModel *model, db_id stopId, db_id jobId, QTime arr)
|
void RSCouplingInterface::loadCouplings(StopModel *model, db_id stopId, db_id jobId, QTime arr)
|
||||||
{
|
{
|
||||||
stopsModel = model;
|
stopsModel = model;
|
||||||
|
|
||||||
m_stopId = stopId;
|
m_stopId = stopId;
|
||||||
m_jobId = jobId;
|
m_jobId = jobId;
|
||||||
arrival = arr;
|
arrival = arr;
|
||||||
|
|
||||||
coupled.clear();
|
coupled.clear();
|
||||||
uncoupled.clear();
|
uncoupled.clear();
|
||||||
|
@ -56,12 +55,12 @@ void RSCouplingInterface::loadCouplings(StopModel *model, db_id stopId, db_id jo
|
||||||
query q(mDb, "SELECT rs_id, operation FROM coupling WHERE stop_id=?");
|
query q(mDb, "SELECT rs_id, operation FROM coupling WHERE stop_id=?");
|
||||||
q.bind(1, m_stopId);
|
q.bind(1, m_stopId);
|
||||||
|
|
||||||
for(auto rs : q)
|
for (auto rs : q)
|
||||||
{
|
{
|
||||||
db_id rsId = rs.get<db_id>(0);
|
db_id rsId = rs.get<db_id>(0);
|
||||||
RsOp op = RsOp(rs.get<int>(1));
|
RsOp op = RsOp(rs.get<int>(1));
|
||||||
|
|
||||||
if(op == RsOp::Coupled)
|
if (op == RsOp::Coupled)
|
||||||
coupled.append(rsId);
|
coupled.append(rsId);
|
||||||
else
|
else
|
||||||
uncoupled.append(rsId);
|
uncoupled.append(rsId);
|
||||||
|
@ -70,20 +69,21 @@ void RSCouplingInterface::loadCouplings(StopModel *model, db_id stopId, db_id jo
|
||||||
|
|
||||||
bool RSCouplingInterface::contains(db_id rsId, RsOp op) const
|
bool RSCouplingInterface::contains(db_id rsId, RsOp op) const
|
||||||
{
|
{
|
||||||
if(op == RsOp::Coupled)
|
if (op == RsOp::Coupled)
|
||||||
return coupled.contains(rsId);
|
return coupled.contains(rsId);
|
||||||
else
|
else
|
||||||
return uncoupled.contains(rsId);
|
return uncoupled.contains(rsId);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, bool checkTractionType)
|
bool RSCouplingInterface::coupleRS(db_id rsId, const QString &rsName, bool on,
|
||||||
|
bool checkTractionType)
|
||||||
{
|
{
|
||||||
stopsModel->startStopsEditing();
|
stopsModel->startStopsEditing();
|
||||||
stopsModel->markRsToUpdate(rsId);
|
stopsModel->markRsToUpdate(rsId);
|
||||||
|
|
||||||
if(on)
|
if (on)
|
||||||
{
|
{
|
||||||
if(coupled.contains(rsId))
|
if (coupled.contains(rsId))
|
||||||
{
|
{
|
||||||
qWarning() << "Error already checked:" << rsId;
|
qWarning() << "Error already checked:" << rsId;
|
||||||
return true;
|
return true;
|
||||||
|
@ -99,78 +99,79 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
||||||
" AND stops.arrival<?");
|
" AND stops.arrival<?");
|
||||||
q_RS_lastOp.bind(1, rsId);
|
q_RS_lastOp.bind(1, rsId);
|
||||||
q_RS_lastOp.bind(2, arrival);
|
q_RS_lastOp.bind(2, arrival);
|
||||||
int ret = q_RS_lastOp.step();
|
int ret = q_RS_lastOp.step();
|
||||||
|
|
||||||
bool isOccupied = false; //No Op means RS is turned off in a depot so it isn't occupied
|
bool isOccupied = false; // No Op means RS is turned off in a depot so it isn't occupied
|
||||||
if(ret == SQLITE_ROW)
|
if (ret == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
auto row = q_RS_lastOp.getRows();
|
auto row = q_RS_lastOp.getRows();
|
||||||
RsOp operation = RsOp(row.get<int>(1)); //Get last operation
|
RsOp operation = RsOp(row.get<int>(1)); // Get last operation
|
||||||
jobId = row.get<db_id>(2);
|
jobId = row.get<db_id>(2);
|
||||||
isOccupied = (operation == RsOp::Coupled);
|
isOccupied = (operation == RsOp::Coupled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isOccupied)
|
if (isOccupied)
|
||||||
{
|
{
|
||||||
if(jobId == m_jobId)
|
if (jobId == m_jobId)
|
||||||
{
|
{
|
||||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId
|
qWarning() << "Error while adding coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||||
<< "Rs:" << rsId << "Already coupled by this job:" << m_jobId;
|
<< "Already coupled by this job:" << m_jobId;
|
||||||
|
|
||||||
QMessageBox::warning(qApp->activeWindow(),
|
QMessageBox::warning(qApp->activeWindow(), tr("Error"),
|
||||||
tr("Error"),
|
|
||||||
tr("Error while adding coupling operation.\n"
|
tr("Error while adding coupling operation.\n"
|
||||||
"Rollingstock %1 is already coupled by this job (%2)")
|
"Rollingstock %1 is already coupled by this job (%2)")
|
||||||
.arg(rsName).arg(m_jobId),
|
.arg(rsName)
|
||||||
|
.arg(m_jobId),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId
|
qWarning() << "Error while adding coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||||
<< "Rs:" << rsId << "Occupied by this job:" << jobId;
|
<< "Occupied by this job:" << jobId;
|
||||||
|
|
||||||
int but = QMessageBox::warning(qApp->activeWindow(),
|
int but =
|
||||||
tr("Error"),
|
QMessageBox::warning(qApp->activeWindow(), tr("Error"),
|
||||||
tr("Error while adding coupling operation.\n"
|
tr("Error while adding coupling operation.\n"
|
||||||
"Rollingstock %1 is already coupled to another job (%2)\n"
|
"Rollingstock %1 is already coupled to another job (%2)\n"
|
||||||
"Do you still want to couple it?")
|
"Do you still want to couple it?")
|
||||||
.arg(rsName).arg(jobId),
|
.arg(rsName)
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
.arg(jobId),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||||
|
|
||||||
if(but == QMessageBox::No)
|
if (but == QMessageBox::No)
|
||||||
return false; //Abort
|
return false; // Abort
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(checkTractionType && !stopsModel->isRailwayElectrifiedAfterStop(m_stopId))
|
if (checkTractionType && !stopsModel->isRailwayElectrifiedAfterStop(m_stopId))
|
||||||
{
|
{
|
||||||
//Query RS type
|
// Query RS type
|
||||||
query q_getRSType(mDb, "SELECT rs_models.type,rs_models.sub_type"
|
query q_getRSType(mDb, "SELECT rs_models.type,rs_models.sub_type"
|
||||||
" FROM rs_list"
|
" FROM rs_list"
|
||||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||||
" WHERE rs_list.id=?");
|
" WHERE rs_list.id=?");
|
||||||
q_getRSType.bind(1, rsId);
|
q_getRSType.bind(1, rsId);
|
||||||
if(q_getRSType.step() != SQLITE_ROW)
|
if (q_getRSType.step() != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
qWarning() << "RS seems to not exist, ID:" << rsId;
|
qWarning() << "RS seems to not exist, ID:" << rsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rs = q_getRSType.getRows();
|
auto rs = q_getRSType.getRows();
|
||||||
RsType type = RsType(rs.get<int>(0));
|
RsType type = RsType(rs.get<int>(0));
|
||||||
RsEngineSubType subType = RsEngineSubType(rs.get<int>(1));
|
RsEngineSubType subType = RsEngineSubType(rs.get<int>(1));
|
||||||
|
|
||||||
if(type == RsType::Engine && subType == RsEngineSubType::Electric)
|
if (type == RsType::Engine && subType == RsEngineSubType::Electric)
|
||||||
{
|
{
|
||||||
int but = QMessageBox::warning(qApp->activeWindow(),
|
int but = QMessageBox::warning(
|
||||||
tr("Warning"),
|
qApp->activeWindow(), tr("Warning"),
|
||||||
tr("Rollingstock %1 is an Electric engine but the line is not electrified\n"
|
tr("Rollingstock %1 is an Electric engine but the line is not electrified\n"
|
||||||
"This engine will not be albe to move a train.\n"
|
"This engine will not be albe to move a train.\n"
|
||||||
"Do you still want to couple it?")
|
"Do you still want to couple it?")
|
||||||
.arg(rsName),
|
.arg(rsName),
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||||
if(but == QMessageBox::No)
|
if (but == QMessageBox::No)
|
||||||
return false; //Cancel coupling operation
|
return false; // Cancel coupling operation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,44 +181,45 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
||||||
ret = q_addCoupling.execute();
|
ret = q_addCoupling.execute();
|
||||||
q_addCoupling.reset();
|
q_addCoupling.reset();
|
||||||
|
|
||||||
if(ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId
|
qWarning() << "Error while adding coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||||
<< "Rs:" << rsId << "Op: Coupled " << "Ret:" << ret
|
<< "Op: Coupled "
|
||||||
<< mDb.error_msg();
|
<< "Ret:" << ret << mDb.error_msg();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
coupled.append(rsId);
|
coupled.append(rsId);
|
||||||
|
|
||||||
//Check if there is a next coupling operation in the same job
|
// Check if there is a next coupling operation in the same job
|
||||||
query q(mDb, "SELECT s2.id, s2.arrival, s2.station_id, stations.name"
|
query q(mDb, "SELECT s2.id, s2.arrival, s2.station_id, stations.name"
|
||||||
" FROM coupling"
|
" FROM coupling"
|
||||||
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
||||||
" JOIN stops s1 ON s1.id=?"
|
" JOIN stops s1 ON s1.id=?"
|
||||||
" JOIN stations ON stations.id=s2.station_id"
|
" JOIN stations ON stations.id=s2.station_id"
|
||||||
" WHERE coupling.rs_id=? AND coupling.operation=? AND s1.job_id=s2.job_id AND s1.arrival < s2.arrival");
|
" WHERE coupling.rs_id=? AND coupling.operation=? AND s1.job_id=s2.job_id AND "
|
||||||
|
"s1.arrival < s2.arrival");
|
||||||
q.bind(1, m_stopId);
|
q.bind(1, m_stopId);
|
||||||
q.bind(2, rsId);
|
q.bind(2, rsId);
|
||||||
q.bind(3, int(RsOp::Coupled));
|
q.bind(3, int(RsOp::Coupled));
|
||||||
|
|
||||||
if(q.step() == SQLITE_ROW)
|
if (q.step() == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
auto r = q.getRows();
|
auto r = q.getRows();
|
||||||
db_id stopId = r.get<db_id>(0);
|
db_id stopId = r.get<db_id>(0);
|
||||||
QTime arr = r.get<QTime>(1);
|
QTime arr = r.get<QTime>(1);
|
||||||
db_id stId = r.get<db_id>(2);
|
db_id stId = r.get<db_id>(2);
|
||||||
QString stName = r.get<QString>(3);
|
QString stName = r.get<QString>(3);
|
||||||
|
|
||||||
qDebug() << "Found coupling, RS:" << rsId << "Stop:" << stopId << "St:" << stId << arr;
|
qDebug() << "Found coupling, RS:" << rsId << "Stop:" << stopId << "St:" << stId << arr;
|
||||||
|
|
||||||
int but = QMessageBox::question(qApp->activeWindow(),
|
int but =
|
||||||
tr("Delete coupling?"),
|
QMessageBox::question(qApp->activeWindow(), tr("Delete coupling?"),
|
||||||
tr("You couple %1 also in a next stop in %2 at %3.\n"
|
tr("You couple %1 also in a next stop in %2 at %3.\n"
|
||||||
"Do you want to remove the other coupling operation?")
|
"Do you want to remove the other coupling operation?")
|
||||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
if(but == QMessageBox::Yes)
|
if (but == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
qDebug() << "Deleting coupling";
|
qDebug() << "Deleting coupling";
|
||||||
|
|
||||||
|
@ -226,11 +228,11 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
||||||
ret = q_deleteCoupling.execute();
|
ret = q_deleteCoupling.execute();
|
||||||
q_deleteCoupling.reset();
|
q_deleteCoupling.reset();
|
||||||
|
|
||||||
if(ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "Error while deleting next coupling op. Stop:" << stopId
|
qWarning() << "Error while deleting next coupling op. Stop:" << stopId
|
||||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
<< "Rs:" << rsId << "Op: Uncoupled "
|
||||||
<< mDb.error_msg();
|
<< "Ret:" << ret << mDb.error_msg();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -242,7 +244,7 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int row = coupled.indexOf(rsId);
|
int row = coupled.indexOf(rsId);
|
||||||
if(row == -1)
|
if (row == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
q_deleteCoupling.bind(1, m_stopId);
|
q_deleteCoupling.bind(1, m_stopId);
|
||||||
|
@ -250,44 +252,46 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
||||||
int ret = q_deleteCoupling.execute();
|
int ret = q_deleteCoupling.execute();
|
||||||
q_deleteCoupling.reset();
|
q_deleteCoupling.reset();
|
||||||
|
|
||||||
if(ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "Error while deleting coupling op. Stop:" << m_stopId
|
qWarning() << "Error while deleting coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||||
<< "Rs:" << rsId << "Op: Coupled " << "Ret:" << ret
|
<< "Op: Coupled "
|
||||||
<< mDb.error_msg();
|
<< "Ret:" << ret << mDb.error_msg();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
coupled.removeAt(row);
|
coupled.removeAt(row);
|
||||||
|
|
||||||
//Check if there is a next uncoupling operation
|
// Check if there is a next uncoupling operation
|
||||||
query q(mDb, "SELECT s2.id, MIN(s2.arrival), s2.station_id, stations.name"
|
query q(mDb, "SELECT s2.id, MIN(s2.arrival), s2.station_id, stations.name"
|
||||||
" FROM coupling"
|
" FROM coupling"
|
||||||
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
||||||
" JOIN stops s1 ON s1.id=?"
|
" JOIN stops s1 ON s1.id=?"
|
||||||
" JOIN stations ON stations.id=s2.station_id"
|
" JOIN stations ON stations.id=s2.station_id"
|
||||||
" WHERE coupling.rs_id=? AND coupling.operation=? AND s2.arrival > s1.arrival AND s2.job_id=s1.job_id");
|
" WHERE coupling.rs_id=? AND coupling.operation=? AND s2.arrival > s1.arrival "
|
||||||
|
"AND s2.job_id=s1.job_id");
|
||||||
q.bind(1, m_stopId);
|
q.bind(1, m_stopId);
|
||||||
q.bind(2, rsId);
|
q.bind(2, rsId);
|
||||||
q.bind(3, int(RsOp::Uncoupled));
|
q.bind(3, int(RsOp::Uncoupled));
|
||||||
|
|
||||||
if(q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
if (q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
auto r = q.getRows();
|
auto r = q.getRows();
|
||||||
db_id stopId = r.get<db_id>(0);
|
db_id stopId = r.get<db_id>(0);
|
||||||
QTime arr = r.get<QTime>(1);
|
QTime arr = r.get<QTime>(1);
|
||||||
db_id stId = r.get<db_id>(2);
|
db_id stId = r.get<db_id>(2);
|
||||||
QString stName = r.get<QString>(3);
|
QString stName = r.get<QString>(3);
|
||||||
|
|
||||||
qDebug() << "Found uncoupling, RS:" << rsId << "Stop:" << stopId << "St:" << stId << arr;
|
qDebug() << "Found uncoupling, RS:" << rsId << "Stop:" << stopId << "St:" << stId
|
||||||
|
<< arr;
|
||||||
|
|
||||||
int but = QMessageBox::question(qApp->activeWindow(),
|
int but = QMessageBox::question(
|
||||||
tr("Delete uncoupling?"),
|
qApp->activeWindow(), tr("Delete uncoupling?"),
|
||||||
tr("You don't couple %1 anymore.\n"
|
tr("You don't couple %1 anymore.\n"
|
||||||
"Do you want to remove also the uncoupling operation in %2 at %3?")
|
"Do you want to remove also the uncoupling operation in %2 at %3?")
|
||||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
if(but == QMessageBox::Yes)
|
if (but == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
qDebug() << "Deleting coupling";
|
qDebug() << "Deleting coupling";
|
||||||
|
|
||||||
|
@ -296,11 +300,11 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
||||||
ret = q_deleteCoupling.execute();
|
ret = q_deleteCoupling.execute();
|
||||||
q_deleteCoupling.reset();
|
q_deleteCoupling.reset();
|
||||||
|
|
||||||
if(ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "Error while deleting next uncoupling op. Stop:" << stopId
|
qWarning() << "Error while deleting next uncoupling op. Stop:" << stopId
|
||||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
<< "Rs:" << rsId << "Op: Uncoupled "
|
||||||
<< mDb.error_msg();
|
<< "Ret:" << ret << mDb.error_msg();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -313,14 +317,14 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString& rsName, bool on)
|
bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString &rsName, bool on)
|
||||||
{
|
{
|
||||||
stopsModel->startStopsEditing();
|
stopsModel->startStopsEditing();
|
||||||
stopsModel->markRsToUpdate(rsId);
|
stopsModel->markRsToUpdate(rsId);
|
||||||
|
|
||||||
if(on)
|
if (on)
|
||||||
{
|
{
|
||||||
if(uncoupled.contains(rsId))
|
if (uncoupled.contains(rsId))
|
||||||
{
|
{
|
||||||
qWarning() << "Error already checked:" << rsId;
|
qWarning() << "Error already checked:" << rsId;
|
||||||
return true;
|
return true;
|
||||||
|
@ -332,44 +336,46 @@ bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString& rsName, bool on)
|
||||||
int ret = q_addCoupling.execute();
|
int ret = q_addCoupling.execute();
|
||||||
q_addCoupling.reset();
|
q_addCoupling.reset();
|
||||||
|
|
||||||
if(ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId
|
qWarning() << "Error while adding coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
<< "Op: Uncoupled "
|
||||||
<< mDb.error_msg();
|
<< "Ret:" << ret << mDb.error_msg();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uncoupled.append(rsId);
|
uncoupled.append(rsId);
|
||||||
|
|
||||||
//Check if there is a next uncoupling operation
|
// Check if there is a next uncoupling operation
|
||||||
query q(mDb, "SELECT s2.id, MIN(s2.arrival), s2.station_id, stations.name"
|
query q(mDb, "SELECT s2.id, MIN(s2.arrival), s2.station_id, stations.name"
|
||||||
" FROM coupling"
|
" FROM coupling"
|
||||||
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
||||||
" JOIN stops s1 ON s1.id=?"
|
" JOIN stops s1 ON s1.id=?"
|
||||||
" JOIN stations ON stations.id=s2.station_id"
|
" JOIN stations ON stations.id=s2.station_id"
|
||||||
" WHERE coupling.rs_id=? AND coupling.operation=? AND s2.arrival > s1.arrival AND s2.job_id=s1.job_id");
|
" WHERE coupling.rs_id=? AND coupling.operation=? AND s2.arrival > s1.arrival "
|
||||||
|
"AND s2.job_id=s1.job_id");
|
||||||
q.bind(1, m_stopId);
|
q.bind(1, m_stopId);
|
||||||
q.bind(2, rsId);
|
q.bind(2, rsId);
|
||||||
q.bind(3, int(RsOp::Uncoupled));
|
q.bind(3, int(RsOp::Uncoupled));
|
||||||
|
|
||||||
if(q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
if (q.step() == SQLITE_ROW && q.getRows().column_type(0) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
auto r = q.getRows();
|
auto r = q.getRows();
|
||||||
db_id stopId = r.get<db_id>(0);
|
db_id stopId = r.get<db_id>(0);
|
||||||
QTime arr = r.get<QTime>(1);
|
QTime arr = r.get<QTime>(1);
|
||||||
db_id stId = r.get<db_id>(2);
|
db_id stId = r.get<db_id>(2);
|
||||||
QString stName = r.get<QString>(3);
|
QString stName = r.get<QString>(3);
|
||||||
|
|
||||||
qDebug() << "Found uncoupling, RS:" << rsId << "Stop:" << stopId << "St:" << stId << arr;
|
qDebug() << "Found uncoupling, RS:" << rsId << "Stop:" << stopId << "St:" << stId
|
||||||
|
<< arr;
|
||||||
|
|
||||||
int but = QMessageBox::question(qApp->activeWindow(),
|
int but =
|
||||||
tr("Delete uncoupling?"),
|
QMessageBox::question(qApp->activeWindow(), tr("Delete uncoupling?"),
|
||||||
tr("You uncouple %1 also in %2 at %3.\n"
|
tr("You uncouple %1 also in %2 at %3.\n"
|
||||||
"Do you want to remove the other uncoupling operation?")
|
"Do you want to remove the other uncoupling operation?")
|
||||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
if(but == QMessageBox::Yes)
|
if (but == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
qDebug() << "Deleting coupling";
|
qDebug() << "Deleting coupling";
|
||||||
|
|
||||||
|
@ -378,11 +384,11 @@ bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString& rsName, bool on)
|
||||||
ret = q_deleteCoupling.execute();
|
ret = q_deleteCoupling.execute();
|
||||||
q_deleteCoupling.reset();
|
q_deleteCoupling.reset();
|
||||||
|
|
||||||
if(ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "Error while deleting next uncoupling op. Stop:" << stopId
|
qWarning() << "Error while deleting next uncoupling op. Stop:" << stopId
|
||||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
<< "Rs:" << rsId << "Op: Uncoupled "
|
||||||
<< mDb.error_msg();
|
<< "Ret:" << ret << mDb.error_msg();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -394,7 +400,7 @@ bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString& rsName, bool on)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int row = uncoupled.indexOf(rsId);
|
int row = uncoupled.indexOf(rsId);
|
||||||
if(row == -1)
|
if (row == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
q_deleteCoupling.bind(1, m_stopId);
|
q_deleteCoupling.bind(1, m_stopId);
|
||||||
|
@ -402,11 +408,11 @@ bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString& rsName, bool on)
|
||||||
int ret = q_deleteCoupling.execute();
|
int ret = q_deleteCoupling.execute();
|
||||||
q_deleteCoupling.reset();
|
q_deleteCoupling.reset();
|
||||||
|
|
||||||
if(ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "Error while deleting coupling op. Stop:" << m_stopId
|
qWarning() << "Error while deleting coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
<< "Op: Uncoupled "
|
||||||
<< mDb.error_msg();
|
<< "Ret:" << ret << mDb.error_msg();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,48 +432,45 @@ int RSCouplingInterface::importRSFromJob(db_id otherStopId)
|
||||||
" WHERE coupling.stop_id=? AND coupling.operation=0");
|
" WHERE coupling.stop_id=? AND coupling.operation=0");
|
||||||
q_getUncoupled.bind(1, otherStopId);
|
q_getUncoupled.bind(1, otherStopId);
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
bool lineElectrified = stopsModel->isRailwayElectrifiedAfterStop(m_stopId);
|
bool lineElectrified = stopsModel->isRailwayElectrifiedAfterStop(m_stopId);
|
||||||
|
|
||||||
QElapsedTimer timer;
|
QElapsedTimer timer;
|
||||||
timer.start();
|
timer.start();
|
||||||
|
|
||||||
for(auto rs : q_getUncoupled)
|
for (auto rs : q_getUncoupled)
|
||||||
{
|
{
|
||||||
db_id rsId = rs.get<db_id>(0);
|
db_id rsId = rs.get<db_id>(0);
|
||||||
|
|
||||||
int number = rs.get<int>(1);
|
int number = rs.get<int>(1);
|
||||||
int modelNameLen = sqlite3_column_bytes(q_getUncoupled.stmt(), 2);
|
int modelNameLen = sqlite3_column_bytes(q_getUncoupled.stmt(), 2);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q_getUncoupled.stmt(), 2));
|
const char *modelName =
|
||||||
|
reinterpret_cast<char const *>(sqlite3_column_text(q_getUncoupled.stmt(), 2));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(q_getUncoupled.stmt(), 3);
|
int modelSuffixLen = sqlite3_column_bytes(q_getUncoupled.stmt(), 3);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(q_getUncoupled.stmt(), 3));
|
const char *modelSuffix =
|
||||||
RsType rsType = RsType(rs.get<int>(4));
|
reinterpret_cast<char const *>(sqlite3_column_text(q_getUncoupled.stmt(), 3));
|
||||||
|
RsType rsType = RsType(rs.get<int>(4));
|
||||||
|
|
||||||
QString rsName = rs_utils::formatNameRef(modelName,
|
QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||||
modelNameLen,
|
modelSuffixLen, rsType);
|
||||||
number,
|
|
||||||
modelSuffix,
|
|
||||||
modelSuffixLen,
|
|
||||||
rsType);
|
|
||||||
|
|
||||||
//TODO: optimize work
|
// TODO: optimize work
|
||||||
if(coupleRS(rsId, rsName, true, !lineElectrified))
|
if (coupleRS(rsId, rsName, true, !lineElectrified))
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if(timer.elapsed() > 10000)
|
if (timer.elapsed() > 10000)
|
||||||
{
|
{
|
||||||
//After 10 seconds, give opportunity to stop
|
// After 10 seconds, give opportunity to stop
|
||||||
int ret = QMessageBox::question(
|
int ret = QMessageBox::question(
|
||||||
qApp->activeWindow(),
|
qApp->activeWindow(), tr("Continue Importation?"),
|
||||||
tr("Continue Importation?"),
|
tr("Rollingstock importation is taking more time than expected.\n"
|
||||||
tr("Rollingstock importation is taking more time than expected.\n"
|
"Do you want to continue?"));
|
||||||
"Do you want to continue?"));
|
|
||||||
|
|
||||||
if(ret == QMessageBox::No)
|
if (ret == QMessageBox::No)
|
||||||
return count; //Abort here
|
return count; // Abort here
|
||||||
|
|
||||||
timer.restart(); //Count again
|
timer.restart(); // Count again
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,13 +490,14 @@ bool RSCouplingInterface::hasEngineAfterStop(bool *isElectricOnNonElectrifiedLin
|
||||||
" LIMIT 1");
|
" LIMIT 1");
|
||||||
q_hasEngine.bind(1, m_jobId);
|
q_hasEngine.bind(1, m_jobId);
|
||||||
q_hasEngine.bind(2, arrival);
|
q_hasEngine.bind(2, arrival);
|
||||||
if(q_hasEngine.step() != SQLITE_ROW)
|
if (q_hasEngine.step() != SQLITE_ROW)
|
||||||
return false; //No engine
|
return false; // No engine
|
||||||
|
|
||||||
if(isElectricOnNonElectrifiedLine)
|
if (isElectricOnNonElectrifiedLine)
|
||||||
{
|
{
|
||||||
RsEngineSubType subType = RsEngineSubType(q_hasEngine.getRows().get<int>(1));
|
RsEngineSubType subType = RsEngineSubType(q_hasEngine.getRows().get<int>(1));
|
||||||
*isElectricOnNonElectrifiedLine = (subType == RsEngineSubType::Electric) && (!isRailwayElectrified());
|
*isElectricOnNonElectrifiedLine =
|
||||||
|
(subType == RsEngineSubType::Electric) && (!isRailwayElectrified());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,18 +35,18 @@ QVariant RSListOnDemandModel::data(const QModelIndex &idx, int role) const
|
||||||
if (!idx.isValid() || row >= curItemCount || idx.column() >= NCols)
|
if (!idx.isValid() || row >= curItemCount || idx.column() >= NCols)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
//qDebug() << "Data:" << idx.row();
|
// qDebug() << "Data:" << idx.row();
|
||||||
|
|
||||||
if(row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
if (row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
||||||
{
|
{
|
||||||
//Fetch above or below current cache
|
// Fetch above or below current cache
|
||||||
const_cast<RSListOnDemandModel *>(this)->fetchRow(row);
|
const_cast<RSListOnDemandModel *>(this)->fetchRow(row);
|
||||||
|
|
||||||
//Temporarily return null
|
// Temporarily return null
|
||||||
return role == Qt::DisplayRole ? QVariant("...") : QVariant();
|
return role == Qt::DisplayRole ? QVariant("...") : QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
const RSItem& item = cache.at(row - cacheFirstRow);
|
const RSItem &item = cache.at(row - cacheFirstRow);
|
||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
|
@ -63,9 +63,9 @@ QVariant RSListOnDemandModel::data(const QModelIndex &idx, int role) const
|
||||||
}
|
}
|
||||||
case Qt::FontRole:
|
case Qt::FontRole:
|
||||||
{
|
{
|
||||||
if(item.type == RsType::Engine)
|
if (item.type == RsType::Engine)
|
||||||
{
|
{
|
||||||
//Engines in bold
|
// Engines in bold
|
||||||
QFont f;
|
QFont f;
|
||||||
f.setBold(true);
|
f.setBold(true);
|
||||||
return f;
|
return f;
|
||||||
|
|
|
@ -38,9 +38,13 @@ class RSListOnDemandModel : public IPagedItemModelImpl<RSListOnDemandModel, RSLi
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum { BatchSize = 50 };
|
enum
|
||||||
|
{
|
||||||
|
BatchSize = 50
|
||||||
|
};
|
||||||
|
|
||||||
enum Columns {
|
enum Columns
|
||||||
|
{
|
||||||
Name = 0,
|
Name = 0,
|
||||||
NCols
|
NCols
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,17 +25,12 @@
|
||||||
|
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
|
|
||||||
|
RSProxyModel::RSProxyModel(RSCouplingInterface *mgr, RsOp o, RsType type, QObject *parent) :
|
||||||
RSProxyModel::RSProxyModel(RSCouplingInterface *mgr,
|
QAbstractListModel(parent),
|
||||||
RsOp o,
|
|
||||||
RsType type,
|
|
||||||
QObject *parent) :
|
|
||||||
QAbstractListModel (parent),
|
|
||||||
couplingMgr(mgr),
|
couplingMgr(mgr),
|
||||||
op(o),
|
op(o),
|
||||||
targetType(type)
|
targetType(type)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RSProxyModel::rowCount(const QModelIndex &parent) const
|
int RSProxyModel::rowCount(const QModelIndex &parent) const
|
||||||
|
@ -45,10 +40,10 @@ int RSProxyModel::rowCount(const QModelIndex &parent) const
|
||||||
|
|
||||||
QVariant RSProxyModel::data(const QModelIndex &idx, int role) const
|
QVariant RSProxyModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
if(!idx.isValid() || idx.column() > 0 || idx.row() >= m_data.size())
|
if (!idx.isValid() || idx.column() > 0 || idx.row() >= m_data.size())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
const RsItem& item = m_data.at(idx.row());
|
const RsItem &item = m_data.at(idx.row());
|
||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
|
@ -58,92 +53,104 @@ QVariant RSProxyModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
return couplingMgr->contains(item.rsId, op) ? Qt::Checked : Qt::Unchecked;
|
return couplingMgr->contains(item.rsId, op) ? Qt::Checked : Qt::Unchecked;
|
||||||
}
|
}
|
||||||
case Qt::BackgroundRole: //NOTE SYNC: RSCoupleDialog
|
case Qt::BackgroundRole: // NOTE SYNC: RSCoupleDialog
|
||||||
{
|
{
|
||||||
if(item.flag == ErrNotCoupledBefore || item.flag == ErrAlreadyCoupled)
|
if (item.flag == ErrNotCoupledBefore || item.flag == ErrAlreadyCoupled)
|
||||||
{
|
{
|
||||||
//Error: already coupled or already uncoupled or not coupled at all before this stop
|
// Error: already coupled or already uncoupled or not coupled at all before this stop
|
||||||
return QBrush(qRgb(255, 86, 255)); //Solid light magenta #FF56FF
|
return QBrush(qRgb(255, 86, 255)); // Solid light magenta #FF56FF
|
||||||
}
|
}
|
||||||
if(item.flag == WrongStation)
|
if (item.flag == WrongStation)
|
||||||
{
|
{
|
||||||
//Error: RS is not in this station
|
// Error: RS is not in this station
|
||||||
return QBrush(qRgb(255, 61, 67)); //Solid light red #FF3d43
|
return QBrush(qRgb(255, 61, 67)); // Solid light red #FF3d43
|
||||||
}
|
}
|
||||||
if(targetType == RsType::Engine && item.engineType == RsEngineSubType::Electric && !couplingMgr->isRailwayElectrified())
|
if (targetType == RsType::Engine && item.engineType == RsEngineSubType::Electric
|
||||||
|
&& !couplingMgr->isRailwayElectrified())
|
||||||
{
|
{
|
||||||
//Warn Electric traction not possible
|
// Warn Electric traction not possible
|
||||||
return QBrush(qRgb(0, 0, 255), Qt::FDiagPattern); //Blue
|
return QBrush(qRgb(0, 0, 255), Qt::FDiagPattern); // Blue
|
||||||
}
|
}
|
||||||
if(item.flag == FirstUseOfRS)
|
if (item.flag == FirstUseOfRS)
|
||||||
{
|
{
|
||||||
return QBrush(qRgb(0, 255, 255)); //Cyan
|
return QBrush(qRgb(0, 255, 255)); // Cyan
|
||||||
}
|
}
|
||||||
if(item.flag == UnusedRS)
|
if (item.flag == UnusedRS)
|
||||||
{
|
{
|
||||||
return QBrush(qRgb(0, 255, 0)); //Green
|
return QBrush(qRgb(0, 255, 0)); // Green
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qt::ToolTipRole:
|
case Qt::ToolTipRole:
|
||||||
{
|
{
|
||||||
if(item.flag == ErrNotCoupledBefore)
|
if (item.flag == ErrNotCoupledBefore)
|
||||||
{
|
{
|
||||||
//Error
|
// Error
|
||||||
return tr("Rollingstock <b>%1</b> cannot be uncoupled here because it wasn't coupled to this job before this stop "
|
return tr("Rollingstock <b>%1</b> cannot be uncoupled here because it wasn't coupled "
|
||||||
|
"to this job before this stop "
|
||||||
"or because it was already uncoupled before this stop.<br>"
|
"or because it was already uncoupled before this stop.<br>"
|
||||||
"Please remove the tick").arg(item.rsName);
|
"Please remove the tick")
|
||||||
|
.arg(item.rsName);
|
||||||
}
|
}
|
||||||
if(item.flag == ErrAlreadyCoupled)
|
if (item.flag == ErrAlreadyCoupled)
|
||||||
{
|
{
|
||||||
//Error
|
// Error
|
||||||
if(item.jobId == couplingMgr->getJobId())
|
if (item.jobId == couplingMgr->getJobId())
|
||||||
{
|
{
|
||||||
return tr("Rollingstock <b>%1</b> cannot be coupled here because it was already coupled to this job before this stop<br>"
|
return tr("Rollingstock <b>%1</b> cannot be coupled here because it was already "
|
||||||
"Please remove the tick").arg(item.rsName);
|
"coupled to this job before this stop<br>"
|
||||||
}else{
|
"Please remove the tick")
|
||||||
return tr("Rollingstock <b>%1</b> cannot be coupled here because it was already coupled before this stop<br>"
|
.arg(item.rsName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return tr("Rollingstock <b>%1</b> cannot be coupled here because it was already "
|
||||||
|
"coupled before this stop<br>"
|
||||||
"to job <b>%2<b/><br>"
|
"to job <b>%2<b/><br>"
|
||||||
"Please remove the tick")
|
"Please remove the tick")
|
||||||
.arg(item.rsName,
|
.arg(item.rsName, JobCategoryName::jobName(item.jobId, item.jobCat));
|
||||||
JobCategoryName::jobName(item.jobId, item.jobCat));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(item.flag == WrongStation)
|
if (item.flag == WrongStation)
|
||||||
{
|
{
|
||||||
//Error
|
// Error
|
||||||
return tr("Rollingstock <b>%1</b> cannot be coupled here because it is not in this station.<br>"
|
return tr("Rollingstock <b>%1</b> cannot be coupled here because it is not in this "
|
||||||
"Please remove the tick").arg(item.rsName);
|
"station.<br>"
|
||||||
|
"Please remove the tick")
|
||||||
|
.arg(item.rsName);
|
||||||
}
|
}
|
||||||
if(targetType == RsType::Engine && item.engineType == RsEngineSubType::Electric && !couplingMgr->isRailwayElectrified())
|
if (targetType == RsType::Engine && item.engineType == RsEngineSubType::Electric
|
||||||
|
&& !couplingMgr->isRailwayElectrified())
|
||||||
{
|
{
|
||||||
//Warn Electric traction not possible
|
// Warn Electric traction not possible
|
||||||
return tr("Engine <b>%1</b> is electric but the line is not electrified!").arg(item.rsName);
|
return tr("Engine <b>%1</b> is electric but the line is not electrified!")
|
||||||
|
.arg(item.rsName);
|
||||||
}
|
}
|
||||||
if(item.flag == HasNextOperation)
|
if (item.flag == HasNextOperation)
|
||||||
{
|
{
|
||||||
return tr("Rollingstock <b>%1</b> is coupled in this station also by <b>%2</b> at <b>%3</b>.")
|
return tr("Rollingstock <b>%1</b> is coupled in this station also by <b>%2</b> at "
|
||||||
.arg(item.rsName,
|
"<b>%3</b>.")
|
||||||
JobCategoryName::jobName(item.jobId, item.jobCat),
|
.arg(item.rsName, JobCategoryName::jobName(item.jobId, item.jobCat),
|
||||||
item.time.toString("HH:mm"));
|
item.time.toString("HH:mm"));
|
||||||
}
|
}
|
||||||
if(item.flag == LastOperation)
|
if (item.flag == LastOperation)
|
||||||
{
|
{
|
||||||
return tr("Rollingstock <b>%1</b> was left in this station by <b>%2</b> at <b>%3</b>.")
|
return tr("Rollingstock <b>%1</b> was left in this station by <b>%2</b> at <b>%3</b>.")
|
||||||
.arg(item.rsName,
|
.arg(item.rsName, JobCategoryName::jobName(item.jobId, item.jobCat),
|
||||||
JobCategoryName::jobName(item.jobId, item.jobCat),
|
item.time.toString("HH:mm"));
|
||||||
item.time.toString("HH:mm"));
|
|
||||||
}
|
}
|
||||||
if(item.flag == FirstUseOfRS)
|
if (item.flag == FirstUseOfRS)
|
||||||
{
|
{
|
||||||
if(op == RsOp::Coupled && couplingMgr->contains(item.rsId, RsOp::Coupled))
|
if (op == RsOp::Coupled && couplingMgr->contains(item.rsId, RsOp::Coupled))
|
||||||
return tr("This is the first use of this rollingstock <b>%1</b>").arg(item.rsName);
|
return tr("This is the first use of this rollingstock <b>%1</b>").arg(item.rsName);
|
||||||
return tr("This would be the first use of this rollingstock <b>%1</b>").arg(item.rsName);
|
return tr("This would be the first use of this rollingstock <b>%1</b>")
|
||||||
|
.arg(item.rsName);
|
||||||
}
|
}
|
||||||
if(item.flag == UnusedRS)
|
if (item.flag == UnusedRS)
|
||||||
{
|
{
|
||||||
return tr("Rollingstock <b>%1</b> is never used in this session. You can couple it for the first time from any one station")
|
return tr("Rollingstock <b>%1</b> is never used in this session. You can couple it for "
|
||||||
.arg(item.rsName);
|
"the first time from any one station")
|
||||||
|
.arg(item.rsName);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -154,21 +161,23 @@ QVariant RSProxyModel::data(const QModelIndex &idx, int role) const
|
||||||
|
|
||||||
bool RSProxyModel::setData(const QModelIndex &idx, const QVariant &value, int role)
|
bool RSProxyModel::setData(const QModelIndex &idx, const QVariant &value, int role)
|
||||||
{
|
{
|
||||||
if(role != Qt::CheckStateRole || !idx.isValid() || idx.column() > 0 || idx.row() >= m_data.size())
|
if (role != Qt::CheckStateRole || !idx.isValid() || idx.column() > 0
|
||||||
|
|| idx.row() >= m_data.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Qt::CheckState state = value.value<Qt::CheckState>();
|
Qt::CheckState state = value.value<Qt::CheckState>();
|
||||||
|
|
||||||
const RsItem& item = m_data.at(idx.row());
|
const RsItem &item = m_data.at(idx.row());
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
if(op == RsOp::Coupled) //Check traction type only if we are dealing with RsType::Engine
|
if (op == RsOp::Coupled) // Check traction type only if we are dealing with RsType::Engine
|
||||||
ret = couplingMgr->coupleRS(item.rsId, item.rsName, state == Qt::Checked, targetType == RsType::Engine);
|
ret = couplingMgr->coupleRS(item.rsId, item.rsName, state == Qt::Checked,
|
||||||
|
targetType == RsType::Engine);
|
||||||
else
|
else
|
||||||
ret = couplingMgr->uncoupleRS(item.rsId, item.rsName, state == Qt::Checked);
|
ret = couplingMgr->uncoupleRS(item.rsId, item.rsName, state == Qt::Checked);
|
||||||
|
|
||||||
if(ret)
|
if (ret)
|
||||||
emit dataChanged(idx, idx);
|
emit dataChanged(idx, idx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -176,11 +185,9 @@ bool RSProxyModel::setData(const QModelIndex &idx, const QVariant &value, int ro
|
||||||
|
|
||||||
Qt::ItemFlags RSProxyModel::flags(const QModelIndex &index) const
|
Qt::ItemFlags RSProxyModel::flags(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if(index.isValid())
|
if (index.isValid())
|
||||||
return Qt::ItemIsEnabled
|
return Qt::ItemIsEnabled | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable
|
||||||
| Qt::ItemNeverHasChildren
|
| Qt::ItemIsUserCheckable;
|
||||||
| Qt::ItemIsSelectable
|
|
||||||
| Qt::ItemIsUserCheckable;
|
|
||||||
return Qt::NoItemFlags;
|
return Qt::NoItemFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,11 +33,7 @@ class RSProxyModel : public QAbstractListModel
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
RSProxyModel(RSCouplingInterface *mgr, RsOp o, RsType type, QObject *parent = nullptr);
|
||||||
RSProxyModel(RSCouplingInterface *mgr,
|
|
||||||
RsOp o,
|
|
||||||
RsType type,
|
|
||||||
QObject *parent = nullptr);
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
|
|
||||||
|
@ -48,28 +44,28 @@ public:
|
||||||
|
|
||||||
enum RSItemFlg
|
enum RSItemFlg
|
||||||
{
|
{
|
||||||
NoFlag = 0,
|
NoFlag = 0,
|
||||||
WrongStation = 1,
|
WrongStation = 1,
|
||||||
LastOperation = 2,
|
LastOperation = 2,
|
||||||
HasNextOperation = 3,
|
HasNextOperation = 3,
|
||||||
FirstUseOfRS = 4,
|
FirstUseOfRS = 4,
|
||||||
UnusedRS = 5,
|
UnusedRS = 5,
|
||||||
ErrNotCoupledBefore = 6,
|
ErrNotCoupledBefore = 6,
|
||||||
ErrAlreadyCoupled = 7
|
ErrAlreadyCoupled = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RsItem
|
struct RsItem
|
||||||
{
|
{
|
||||||
db_id rsId;
|
db_id rsId;
|
||||||
db_id jobId; //Can be next job or previous job
|
db_id jobId; // Can be next job or previous job
|
||||||
QString rsName;
|
QString rsName;
|
||||||
int flag;
|
int flag;
|
||||||
QTime time; //Can be next or previous operation time
|
QTime time; // Can be next or previous operation time
|
||||||
JobCategory jobCat;
|
JobCategory jobCat;
|
||||||
RsEngineSubType engineType;
|
RsEngineSubType engineType;
|
||||||
};
|
};
|
||||||
|
|
||||||
void loadData(const QVector<RsItem>& items);
|
void loadData(const QVector<RsItem> &items);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<RsItem> m_data;
|
QVector<RsItem> m_data;
|
||||||
|
|
|
@ -26,7 +26,6 @@ using namespace sqlite3pp;
|
||||||
|
|
||||||
#include "utils/rs_utils.h"
|
#include "utils/rs_utils.h"
|
||||||
|
|
||||||
|
|
||||||
StopCouplingModel::StopCouplingModel(sqlite3pp::database &db, QObject *parent) :
|
StopCouplingModel::StopCouplingModel(sqlite3pp::database &db, QObject *parent) :
|
||||||
RSListOnDemandModel(db, parent),
|
RSListOnDemandModel(db, parent),
|
||||||
m_stopId(0),
|
m_stopId(0),
|
||||||
|
@ -46,65 +45,65 @@ qint64 StopCouplingModel::recalcTotalItemCount()
|
||||||
|
|
||||||
void StopCouplingModel::setStop(db_id stopId, RsOp op)
|
void StopCouplingModel::setStop(db_id stopId, RsOp op)
|
||||||
{
|
{
|
||||||
m_stopId = stopId;
|
m_stopId = stopId;
|
||||||
m_operation = op;
|
m_operation = op;
|
||||||
|
|
||||||
refreshData(true);
|
refreshData(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopCouplingModel::internalFetch(int first, int /*sortCol*/, int /*valRow*/, const QVariant& /*val*/)
|
void StopCouplingModel::internalFetch(int first, int /*sortCol*/, int /*valRow*/,
|
||||||
|
const QVariant & /*val*/)
|
||||||
{
|
{
|
||||||
query q(mDb);
|
query q(mDb);
|
||||||
|
|
||||||
int offset = first + curPage * ItemsPerPage;
|
int offset = first + curPage * ItemsPerPage;
|
||||||
|
|
||||||
QByteArray sql = "SELECT coupling.rs_id,rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
QByteArray sql =
|
||||||
" FROM coupling"
|
"SELECT coupling.rs_id,rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
||||||
" JOIN rs_list ON rs_list.id=coupling.rs_id"
|
" FROM coupling"
|
||||||
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
" JOIN rs_list ON rs_list.id=coupling.rs_id"
|
||||||
" WHERE coupling.stop_id=?2 AND coupling.operation=?3"
|
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||||
" ORDER BY rs_models.type,rs_models.name,rs_list.number,rs_models.suffix";
|
" WHERE coupling.stop_id=?2 AND coupling.operation=?3"
|
||||||
|
" ORDER BY rs_models.type,rs_models.name,rs_list.number,rs_models.suffix";
|
||||||
|
|
||||||
sql += " LIMIT ?1";
|
sql += " LIMIT ?1";
|
||||||
if(offset)
|
if (offset)
|
||||||
sql += " OFFSET ?2";
|
sql += " OFFSET ?2";
|
||||||
|
|
||||||
q.prepare(sql);
|
q.prepare(sql);
|
||||||
q.bind(1, BatchSize);
|
q.bind(1, BatchSize);
|
||||||
q.bind(2, m_stopId);
|
q.bind(2, m_stopId);
|
||||||
q.bind(3, int(m_operation));
|
q.bind(3, int(m_operation));
|
||||||
if(offset)
|
if (offset)
|
||||||
q.bind(2, offset);
|
q.bind(2, offset);
|
||||||
|
|
||||||
QVector<RSItem> vec(BatchSize);
|
QVector<RSItem> vec(BatchSize);
|
||||||
|
|
||||||
auto it = q.begin();
|
auto it = q.begin();
|
||||||
const auto end = q.end();
|
const auto end = q.end();
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for(; it != end; ++it)
|
for (; it != end; ++it)
|
||||||
{
|
{
|
||||||
auto r = *it;
|
auto r = *it;
|
||||||
RSItem &item = vec[i];
|
RSItem &item = vec[i];
|
||||||
item.rsId = r.get<db_id>(0);
|
item.rsId = r.get<db_id>(0);
|
||||||
|
|
||||||
int number = r.get<int>(1);
|
int number = r.get<int>(1);
|
||||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 2);
|
int modelNameLen = sqlite3_column_bytes(q.stmt(), 2);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 2));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 2));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 3);
|
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 3);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 3));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 3));
|
||||||
item.type = RsType(sqlite3_column_int(q.stmt(), 4));
|
item.type = RsType(sqlite3_column_int(q.stmt(), 4));
|
||||||
|
|
||||||
item.name = rs_utils::formatNameRef(modelName, modelNameLen,
|
item.name = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||||
number,
|
modelSuffixLen, item.type);
|
||||||
modelSuffix, modelSuffixLen,
|
|
||||||
item.type);
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i < BatchSize)
|
if (i < BatchSize)
|
||||||
vec.remove(i, BatchSize - i);
|
vec.remove(i, BatchSize - i);
|
||||||
|
|
||||||
postResult(vec, first);
|
postResult(vec, first);
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#include "rslistondemandmodel.h"
|
#include "rslistondemandmodel.h"
|
||||||
|
|
||||||
|
|
||||||
class StopCouplingModel : public RSListOnDemandModel
|
class StopCouplingModel : public RSListOnDemandModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,9 +36,9 @@ struct StopItem
|
||||||
{
|
{
|
||||||
struct Gate
|
struct Gate
|
||||||
{
|
{
|
||||||
db_id gateConnId = 0;
|
db_id gateConnId = 0;
|
||||||
db_id gateId = 0;
|
db_id gateId = 0;
|
||||||
int gateTrackNum = -1;
|
int gateTrackNum = -1;
|
||||||
utils::Side stationTrackSide = utils::Side::NSides;
|
utils::Side stationTrackSide = utils::Side::NSides;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ struct StopItem
|
||||||
db_id segmentId = 0;
|
db_id segmentId = 0;
|
||||||
int inTrackNum = -1;
|
int inTrackNum = -1;
|
||||||
int outTrackNum = -1;
|
int outTrackNum = -1;
|
||||||
bool reversed = false;
|
bool reversed = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
db_id stopId = 0;
|
db_id stopId = 0;
|
||||||
|
@ -62,12 +62,11 @@ struct StopItem
|
||||||
QTime arrival;
|
QTime arrival;
|
||||||
QTime departure;
|
QTime departure;
|
||||||
|
|
||||||
int addHere = 0;
|
int addHere = 0;
|
||||||
|
|
||||||
StopType type = StopType::Normal;
|
StopType type = StopType::Normal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The StopModel class
|
* \brief The StopModel class
|
||||||
*
|
*
|
||||||
|
@ -80,7 +79,7 @@ class StopModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
StopModel(sqlite3pp::database& db, QObject *parent = nullptr);
|
StopModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||||
|
|
||||||
// QAbstractListModel
|
// QAbstractListModel
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
@ -105,7 +104,7 @@ public:
|
||||||
|
|
||||||
// Editing
|
// Editing
|
||||||
void addStop();
|
void addStop();
|
||||||
void removeStop(const QModelIndex& idx);
|
void removeStop(const QModelIndex &idx);
|
||||||
void removeLastIfEmpty();
|
void removeLastIfEmpty();
|
||||||
|
|
||||||
void uncoupleStillCoupledAtLastStop();
|
void uncoupleStillCoupledAtLastStop();
|
||||||
|
@ -118,7 +117,8 @@ public:
|
||||||
db_id getNewShiftId() const;
|
db_id getNewShiftId() const;
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
void setStopInfo(const QModelIndex& idx, StopItem newStop, StopItem::Segment prevSeg, bool avoidTimeRecalc = false);
|
void setStopInfo(const QModelIndex &idx, StopItem newStop, StopItem::Segment prevSeg,
|
||||||
|
bool avoidTimeRecalc = false);
|
||||||
|
|
||||||
bool setStopTypeRange(int firstRow, int lastRow, StopType type);
|
bool setStopTypeRange(int firstRow, int lastRow, StopType type);
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ public:
|
||||||
// Convinience
|
// Convinience
|
||||||
int getStopRow(db_id stopId) const;
|
int getStopRow(db_id stopId) const;
|
||||||
|
|
||||||
bool isAddHere(const QModelIndex& idx);
|
bool isAddHere(const QModelIndex &idx);
|
||||||
|
|
||||||
std::pair<QTime, QTime> getFirstLastTimes() const;
|
std::pair<QTime, QTime> getFirstLastTimes() const;
|
||||||
|
|
||||||
|
@ -139,10 +139,18 @@ public:
|
||||||
bool isRailwayElectrifiedAfterStop(db_id stopId) const;
|
bool isRailwayElectrifiedAfterStop(db_id stopId) const;
|
||||||
bool isRailwayElectrifiedAfterRow(int row) const;
|
bool isRailwayElectrifiedAfterRow(int row) const;
|
||||||
|
|
||||||
inline StopItem getItemAt(int row) const { return stops.at(row); }
|
inline StopItem getItemAt(int row) const
|
||||||
inline StopType getItemTypeAt(int row) const { return stops.at(row).type; }
|
{
|
||||||
inline db_id getItemStationAt(int row) const { return stops.at(row).stationId; }
|
return stops.at(row);
|
||||||
|
}
|
||||||
|
inline StopType getItemTypeAt(int row) const
|
||||||
|
{
|
||||||
|
return stops.at(row).type;
|
||||||
|
}
|
||||||
|
inline db_id getItemStationAt(int row) const
|
||||||
|
{
|
||||||
|
return stops.at(row).stationId;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_AUTO_TIME_RECALC
|
#ifdef ENABLE_AUTO_TIME_RECALC
|
||||||
void rebaseTimesToSpeed(int firstIdx, QTime firstArr, QTime firstDep);
|
void rebaseTimesToSpeed(int firstIdx, QTime firstArr, QTime firstDep);
|
||||||
|
@ -150,8 +158,7 @@ public:
|
||||||
|
|
||||||
bool trySelectTrackForStop(StopItem &item);
|
bool trySelectTrackForStop(StopItem &item);
|
||||||
|
|
||||||
bool trySetTrackConnections(StopItem &item, db_id trackId,
|
bool trySetTrackConnections(StopItem &item, db_id trackId, QString *outErr);
|
||||||
QString *outErr);
|
|
||||||
|
|
||||||
bool trySelectNextSegment(StopItem &item, db_id segmentId, int suggestedOutGateTrk,
|
bool trySelectNextSegment(StopItem &item, db_id segmentId, int suggestedOutGateTrk,
|
||||||
db_id nextStationId, db_id &out_gateId, db_id &out_suggestedTrackId);
|
db_id nextStationId, db_id &out_gateId, db_id &out_suggestedTrackId);
|
||||||
|
@ -162,7 +169,7 @@ signals:
|
||||||
void categoryChanged(int newCat);
|
void categoryChanged(int newCat);
|
||||||
void jobIdChanged(db_id jobId);
|
void jobIdChanged(db_id jobId);
|
||||||
void jobShiftChanged(db_id shiftId);
|
void jobShiftChanged(db_id shiftId);
|
||||||
void errorSetShiftWithoutStops(); //TODO: find better way to show errors
|
void errorSetShiftWithoutStops(); // TODO: find better way to show errors
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setCategory(int value);
|
void setCategory(int value);
|
||||||
|
@ -182,25 +189,29 @@ private:
|
||||||
db_id createStop(db_id jobId, const QTime &arr, const QTime &dep, StopType type);
|
db_id createStop(db_id jobId, const QTime &arr, const QTime &dep, StopType type);
|
||||||
void deleteStop(db_id stopId);
|
void deleteStop(db_id stopId);
|
||||||
|
|
||||||
bool updateCurrentInGate(StopItem& curStop, const StopItem::Segment& prevSeg);
|
bool updateCurrentInGate(StopItem &curStop, const StopItem::Segment &prevSeg);
|
||||||
bool updateStopTime(StopItem& item, int row, bool propagate, const QTime &oldArr, const QTime &oldDep);
|
bool updateStopTime(StopItem &item, int row, bool propagate, const QTime &oldArr,
|
||||||
|
const QTime &oldDep);
|
||||||
|
|
||||||
int calcTravelTime(db_id segmentId);
|
int calcTravelTime(db_id segmentId);
|
||||||
int defaultStopTimeSec();
|
int defaultStopTimeSec();
|
||||||
|
|
||||||
void shiftStopsBy24hoursFrom(const QTime& startTime);
|
void shiftStopsBy24hoursFrom(const QTime &startTime);
|
||||||
|
|
||||||
friend class RSCouplingInterface;
|
friend class RSCouplingInterface;
|
||||||
bool startInfoEditing();
|
bool startInfoEditing();
|
||||||
bool startStopsEditing();
|
bool startStopsEditing();
|
||||||
bool endStopsEditing();
|
bool endStopsEditing();
|
||||||
inline void markRsToUpdate(db_id rsId) { rsToUpdate.insert(rsId); }
|
inline void markRsToUpdate(db_id rsId)
|
||||||
|
{
|
||||||
|
rsToUpdate.insert(rsId);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//To simulate acceleration/braking we add 4 km to distance
|
// To simulate acceleration/braking we add 4 km to distance
|
||||||
static constexpr double accelerationDistMeters = 4000.0;
|
static constexpr double accelerationDistMeters = 4000.0;
|
||||||
|
|
||||||
sqlite3pp::database& mDb;
|
sqlite3pp::database &mDb;
|
||||||
|
|
||||||
QVector<StopItem> stops;
|
QVector<StopItem> stops;
|
||||||
|
|
||||||
|
@ -218,8 +229,8 @@ private:
|
||||||
|
|
||||||
enum EditState
|
enum EditState
|
||||||
{
|
{
|
||||||
NotEditing = 0,
|
NotEditing = 0,
|
||||||
InfoEditing = 1,
|
InfoEditing = 1,
|
||||||
StopsEditing = 2
|
StopsEditing = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ using namespace sqlite3pp;
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
TrainAssetModel::TrainAssetModel(database& db, QObject *parent) :
|
TrainAssetModel::TrainAssetModel(database &db, QObject *parent) :
|
||||||
RSListOnDemandModel(db, parent),
|
RSListOnDemandModel(db, parent),
|
||||||
m_jobId(0),
|
m_jobId(0),
|
||||||
m_mode(BeforeStop)
|
m_mode(BeforeStop)
|
||||||
|
@ -45,30 +45,33 @@ qint64 TrainAssetModel::recalcTotalItemCount()
|
||||||
" GROUP BY coupling.rs_id"
|
" GROUP BY coupling.rs_id"
|
||||||
" HAVING coupling.operation=1)");
|
" HAVING coupling.operation=1)");
|
||||||
q.bind(1, m_jobId);
|
q.bind(1, m_jobId);
|
||||||
//HACK: 1 minute is the min interval between stops,
|
// HACK: 1 minute is the min interval between stops,
|
||||||
//by adding 1 minute we include the current stop but leave out the next one
|
// by adding 1 minute we include the current stop but leave out the next one
|
||||||
if(m_mode == AfterStop)
|
if (m_mode == AfterStop)
|
||||||
q.bind(2, m_arrival.addSecs(60));
|
q.bind(2, m_arrival.addSecs(60));
|
||||||
else
|
else
|
||||||
q.bind(2, m_arrival);
|
q.bind(2, m_arrival);
|
||||||
int ret = q.step();
|
int ret = q.step();
|
||||||
if(ret != SQLITE_ROW)
|
if (ret != SQLITE_ROW)
|
||||||
qWarning() << "TrainAssetModel: " << mDb.error_msg() << mDb.error_code();
|
qWarning() << "TrainAssetModel: " << mDb.error_msg() << mDb.error_code();
|
||||||
|
|
||||||
const qint64 count = q.getRows().get<int>(0);
|
const qint64 count = q.getRows().get<int>(0);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrainAssetModel::internalFetch(int first, int sortCol, int /*valRow*/, const QVariant &/*val*/)
|
void TrainAssetModel::internalFetch(int first, int sortCol, int /*valRow*/,
|
||||||
|
const QVariant & /*val*/)
|
||||||
{
|
{
|
||||||
query q(mDb);
|
query q(mDb);
|
||||||
|
|
||||||
int offset = first + curPage * ItemsPerPage;
|
int offset = first + curPage * ItemsPerPage;
|
||||||
|
|
||||||
//const char *whereCol;
|
// const char *whereCol;
|
||||||
|
|
||||||
QByteArray sql = "SELECT sub.rs_id,sub.number,sub.name,sub.suffix,sub.type FROM("
|
QByteArray sql = "SELECT sub.rs_id,sub.number,sub.name,sub.suffix,sub.type FROM("
|
||||||
"SELECT coupling.rs_id,rs_list.number,rs_models.name,rs_models.suffix,rs_models.type,MAX(stops.arrival)"
|
"SELECT "
|
||||||
|
"coupling.rs_id,rs_list.number,rs_models.name,rs_models.suffix,rs_models.type,"
|
||||||
|
"MAX(stops.arrival)"
|
||||||
" FROM stops"
|
" FROM stops"
|
||||||
" JOIN coupling ON coupling.stop_id=stops.id"
|
" JOIN coupling ON coupling.stop_id=stops.id"
|
||||||
" JOIN rs_list ON rs_list.id=rs_id"
|
" JOIN rs_list ON rs_list.id=rs_id"
|
||||||
|
@ -103,49 +106,47 @@ void TrainAssetModel::internalFetch(int first, int sortCol, int /*valRow*/, cons
|
||||||
// sql += " DESC";
|
// sql += " DESC";
|
||||||
|
|
||||||
sql += " LIMIT ?1";
|
sql += " LIMIT ?1";
|
||||||
if(offset)
|
if (offset)
|
||||||
sql += " OFFSET ?2";
|
sql += " OFFSET ?2";
|
||||||
|
|
||||||
q.prepare(sql);
|
q.prepare(sql);
|
||||||
q.bind(1, BatchSize);
|
q.bind(1, BatchSize);
|
||||||
q.bind(3, m_jobId);
|
q.bind(3, m_jobId);
|
||||||
//HACK: 1 minute is the min interval between stops,
|
// HACK: 1 minute is the min interval between stops,
|
||||||
//by adding 1 minute we include the current stop but leave out the next one
|
// by adding 1 minute we include the current stop but leave out the next one
|
||||||
if(m_mode == AfterStop)
|
if (m_mode == AfterStop)
|
||||||
q.bind(4, m_arrival.addSecs(60));
|
q.bind(4, m_arrival.addSecs(60));
|
||||||
else
|
else
|
||||||
q.bind(4, m_arrival);
|
q.bind(4, m_arrival);
|
||||||
if(offset)
|
if (offset)
|
||||||
q.bind(2, offset);
|
q.bind(2, offset);
|
||||||
|
|
||||||
QVector<RSItem> vec(BatchSize);
|
QVector<RSItem> vec(BatchSize);
|
||||||
|
|
||||||
auto it = q.begin();
|
auto it = q.begin();
|
||||||
const auto end = q.end();
|
const auto end = q.end();
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(; it != end; ++it)
|
for (; it != end; ++it)
|
||||||
{
|
{
|
||||||
auto r = *it;
|
auto r = *it;
|
||||||
RSItem &item = vec[i];
|
RSItem &item = vec[i];
|
||||||
item.rsId = r.get<db_id>(0);
|
item.rsId = r.get<db_id>(0);
|
||||||
|
|
||||||
int number = r.get<int>(1);
|
int number = r.get<int>(1);
|
||||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 2);
|
int modelNameLen = sqlite3_column_bytes(q.stmt(), 2);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 2));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 2));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 3);
|
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 3);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 3));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 3));
|
||||||
item.type = RsType(sqlite3_column_int(q.stmt(), 4));
|
item.type = RsType(sqlite3_column_int(q.stmt(), 4));
|
||||||
|
|
||||||
item.name = rs_utils::formatNameRef(modelName, modelNameLen,
|
item.name = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||||
number,
|
modelSuffixLen, item.type);
|
||||||
modelSuffix, modelSuffixLen,
|
|
||||||
item.type);
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i < BatchSize)
|
if (i < BatchSize)
|
||||||
vec.remove(i, BatchSize - i);
|
vec.remove(i, BatchSize - i);
|
||||||
|
|
||||||
postResult(vec, first);
|
postResult(vec, first);
|
||||||
|
@ -153,9 +154,9 @@ void TrainAssetModel::internalFetch(int first, int sortCol, int /*valRow*/, cons
|
||||||
|
|
||||||
void TrainAssetModel::setStop(db_id jobId, QTime arrival, Mode mode)
|
void TrainAssetModel::setStop(db_id jobId, QTime arrival, Mode mode)
|
||||||
{
|
{
|
||||||
m_jobId = jobId;
|
m_jobId = jobId;
|
||||||
m_arrival = arrival;
|
m_arrival = arrival;
|
||||||
m_mode = mode;
|
m_mode = mode;
|
||||||
|
|
||||||
refreshData(true);
|
refreshData(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,13 @@ class TrainAssetModel : public RSListOnDemandModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum Mode {
|
enum Mode
|
||||||
|
{
|
||||||
BeforeStop,
|
BeforeStop,
|
||||||
AfterStop
|
AfterStop
|
||||||
};
|
};
|
||||||
|
|
||||||
TrainAssetModel(sqlite3pp::database& db, QObject *parent = nullptr);
|
TrainAssetModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||||
|
|
||||||
// TrainAssetModel
|
// TrainAssetModel
|
||||||
void setStop(db_id jobId, QTime arrival, Mode mode);
|
void setStop(db_id jobId, QTime arrival, Mode mode);
|
||||||
|
|
|
@ -36,15 +36,15 @@
|
||||||
#include "app/session.h"
|
#include "app/session.h"
|
||||||
|
|
||||||
RSCoupleDialog::RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent) :
|
RSCoupleDialog::RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent) :
|
||||||
QDialog (parent),
|
QDialog(parent),
|
||||||
couplingMgr(mgr),
|
couplingMgr(mgr),
|
||||||
legend(nullptr),
|
legend(nullptr),
|
||||||
m_showLegend(false),
|
m_showLegend(false),
|
||||||
op(o)
|
op(o)
|
||||||
{
|
{
|
||||||
engModel = new RSProxyModel(couplingMgr, op, RsType::Engine, this);
|
engModel = new RSProxyModel(couplingMgr, op, RsType::Engine, this);
|
||||||
coachModel = new RSProxyModel(couplingMgr, op, RsType::Coach, this);
|
coachModel = new RSProxyModel(couplingMgr, op, RsType::Coach, this);
|
||||||
freightModel = new RSProxyModel(couplingMgr, op, RsType::FreightWagon, this);
|
freightModel = new RSProxyModel(couplingMgr, op, RsType::FreightWagon, this);
|
||||||
|
|
||||||
QGridLayout *lay = new QGridLayout(this);
|
QGridLayout *lay = new QGridLayout(this);
|
||||||
|
|
||||||
|
@ -86,7 +86,8 @@ RSCoupleDialog::RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent
|
||||||
showHideLegendBut = new QPushButton;
|
showHideLegendBut = new QPushButton;
|
||||||
buttonLay->addWidget(showHideLegendBut);
|
buttonLay->addWidget(showHideLegendBut);
|
||||||
|
|
||||||
QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok); //TODO: implement also cancel
|
QDialogButtonBox *box =
|
||||||
|
new QDialogButtonBox(QDialogButtonBox::Ok); // TODO: implement also cancel
|
||||||
connect(box, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
connect(box, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
connect(box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
buttonLay->addWidget(box);
|
buttonLay->addWidget(box);
|
||||||
|
@ -100,13 +101,14 @@ RSCoupleDialog::RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent
|
||||||
setLegendVisible(AppSettings.getShowCouplingLegend());
|
setLegendVisible(AppSettings.getShowCouplingLegend());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSCoupleDialog::loadProxyModels(sqlite3pp::database& db, db_id jobId, db_id stopId, db_id stationId, const QTime& arrival)
|
void RSCoupleDialog::loadProxyModels(sqlite3pp::database &db, db_id jobId, db_id stopId,
|
||||||
|
db_id stationId, const QTime &arrival)
|
||||||
{
|
{
|
||||||
QVector<RSProxyModel::RsItem> engines, freight, coaches;
|
QVector<RSProxyModel::RsItem> engines, freight, coaches;
|
||||||
|
|
||||||
sqlite3pp::query q(db);
|
sqlite3pp::query q(db);
|
||||||
|
|
||||||
if(op == RsOp::Coupled)
|
if (op == RsOp::Coupled)
|
||||||
{
|
{
|
||||||
/* Show Couple-able RS:
|
/* Show Couple-able RS:
|
||||||
* - RS free in this station
|
* - RS free in this station
|
||||||
|
@ -117,59 +119,68 @@ void RSCoupleDialog::loadProxyModels(sqlite3pp::database& db, db_id jobId, db_id
|
||||||
* - Possible wrong operations to let the user remove them
|
* - Possible wrong operations to let the user remove them
|
||||||
*/
|
*/
|
||||||
|
|
||||||
q.prepare("SELECT MAX(sub.p), sub.rs_id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type, rs_models.sub_type, sub.arr, sub.job_id, jobs.category FROM ("
|
q.prepare(
|
||||||
|
"SELECT MAX(sub.p), sub.rs_id, rs_list.number, rs_models.name, rs_models.suffix, "
|
||||||
|
"rs_models.type, rs_models.sub_type, sub.arr, sub.job_id, jobs.category FROM ("
|
||||||
|
|
||||||
//Select possible wrong operations to let user remove (un-check) them
|
// Select possible wrong operations to let user remove (un-check) them
|
||||||
" SELECT 1 AS p, coupling.rs_id AS rs_id, NULL AS arr, NULL AS job_id FROM coupling WHERE coupling.stop_id=?3 AND coupling.operation=1"
|
" SELECT 1 AS p, coupling.rs_id AS rs_id, NULL AS arr, NULL AS job_id FROM coupling "
|
||||||
" UNION ALL"
|
"WHERE coupling.stop_id=?3 AND coupling.operation=1"
|
||||||
|
" UNION ALL"
|
||||||
|
|
||||||
//Select RS uncoupled before our arrival (included RS uncoupled at exact same time) (except uncoupled by us)
|
// Select RS uncoupled before our arrival (included RS uncoupled at exact same time)
|
||||||
" SELECT 2 AS p, coupling.rs_id AS rs_id, MAX(stops.arrival) AS arr, stops.job_id AS job_id"
|
// (except uncoupled by us)
|
||||||
" FROM stops"
|
" SELECT 2 AS p, coupling.rs_id AS rs_id, MAX(stops.arrival) AS arr, stops.job_id AS "
|
||||||
" JOIN coupling ON coupling.stop_id=stops.id"
|
"job_id"
|
||||||
" WHERE stops.station_id=?1 AND stops.arrival <= ?2 AND stops.id<>?3"
|
" FROM stops"
|
||||||
" GROUP BY coupling.rs_id"
|
" JOIN coupling ON coupling.stop_id=stops.id"
|
||||||
" HAVING coupling.operation=0"
|
" WHERE stops.station_id=?1 AND stops.arrival <= ?2 AND stops.id<>?3"
|
||||||
" UNION ALL"
|
" GROUP BY coupling.rs_id"
|
||||||
|
" HAVING coupling.operation=0"
|
||||||
|
" UNION ALL"
|
||||||
|
|
||||||
//Select RS coupled after our arrival (excluded RS coupled at exact same time)
|
// Select RS coupled after our arrival (excluded RS coupled at exact same time)
|
||||||
" SELECT 3 AS p, coupling.rs_id, MIN(stops.arrival) AS arr, stops.job_id AS job_id"
|
" SELECT 3 AS p, coupling.rs_id, MIN(stops.arrival) AS arr, stops.job_id AS job_id"
|
||||||
" FROM coupling"
|
" FROM coupling"
|
||||||
" JOIN stops ON stops.id=coupling.stop_id"
|
" JOIN stops ON stops.id=coupling.stop_id"
|
||||||
" WHERE stops.station_id=?1 AND stops.arrival > ?2"
|
" WHERE stops.station_id=?1 AND stops.arrival > ?2"
|
||||||
" GROUP BY coupling.rs_id"
|
" GROUP BY coupling.rs_id"
|
||||||
" HAVING coupling.operation=1"
|
" HAVING coupling.operation=1"
|
||||||
" UNION ALL"
|
" UNION ALL"
|
||||||
|
|
||||||
//Select coupled RS for first time
|
// Select coupled RS for first time
|
||||||
" SELECT 4 AS p, rs_list.id AS rs_id, NULL AS arr, NULL AS job_id"
|
" SELECT 4 AS p, rs_list.id AS rs_id, NULL AS arr, NULL AS job_id"
|
||||||
" FROM rs_list"
|
" FROM rs_list"
|
||||||
" WHERE NOT EXISTS ("
|
" WHERE NOT EXISTS ("
|
||||||
" SELECT coupling.rs_id FROM coupling"
|
" SELECT coupling.rs_id FROM coupling"
|
||||||
" JOIN stops ON stops.id=coupling.stop_id WHERE coupling.rs_id=rs_list.id AND stops.arrival<?2)"
|
" JOIN stops ON stops.id=coupling.stop_id WHERE coupling.rs_id=rs_list.id AND "
|
||||||
" UNION ALL"
|
"stops.arrival<?2)"
|
||||||
|
" UNION ALL"
|
||||||
|
|
||||||
//Select unused RS (RS without any operation)
|
// Select unused RS (RS without any operation)
|
||||||
" SELECT 5 AS p, rs_list.id AS rs_id, NULL AS arr, NULL AS job_id"
|
" SELECT 5 AS p, rs_list.id AS rs_id, NULL AS arr, NULL AS job_id"
|
||||||
" FROM rs_list"
|
" FROM rs_list"
|
||||||
" WHERE NOT EXISTS (SELECT coupling.rs_id FROM coupling WHERE coupling.rs_id=rs_list.id)"
|
" WHERE NOT EXISTS (SELECT coupling.rs_id FROM coupling WHERE coupling.rs_id=rs_list.id)"
|
||||||
" UNION ALL"
|
" UNION ALL"
|
||||||
|
|
||||||
//Select RS coupled before our arrival (already coupled by this job or occupied by other job)
|
// Select RS coupled before our arrival (already coupled by this job or occupied by other
|
||||||
" SELECT 7 AS p, c1.rs_id, MAX(s1.arrival) AS arr, s1.job_id AS job_id"
|
// job)
|
||||||
" FROM coupling c1"
|
" SELECT 7 AS p, c1.rs_id, MAX(s1.arrival) AS arr, s1.job_id AS job_id"
|
||||||
" JOIN coupling c2 ON c2.rs_id=c1.rs_id"
|
" FROM coupling c1"
|
||||||
" JOIN stops s1 ON s1.id=c2.stop_id"
|
" JOIN coupling c2 ON c2.rs_id=c1.rs_id"
|
||||||
" WHERE c1.stop_id=?3 AND c1.operation=1 AND s1.arrival<?2"
|
" JOIN stops s1 ON s1.id=c2.stop_id"
|
||||||
" GROUP BY c1.rs_id"
|
" WHERE c1.stop_id=?3 AND c1.operation=1 AND s1.arrival<?2"
|
||||||
" HAVING c2.operation=1"
|
" GROUP BY c1.rs_id"
|
||||||
" ) AS sub"
|
" HAVING c2.operation=1"
|
||||||
|
" ) AS sub"
|
||||||
|
|
||||||
" JOIN rs_list ON rs_list.id=sub.rs_id" //FIXME: it seems it is better to join in the subquery directly, also avoids some LEFT in joins
|
" JOIN rs_list ON rs_list.id=sub.rs_id" // FIXME: it seems it is better to join in the
|
||||||
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
// subquery directly, also avoids some LEFT in
|
||||||
" LEFT JOIN jobs ON jobs.id=sub.job_id"
|
// joins
|
||||||
" GROUP BY sub.rs_id"
|
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||||
" ORDER BY rs_models.name, rs_list.number");
|
" LEFT JOIN jobs ON jobs.id=sub.job_id"
|
||||||
|
" GROUP BY sub.rs_id"
|
||||||
|
" ORDER BY rs_models.name, rs_list.number");
|
||||||
|
|
||||||
q.bind(1, stationId);
|
q.bind(1, stationId);
|
||||||
q.bind(2, arrival);
|
q.bind(2, arrival);
|
||||||
|
@ -184,65 +195,67 @@ void RSCoupleDialog::loadProxyModels(sqlite3pp::database& db, db_id jobId, db_id
|
||||||
* - Show possible wrong operations to let user remove them
|
* - Show possible wrong operations to let user remove them
|
||||||
*/
|
*/
|
||||||
|
|
||||||
q.prepare("SELECT MAX(sub.p), sub.rs_id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type, rs_models.sub_type, sub.arr, NULL AS job_id, NULL AS category FROM("
|
q.prepare(
|
||||||
"SELECT 8 AS p, coupling.rs_id AS rs_id, MAX(stops.arrival) AS arr"
|
"SELECT MAX(sub.p), sub.rs_id, rs_list.number, rs_models.name, rs_models.suffix, "
|
||||||
" FROM stops"
|
"rs_models.type, rs_models.sub_type, sub.arr, NULL AS job_id, NULL AS category FROM("
|
||||||
" JOIN coupling ON coupling.stop_id=stops.id"
|
"SELECT 8 AS p, coupling.rs_id AS rs_id, MAX(stops.arrival) AS arr"
|
||||||
" WHERE stops.arrival<?2"
|
" FROM stops"
|
||||||
" GROUP BY coupling.rs_id"
|
" JOIN coupling ON coupling.stop_id=stops.id"
|
||||||
" HAVING coupling.operation=1 AND stops.job_id=?1"
|
" WHERE stops.arrival<?2"
|
||||||
" UNION ALL"
|
" GROUP BY coupling.rs_id"
|
||||||
|
" HAVING coupling.operation=1 AND stops.job_id=?1"
|
||||||
|
" UNION ALL"
|
||||||
|
|
||||||
//Select possible wrong operations to let user remove them
|
// Select possible wrong operations to let user remove them
|
||||||
" SELECT 6 AS p, coupling.rs_id AS rs_id, NULL AS arr FROM coupling WHERE coupling.stop_id=?3 AND coupling.operation=0"
|
" SELECT 6 AS p, coupling.rs_id AS rs_id, NULL AS arr FROM coupling WHERE "
|
||||||
") AS sub"
|
"coupling.stop_id=?3 AND coupling.operation=0"
|
||||||
" JOIN rs_list ON rs_list.id=sub.rs_id" //FIXME: it seems it is better to join in the subquery directly, also avoids some LEFT in joins
|
") AS sub"
|
||||||
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
" JOIN rs_list ON rs_list.id=sub.rs_id" // FIXME: it seems it is better to join in the
|
||||||
" GROUP BY sub.rs_id"
|
// subquery directly, also avoids some LEFT in
|
||||||
" ORDER BY rs_models.name, rs_list.number");
|
// joins
|
||||||
|
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||||
|
" GROUP BY sub.rs_id"
|
||||||
|
" ORDER BY rs_models.name, rs_list.number");
|
||||||
|
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
q.bind(2, arrival);
|
q.bind(2, arrival);
|
||||||
q.bind(3, stopId);
|
q.bind(3, stopId);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto rs : q)
|
for (auto rs : q)
|
||||||
{
|
{
|
||||||
/*Priority flag:
|
/*Priority flag:
|
||||||
* 1: The RS is not free in this station, it's shown to let the user remove the operation
|
* 1: The RS is not free in this station, it's shown to let the user remove the operation
|
||||||
* 2: The RS is free and has no following operation in this station
|
* 2: The RS is free and has no following operation in this station
|
||||||
* (It could have wrong operation in other station that should be fixed by user,
|
* (It could have wrong operation in other station that should be fixed by user,
|
||||||
* as shown in RsErrorWidget)
|
* as shown in RsErrorWidget)
|
||||||
* 3: The RS is free but a job will couple it in the future so you should bring it back here before that time
|
* 3: The RS is free but a job will couple it in the future so you should bring it back here
|
||||||
* 4: The RS is used for first time
|
* before that time 4: The RS is used for first time 5: The RS is unsed 6: RS was not
|
||||||
* 5: The RS is unsed
|
* coupled before this stop and you are trying to uncouple it 7: Normal RS uncouple-able,
|
||||||
* 6: RS was not coupled before this stop and you are trying to uncouple it
|
* used to win against 6
|
||||||
* 7: Normal RS uncouple-able, used to win against 6
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
RSProxyModel::RsItem item;
|
RSProxyModel::RsItem item;
|
||||||
item.flag = rs.get<int>(0);
|
item.flag = rs.get<int>(0);
|
||||||
item.rsId = rs.get<db_id>(1);
|
item.rsId = rs.get<db_id>(1);
|
||||||
|
|
||||||
int number = rs.get<int>(2);
|
int number = rs.get<int>(2);
|
||||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 3);
|
int modelNameLen = sqlite3_column_bytes(q.stmt(), 3);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 3));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 3));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 4);
|
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 4);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 4));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 4));
|
||||||
RsType type = RsType(rs.get<int>(5));
|
RsType type = RsType(rs.get<int>(5));
|
||||||
RsEngineSubType subType = RsEngineSubType(rs.get<int>(6));
|
RsEngineSubType subType = RsEngineSubType(rs.get<int>(6));
|
||||||
|
|
||||||
item.rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
item.rsName = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||||
number,
|
modelSuffixLen, type);
|
||||||
modelSuffix, modelSuffixLen,
|
|
||||||
type);
|
|
||||||
|
|
||||||
item.engineType = RsEngineSubType::Invalid;
|
item.engineType = RsEngineSubType::Invalid;
|
||||||
|
|
||||||
item.time = rs.get<QTime>(7);
|
item.time = rs.get<QTime>(7);
|
||||||
item.jobId = rs.get<db_id>(8);
|
item.jobId = rs.get<db_id>(8);
|
||||||
item.jobCat = JobCategory(rs.get<int>(9));
|
item.jobCat = JobCategory(rs.get<int>(9));
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -274,7 +287,7 @@ void RSCoupleDialog::loadProxyModels(sqlite3pp::database& db, db_id jobId, db_id
|
||||||
|
|
||||||
void RSCoupleDialog::done(int ret)
|
void RSCoupleDialog::done(int ret)
|
||||||
{
|
{
|
||||||
//Save legend state
|
// Save legend state
|
||||||
AppSettings.setShowCouplingLegend(m_showLegend);
|
AppSettings.setShowCouplingLegend(m_showLegend);
|
||||||
|
|
||||||
QDialog::done(ret);
|
QDialog::done(ret);
|
||||||
|
@ -294,35 +307,43 @@ void RSCoupleDialog::setLegendVisible(bool val)
|
||||||
{
|
{
|
||||||
m_showLegend = val;
|
m_showLegend = val;
|
||||||
|
|
||||||
if(legend->isVisible() && !m_showLegend)
|
if (legend->isVisible() && !m_showLegend)
|
||||||
{
|
{
|
||||||
legend->hide();
|
legend->hide();
|
||||||
}
|
}
|
||||||
else if(m_showLegend && !legend->isVisible())
|
else if (m_showLegend && !legend->isVisible())
|
||||||
{
|
{
|
||||||
legend->show();
|
legend->show();
|
||||||
if(!legend->layout())
|
if (!legend->layout())
|
||||||
{
|
{
|
||||||
double fontPt = font().pointSizeF() * 1.2;
|
double fontPt = font().pointSizeF() * 1.2;
|
||||||
|
|
||||||
QVBoxLayout *legendLay = new QVBoxLayout(legend);
|
QVBoxLayout *legendLay = new QVBoxLayout(legend);
|
||||||
QLabel *label = new QLabel(tr("<style>\n"
|
QLabel *label = new QLabel(
|
||||||
"table, td {"
|
tr("<style>\n"
|
||||||
"border: 1px solid black;"
|
"table, td {"
|
||||||
"border-collapse:collapse;"
|
"border: 1px solid black;"
|
||||||
"padding:5px;"
|
"border-collapse:collapse;"
|
||||||
" }"
|
"padding:5px;"
|
||||||
"</style>"
|
" }"
|
||||||
"<table style=\"font-size:%1pt;padding:10pt\"><tr>"
|
"</style>"
|
||||||
"<td><span style=\"background-color:#FFFFFF\">___</span> This item is free in current station.</td>"
|
"<table style=\"font-size:%1pt;padding:10pt\"><tr>"
|
||||||
"<td><span style=\"background-color:#FF3d43\">___</span> The item isn't in this station.</td>"
|
"<td><span style=\"background-color:#FFFFFF\">___</span> This item is free in "
|
||||||
"</tr><tr>"
|
"current station.</td>"
|
||||||
"<td><span style=\"background-color:#00FFFF\">___</span> First use of this item.</td>"
|
"<td><span style=\"background-color:#FF3d43\">___</span> The item isn't in this "
|
||||||
"<td><span style=\"background-color:#FF56FF\">___</span> The item isn't coupled before or already coupled.</td>"
|
"station.</td>"
|
||||||
"</tr><tr>"
|
"</tr><tr>"
|
||||||
"<td><span style=\"background-color:#00FF00\">___</span> This item is never used in this session.</td>"
|
"<td><span style=\"background-color:#00FFFF\">___</span> First use of this "
|
||||||
"<td><span style=\"color:#0000FF;background-color:#FFFFFF\">\\\\\\\\</span> Railway line doesn't allow electric traction.</td>"
|
"item.</td>"
|
||||||
"</tr></table>").arg(fontPt));
|
"<td><span style=\"background-color:#FF56FF\">___</span> The item isn't coupled "
|
||||||
|
"before or already coupled.</td>"
|
||||||
|
"</tr><tr>"
|
||||||
|
"<td><span style=\"background-color:#00FF00\">___</span> This item is never used "
|
||||||
|
"in this session.</td>"
|
||||||
|
"<td><span style=\"color:#0000FF;background-color:#FFFFFF\">\\\\\\\\</span> "
|
||||||
|
"Railway line doesn't allow electric traction.</td>"
|
||||||
|
"</tr></table>")
|
||||||
|
.arg(fontPt));
|
||||||
label->setTextFormat(Qt::RichText);
|
label->setTextFormat(Qt::RichText);
|
||||||
label->setWordWrap(true);
|
label->setWordWrap(true);
|
||||||
legendLay->addWidget(label);
|
legendLay->addWidget(label);
|
||||||
|
|
|
@ -32,14 +32,15 @@ namespace sqlite3pp {
|
||||||
class database;
|
class database;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: on-demand load and filter
|
// FIXME: on-demand load and filter
|
||||||
class RSCoupleDialog : public QDialog
|
class RSCoupleDialog : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent = nullptr);
|
RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent = nullptr);
|
||||||
|
|
||||||
void loadProxyModels(sqlite3pp::database &db, db_id jobId, db_id stopId, db_id stationId, const QTime &arrival);
|
void loadProxyModels(sqlite3pp::database &db, db_id jobId, db_id stopId, db_id stationId,
|
||||||
|
const QTime &arrival);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void done(int ret) override;
|
void done(int ret) override;
|
||||||
|
|
|
@ -34,7 +34,7 @@ ShiftBusyDlg::ShiftBusyDlg(QWidget *parent) :
|
||||||
{
|
{
|
||||||
QVBoxLayout *lay = new QVBoxLayout(this);
|
QVBoxLayout *lay = new QVBoxLayout(this);
|
||||||
|
|
||||||
m_label = new QLabel;
|
m_label = new QLabel;
|
||||||
lay->addWidget(m_label);
|
lay->addWidget(m_label);
|
||||||
|
|
||||||
view = new QTableView;
|
view = new QTableView;
|
||||||
|
@ -57,8 +57,7 @@ void ShiftBusyDlg::setModel(ShiftBusyModel *m)
|
||||||
m_label->setText(tr("Cannot set shift <b>%1</b> to job <b>%2</b>.<br>"
|
m_label->setText(tr("Cannot set shift <b>%1</b> to job <b>%2</b>.<br>"
|
||||||
"The selected shift is busy:<br>"
|
"The selected shift is busy:<br>"
|
||||||
"From: %3 To: %4")
|
"From: %3 To: %4")
|
||||||
.arg(model->getShiftName(),
|
.arg(model->getShiftName(), model->getJobName(),
|
||||||
model->getJobName(),
|
model->getStart().toString("HH:mm"),
|
||||||
model->getStart().toString("HH:mm"),
|
model->getEnd().toString("HH:mm")));
|
||||||
model->getEnd().toString("HH:mm")));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
explicit ShiftBusyDlg(QWidget *parent = nullptr);
|
explicit ShiftBusyDlg(QWidget *parent = nullptr);
|
||||||
|
|
||||||
void setModel(ShiftBusyModel *m);
|
void setModel(ShiftBusyModel *m);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *m_label;
|
QLabel *m_label;
|
||||||
QTableView *view;
|
QTableView *view;
|
||||||
|
|
|
@ -35,9 +35,10 @@ ShiftBusyModel::ShiftBusyModel(sqlite3pp::database &db, QObject *parent) :
|
||||||
|
|
||||||
QVariant ShiftBusyModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant ShiftBusyModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
{
|
{
|
||||||
switch (section) {
|
switch (section)
|
||||||
|
{
|
||||||
case JobCol:
|
case JobCol:
|
||||||
return tr("Job");
|
return tr("Job");
|
||||||
case Start:
|
case Start:
|
||||||
|
@ -66,7 +67,7 @@ QVariant ShiftBusyModel::data(const QModelIndex &idx, int role) const
|
||||||
if (!idx.isValid() || row >= m_data.size() || idx.column() >= NCols)
|
if (!idx.isValid() || row >= m_data.size() || idx.column() >= NCols)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
const JobInfo& info = m_data.at(row);
|
const JobInfo &info = m_data.at(row);
|
||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
|
@ -94,13 +95,13 @@ void ShiftBusyModel::loadData(db_id shiftId, db_id jobId, const QTime &start, co
|
||||||
m_data.clear();
|
m_data.clear();
|
||||||
|
|
||||||
m_shiftId = shiftId;
|
m_shiftId = shiftId;
|
||||||
m_jobId = jobId;
|
m_jobId = jobId;
|
||||||
m_start = start;
|
m_start = start;
|
||||||
m_end = end;
|
m_end = end;
|
||||||
|
|
||||||
query q(mDb, "SELECT name FROM jobshifts WHERE id=?");
|
query q(mDb, "SELECT name FROM jobshifts WHERE id=?");
|
||||||
q.bind(1, m_shiftId);
|
q.bind(1, m_shiftId);
|
||||||
if(q.step() != SQLITE_ROW)
|
if (q.step() != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
endResetModel();
|
endResetModel();
|
||||||
return;
|
return;
|
||||||
|
@ -118,7 +119,7 @@ void ShiftBusyModel::loadData(db_id shiftId, db_id jobId, const QTime &start, co
|
||||||
q.bind(2, m_start);
|
q.bind(2, m_start);
|
||||||
q.bind(3, m_end);
|
q.bind(3, m_end);
|
||||||
q.step();
|
q.step();
|
||||||
int count = q.getRows().get<int>(0) - 1; //Do not count ourself
|
int count = q.getRows().get<int>(0) - 1; // Do not count ourself
|
||||||
m_data.reserve(count);
|
m_data.reserve(count);
|
||||||
|
|
||||||
q.prepare("SELECT jobs.id, jobs.category,"
|
q.prepare("SELECT jobs.id, jobs.category,"
|
||||||
|
@ -133,20 +134,20 @@ void ShiftBusyModel::loadData(db_id shiftId, db_id jobId, const QTime &start, co
|
||||||
q.bind(2, m_start);
|
q.bind(2, m_start);
|
||||||
q.bind(3, m_end);
|
q.bind(3, m_end);
|
||||||
|
|
||||||
for(auto j : q)
|
for (auto j : q)
|
||||||
{
|
{
|
||||||
JobInfo info;
|
JobInfo info;
|
||||||
info.jobId = j.get<db_id>(0);
|
info.jobId = j.get<db_id>(0);
|
||||||
info.jobCat = JobCategory(j.get<int>(1));
|
info.jobCat = JobCategory(j.get<int>(1));
|
||||||
|
|
||||||
if(info.jobId == m_jobId)
|
if (info.jobId == m_jobId)
|
||||||
{
|
{
|
||||||
m_jobCat = info.jobCat;
|
m_jobCat = info.jobCat;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
info.start = j.get<QTime>(3);
|
info.start = j.get<QTime>(3);
|
||||||
info.end = j.get<QTime>(4);
|
info.end = j.get<QTime>(4);
|
||||||
|
|
||||||
m_data.append(info);
|
m_data.append(info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,14 @@ namespace sqlite3pp {
|
||||||
class database;
|
class database;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: move to shifts subdir
|
// TODO: move to shifts subdir
|
||||||
class ShiftBusyModel : public QAbstractTableModel
|
class ShiftBusyModel : public QAbstractTableModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum Columns
|
||||||
enum Columns {
|
{
|
||||||
JobCol = 0,
|
JobCol = 0,
|
||||||
Start,
|
Start,
|
||||||
End,
|
End,
|
||||||
|
@ -55,7 +55,8 @@ public:
|
||||||
ShiftBusyModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
ShiftBusyModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||||
|
|
||||||
// Header:
|
// Header:
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
// Basic functionality:
|
// Basic functionality:
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
@ -63,14 +64,26 @@ public:
|
||||||
|
|
||||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
void loadData(db_id shiftId, db_id jobId, const QTime& start, const QTime& end);
|
void loadData(db_id shiftId, db_id jobId, const QTime &start, const QTime &end);
|
||||||
|
|
||||||
inline bool hasConcurrentJobs() const { return m_data.size(); }
|
inline bool hasConcurrentJobs() const
|
||||||
|
{
|
||||||
|
return m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
inline QTime getStart() const { return m_start; }
|
inline QTime getStart() const
|
||||||
inline QTime getEnd() const { return m_end; }
|
{
|
||||||
|
return m_start;
|
||||||
|
}
|
||||||
|
inline QTime getEnd() const
|
||||||
|
{
|
||||||
|
return m_end;
|
||||||
|
}
|
||||||
|
|
||||||
inline QString getShiftName() const { return m_shiftName; }
|
inline QString getShiftName() const
|
||||||
|
{
|
||||||
|
return m_shiftName;
|
||||||
|
}
|
||||||
QString getJobName() const;
|
QString getJobName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -41,11 +41,11 @@ StopDelegate::StopDelegate(sqlite3pp::database &db, QObject *parent) :
|
||||||
void StopDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
void StopDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
QRect rect = option.rect.adjusted(5, 5, -5, -5);
|
QRect rect = option.rect.adjusted(5, 5, -5, -5);
|
||||||
|
|
||||||
const StopModel *model = static_cast<const StopModel *>(index.model());
|
const StopModel *model = static_cast<const StopModel *>(index.model());
|
||||||
const StopItem item = model->getItemAt(index.row());
|
const StopItem item = model->getItemAt(index.row());
|
||||||
const bool isTransit = item.type == StopType::Transit;
|
const bool isTransit = item.type == StopType::Transit;
|
||||||
|
|
||||||
query q(mDb, "SELECT name FROM stations WHERE id=?");
|
query q(mDb, "SELECT name FROM stations WHERE id=?");
|
||||||
q.bind(1, item.stationId);
|
q.bind(1, item.stationId);
|
||||||
|
@ -56,7 +56,7 @@ void StopDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
painter->save();
|
painter->save();
|
||||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
|
||||||
//Draw bottom border
|
// Draw bottom border
|
||||||
painter->setPen(QPen(Qt::black, 1));
|
painter->setPen(QPen(Qt::black, 1));
|
||||||
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
|
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
|
||||||
|
|
||||||
|
@ -73,120 +73,117 @@ void StopDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
|
|
||||||
painter->setBrush(option.palette.text());
|
painter->setBrush(option.palette.text());
|
||||||
|
|
||||||
const double top = rect.top();
|
const double top = rect.top();
|
||||||
const double bottom = rect.bottom();
|
const double bottom = rect.bottom();
|
||||||
const double left = rect.left();
|
const double left = rect.left();
|
||||||
const double width = rect.width();
|
const double width = rect.width();
|
||||||
const double height = rect.height();
|
const double height = rect.height();
|
||||||
|
|
||||||
const double stHeight = top + (isTransit ? 0.0 : height * 0.1);
|
const double stHeight = top + (isTransit ? 0.0 : height * 0.1);
|
||||||
const double timeHeight = top + height * 0.4;
|
const double timeHeight = top + height * 0.4;
|
||||||
const double lineHeight = top + height * 0.65;
|
const double lineHeight = top + height * 0.65;
|
||||||
|
|
||||||
const double arrX = left + width * (isTransit ? 0.4 : 0.2);
|
const double arrX = left + width * (isTransit ? 0.4 : 0.2);
|
||||||
const double depX = left + width * 0.6;
|
const double depX = left + width * 0.6;
|
||||||
const double transitLineX = left + width * 0.2;
|
const double transitLineX = left + width * 0.2;
|
||||||
|
|
||||||
|
if (item.addHere == 0)
|
||||||
if(item.addHere == 0)
|
|
||||||
{
|
{
|
||||||
//Draw item
|
// Draw item
|
||||||
//Station name
|
// Station name
|
||||||
painter->drawText(QRectF(left, stHeight, width, bottom - stHeight),
|
painter->drawText(QRectF(left, stHeight, width, bottom - stHeight), station,
|
||||||
station,
|
|
||||||
QTextOption(Qt::AlignHCenter));
|
QTextOption(Qt::AlignHCenter));
|
||||||
|
|
||||||
if(item.type != StopType::First)
|
if (item.type != StopType::First)
|
||||||
{
|
{
|
||||||
//Arrival
|
// Arrival
|
||||||
painter->drawText(QRectF(arrX, timeHeight, width, bottom - timeHeight),
|
painter->drawText(QRectF(arrX, timeHeight, width, bottom - timeHeight),
|
||||||
item.arrival.toString("HH:mm"));
|
item.arrival.toString("HH:mm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item.type == StopType::First || item.type == StopType::Normal) //Last, Transit don't have a separate departure
|
if (item.type == StopType::First
|
||||||
|
|| item.type == StopType::Normal) // Last, Transit don't have a separate departure
|
||||||
{
|
{
|
||||||
//Departure
|
// Departure
|
||||||
painter->drawText(QRectF(depX, timeHeight, width, bottom - timeHeight),
|
painter->drawText(QRectF(depX, timeHeight, width, bottom - timeHeight),
|
||||||
item.departure.toString("HH:mm"));
|
item.departure.toString("HH:mm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check direction
|
// Check direction
|
||||||
if(item.fromGate.gateConnId && item.toGate.gateConnId
|
if (item.fromGate.gateConnId && item.toGate.gateConnId && item.type != StopType::First
|
||||||
&& item.type != StopType::First && item.type != StopType::Last)
|
&& item.type != StopType::Last)
|
||||||
{
|
{
|
||||||
//Ignore First and Last stop (sometimes they have fake in/out gates set which might trigger this message)
|
// Ignore First and Last stop (sometimes they have fake in/out gates set which might
|
||||||
//Both entry and exit path are set, check direction
|
// trigger this message) Both entry and exit path are set, check direction
|
||||||
if(item.fromGate.stationTrackSide == item.toGate.stationTrackSide)
|
if (item.fromGate.stationTrackSide == item.toGate.stationTrackSide)
|
||||||
{
|
{
|
||||||
//Train leaves station track from same side of entrance, draw reverse icon
|
// Train leaves station track from same side of entrance, draw reverse icon
|
||||||
QPointF iconTopLeft(left, bottom - PixHeight);
|
QPointF iconTopLeft(left, bottom - PixHeight);
|
||||||
painter->drawPixmap(iconTopLeft, m_reverseDirPix);
|
painter->drawPixmap(iconTopLeft, m_reverseDirPix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item.type != StopType::Last && item.nextSegment.segmentId)
|
if (item.type != StopType::Last && item.nextSegment.segmentId)
|
||||||
{
|
{
|
||||||
//Last has no next segment so do not draw lightning
|
// Last has no next segment so do not draw lightning
|
||||||
|
|
||||||
bool nextSegmentElectrified = model->isRailwayElectrifiedAfterRow(index.row());
|
bool nextSegmentElectrified = model->isRailwayElectrifiedAfterRow(index.row());
|
||||||
bool prevSegmentElectrified = !nextSegmentElectrified; //Trigger change on First stop
|
bool prevSegmentElectrified = !nextSegmentElectrified; // Trigger change on First stop
|
||||||
|
|
||||||
if(item.type != StopType::First && index.row() >= 0)
|
if (item.type != StopType::First && index.row() >= 0)
|
||||||
{
|
{
|
||||||
//Get real previous railway type
|
// Get real previous railway type
|
||||||
prevSegmentElectrified = model->isRailwayElectrifiedAfterRow(index.row() - 1);
|
prevSegmentElectrified = model->isRailwayElectrifiedAfterRow(index.row() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nextSegmentElectrified != prevSegmentElectrified)
|
if (nextSegmentElectrified != prevSegmentElectrified)
|
||||||
{
|
{
|
||||||
//Railway type changed, draw a lightning
|
// Railway type changed, draw a lightning
|
||||||
QPointF lightningTopLeft(left, top + qMin(5.0, height * 0.1));
|
QPointF lightningTopLeft(left, top + qMin(5.0, height * 0.1));
|
||||||
painter->drawPixmap(lightningTopLeft, m_lightningPix);
|
painter->drawPixmap(lightningTopLeft, m_lightningPix);
|
||||||
|
|
||||||
if(!nextSegmentElectrified)
|
if (!nextSegmentElectrified)
|
||||||
{
|
{
|
||||||
//Next railway is not electrified, cross the lightning
|
// Next railway is not electrified, cross the lightning
|
||||||
//Then keep red pen to draw next segment name
|
// Then keep red pen to draw next segment name
|
||||||
painter->setPen(QPen(Qt::red, 4));
|
painter->setPen(QPen(Qt::red, 4));
|
||||||
painter->drawLine(lightningTopLeft, lightningTopLeft + QPointF(PixWidth, PixHeight));
|
painter->drawLine(lightningTopLeft,
|
||||||
|
lightningTopLeft + QPointF(PixWidth, PixHeight));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Draw next segment name
|
// Draw next segment name
|
||||||
q.prepare("SELECT name FROM railway_segments WHERE id=?");
|
q.prepare("SELECT name FROM railway_segments WHERE id=?");
|
||||||
q.bind(1, item.nextSegment.segmentId);
|
q.bind(1, item.nextSegment.segmentId);
|
||||||
q.step();
|
q.step();
|
||||||
auto r = q.getRows();
|
auto r = q.getRows();
|
||||||
const QString segName = r.get<QString>(0);
|
const QString segName = r.get<QString>(0);
|
||||||
q.reset();
|
q.reset();
|
||||||
|
|
||||||
const double lineRightX = left + width * 0.8;
|
const double lineRightX = left + width * 0.8;
|
||||||
painter->drawText(QRectF(transitLineX, lineHeight, lineRightX - left, bottom - lineHeight),
|
painter->drawText(
|
||||||
tr("Seg: %1").arg(segName),
|
QRectF(transitLineX, lineHeight, lineRightX - left, bottom - lineHeight),
|
||||||
QTextOption(Qt::AlignHCenter));
|
tr("Seg: %1").arg(segName), QTextOption(Qt::AlignHCenter));
|
||||||
|
|
||||||
if(item.toGate.gateTrackNum != 0)
|
if (item.toGate.gateTrackNum != 0)
|
||||||
{
|
{
|
||||||
painter->setPen(QPen(Qt::red, 4));
|
painter->setPen(QPen(Qt::red, 4));
|
||||||
painter->drawText(QRectF(lineRightX, lineHeight, left + width - lineRightX, bottom - lineHeight),
|
painter->drawText(
|
||||||
QString::number(item.toGate.gateTrackNum),
|
QRectF(lineRightX, lineHeight, left + width - lineRightX, bottom - lineHeight),
|
||||||
QTextOption(Qt::AlignHCenter));
|
QString::number(item.toGate.gateTrackNum), QTextOption(Qt::AlignHCenter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isTransit)
|
if (isTransit)
|
||||||
{
|
{
|
||||||
//Draw a vertical -0- to tell this is a transit
|
// Draw a vertical -0- to tell this is a transit
|
||||||
painter->setPen(QPen(Qt::red, 4));
|
painter->setPen(QPen(Qt::red, 4));
|
||||||
painter->setBrush(Qt::red);
|
painter->setBrush(Qt::red);
|
||||||
painter->drawLine(QLineF(transitLineX, rect.top(),
|
painter->drawLine(QLineF(transitLineX, rect.top(), transitLineX, rect.bottom()));
|
||||||
transitLineX, rect.bottom()));
|
|
||||||
|
|
||||||
painter->drawEllipse(QRectF(transitLineX - 12 / 2,
|
painter->drawEllipse(
|
||||||
rect.top() + rect.height() * 0.4,
|
QRectF(transitLineX - 12 / 2, rect.top() + rect.height() * 0.4, 12, 12));
|
||||||
12, 12));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (item.addHere == 1)
|
else if (item.addHere == 1)
|
||||||
{
|
{
|
||||||
|
@ -200,30 +197,29 @@ void StopDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize StopDelegate::sizeHint(const QStyleOptionViewItem &/*option*/,
|
QSize StopDelegate::sizeHint(const QStyleOptionViewItem & /*option*/,
|
||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
int w = 200;
|
int w = 200;
|
||||||
int h = NormalStopHeight;
|
int h = NormalStopHeight;
|
||||||
const StopModel *model = static_cast<const StopModel *>(index.model());
|
const StopModel *model = static_cast<const StopModel *>(index.model());
|
||||||
if(index.row() < 0 || index.row() >= model->rowCount())
|
if (index.row() < 0 || index.row() >= model->rowCount())
|
||||||
return QSize(w, AddHereHeight);
|
return QSize(w, AddHereHeight);
|
||||||
|
|
||||||
const StopItem& item = model->getItemAt(index.row());
|
const StopItem &item = model->getItemAt(index.row());
|
||||||
if(item.type == StopType::Transit)
|
if (item.type == StopType::Transit)
|
||||||
h = TransitStopHeight;
|
h = TransitStopHeight;
|
||||||
if(item.addHere != 0)
|
if (item.addHere != 0)
|
||||||
h = AddHereHeight;
|
h = AddHereHeight;
|
||||||
return QSize(w, h);
|
return QSize(w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *StopDelegate::createEditor(QWidget *parent,
|
QWidget *StopDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/,
|
||||||
const QStyleOptionViewItem &/*option*/,
|
|
||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
|
|
||||||
{
|
{
|
||||||
StopModel *model = const_cast<StopModel*>(static_cast<const StopModel *>(index.model()));
|
StopModel *model = const_cast<StopModel *>(static_cast<const StopModel *>(index.model()));
|
||||||
if(model->isAddHere(index))
|
if (model->isAddHere(index))
|
||||||
{
|
{
|
||||||
qDebug() << index << "is AddHere";
|
qDebug() << index << "is AddHere";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -231,35 +227,34 @@ QWidget *StopDelegate::createEditor(QWidget *parent,
|
||||||
|
|
||||||
StopEditor *editor = new StopEditor(mDb, model, parent);
|
StopEditor *editor = new StopEditor(mDb, model, parent);
|
||||||
editor->setAutoFillBackground(true);
|
editor->setAutoFillBackground(true);
|
||||||
editor->setEnabled(false); //Mark it
|
editor->setEnabled(false); // Mark it
|
||||||
|
|
||||||
//Prevent JobPathEditor context menu in table view during stop editing
|
// Prevent JobPathEditor context menu in table view during stop editing
|
||||||
editor->setContextMenuPolicy(Qt::PreventContextMenu);
|
editor->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||||
|
|
||||||
//See 'StopEditor::popupLinesCombo'
|
// See 'StopEditor::popupLinesCombo'
|
||||||
connect(this, &StopDelegate::popupEditorSegmentCombo, editor, &StopEditor::popupSegmentCombo);
|
connect(this, &StopDelegate::popupEditorSegmentCombo, editor, &StopEditor::popupSegmentCombo);
|
||||||
connect(editor, &StopEditor::nextSegmentChosen, this, &StopDelegate::onEditorSegmentChosen);
|
connect(editor, &StopEditor::nextSegmentChosen, this, &StopDelegate::onEditorSegmentChosen);
|
||||||
|
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopDelegate::setEditorData(QWidget *editor,
|
void StopDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||||
const QModelIndex &index) const
|
|
||||||
{
|
{
|
||||||
StopEditor *ed = static_cast<StopEditor*>(editor);
|
StopEditor *ed = static_cast<StopEditor *>(editor);
|
||||||
if(ed->isEnabled()) //We already set data
|
if (ed->isEnabled()) // We already set data
|
||||||
return;
|
return;
|
||||||
ed->setEnabled(true); //Mark it
|
ed->setEnabled(true); // Mark it
|
||||||
|
|
||||||
const StopModel *model = static_cast<const StopModel *>(index.model());
|
const StopModel *model = static_cast<const StopModel *>(index.model());
|
||||||
|
|
||||||
const StopItem item = model->getItemAt(index.row());
|
const StopItem item = model->getItemAt(index.row());
|
||||||
StopItem prev;
|
StopItem prev;
|
||||||
|
|
||||||
int r = index.row();
|
int r = index.row();
|
||||||
if(r > 0)
|
if (r > 0)
|
||||||
{
|
{
|
||||||
//Current stop is not First, get also previous one
|
// Current stop is not First, get also previous one
|
||||||
prev = model->getItemAt(r - 1);
|
prev = model->getItemAt(r - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +267,7 @@ void StopDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||||
DEBUG_IMPORTANT_ENTRY;
|
DEBUG_IMPORTANT_ENTRY;
|
||||||
|
|
||||||
qDebug() << "End editing: stop" << index.row();
|
qDebug() << "End editing: stop" << index.row();
|
||||||
StopEditor *ed = static_cast<StopEditor*>(editor);
|
StopEditor *ed = static_cast<StopEditor *>(editor);
|
||||||
StopModel *stopModel = static_cast<StopModel *>(model);
|
StopModel *stopModel = static_cast<StopModel *>(model);
|
||||||
|
|
||||||
bool avoidTimeRecalc = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
bool avoidTimeRecalc = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||||
|
@ -280,14 +275,15 @@ void StopDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||||
stopModel->setStopInfo(index, ed->getCurItem(), ed->getPrevItem().nextSegment, avoidTimeRecalc);
|
stopModel->setStopInfo(index, ed->getCurItem(), ed->getPrevItem().nextSegment, avoidTimeRecalc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
|
void StopDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex & /*index*/) const
|
||||||
{
|
{
|
||||||
editor->setGeometry(option.rect);
|
editor->setGeometry(option.rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopDelegate::onEditorSegmentChosen(StopEditor *editor)
|
void StopDelegate::onEditorSegmentChosen(StopEditor *editor)
|
||||||
{
|
{
|
||||||
if(editor->closeOnSegmentChosen())
|
if (editor->closeOnSegmentChosen())
|
||||||
{
|
{
|
||||||
emit commitData(editor);
|
emit commitData(editor);
|
||||||
emit closeEditor(editor, StopDelegate::EditNextItem);
|
emit closeEditor(editor, StopDelegate::EditNextItem);
|
||||||
|
@ -296,10 +292,11 @@ void StopDelegate::onEditorSegmentChosen(StopEditor *editor)
|
||||||
|
|
||||||
void StopDelegate::refreshPixmaps()
|
void StopDelegate::refreshPixmaps()
|
||||||
{
|
{
|
||||||
const QString iconPath = QCoreApplication::instance()->applicationDirPath() + QStringLiteral("/icons");
|
const QString iconPath =
|
||||||
|
QCoreApplication::instance()->applicationDirPath() + QStringLiteral("/icons");
|
||||||
|
|
||||||
//Square pixmaps
|
// Square pixmaps
|
||||||
m_lightningPix = QPixmap(PixWidth, PixHeight);
|
m_lightningPix = QPixmap(PixWidth, PixHeight);
|
||||||
m_reverseDirPix = QPixmap(PixWidth, PixHeight);
|
m_reverseDirPix = QPixmap(PixWidth, PixHeight);
|
||||||
|
|
||||||
m_lightningPix.fill(Qt::transparent);
|
m_lightningPix.fill(Qt::transparent);
|
||||||
|
@ -309,26 +306,26 @@ void StopDelegate::refreshPixmaps()
|
||||||
QPainter painter;
|
QPainter painter;
|
||||||
QRectF iconRect;
|
QRectF iconRect;
|
||||||
|
|
||||||
//Cache Lightning
|
// Cache Lightning
|
||||||
mSvg.load(iconPath + QStringLiteral("/lightning.svg"));
|
mSvg.load(iconPath + QStringLiteral("/lightning.svg"));
|
||||||
|
|
||||||
//Scale SVG to fit requested size
|
// Scale SVG to fit requested size
|
||||||
iconRect.setSize(mSvg.defaultSize().scaled(PixWidth, PixHeight, Qt::KeepAspectRatio));
|
iconRect.setSize(mSvg.defaultSize().scaled(PixWidth, PixHeight, Qt::KeepAspectRatio));
|
||||||
|
|
||||||
//Center on pixmap
|
// Center on pixmap
|
||||||
iconRect.moveTop((PixHeight - iconRect.height()) / 2);
|
iconRect.moveTop((PixHeight - iconRect.height()) / 2);
|
||||||
iconRect.moveLeft((PixWidth - iconRect.width()) / 2);
|
iconRect.moveLeft((PixWidth - iconRect.width()) / 2);
|
||||||
painter.begin(&m_lightningPix);
|
painter.begin(&m_lightningPix);
|
||||||
mSvg.render(&painter, iconRect);
|
mSvg.render(&painter, iconRect);
|
||||||
painter.end();
|
painter.end();
|
||||||
|
|
||||||
//Cache Reverse Direction
|
// Cache Reverse Direction
|
||||||
mSvg.load(iconPath + QStringLiteral("/reverse_direction.svg"));
|
mSvg.load(iconPath + QStringLiteral("/reverse_direction.svg"));
|
||||||
|
|
||||||
//Scale SVG to fit requested size
|
// Scale SVG to fit requested size
|
||||||
iconRect.setSize(mSvg.defaultSize().scaled(PixWidth, PixHeight, Qt::KeepAspectRatio));
|
iconRect.setSize(mSvg.defaultSize().scaled(PixWidth, PixHeight, Qt::KeepAspectRatio));
|
||||||
|
|
||||||
//Center on pixmap
|
// Center on pixmap
|
||||||
iconRect.moveTop((PixHeight - iconRect.height()) / 2);
|
iconRect.moveTop((PixHeight - iconRect.height()) / 2);
|
||||||
iconRect.moveLeft((PixWidth - iconRect.width()) / 2);
|
iconRect.moveLeft((PixWidth - iconRect.width()) / 2);
|
||||||
painter.begin(&m_reverseDirPix);
|
painter.begin(&m_reverseDirPix);
|
||||||
|
|
|
@ -46,15 +46,15 @@ public:
|
||||||
|
|
||||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index) const override;
|
const QModelIndex &index) const override;
|
||||||
QSize sizeHint(const QStyleOptionViewItem &option,
|
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
const QModelIndex &index) const override;
|
|
||||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index) const override;
|
const QModelIndex &index) const override;
|
||||||
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
||||||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||||
const QModelIndex &index) const override;
|
const QModelIndex &index) const override;
|
||||||
|
|
||||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const override;
|
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &) const override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/*!
|
/*!
|
||||||
|
@ -87,12 +87,12 @@ private:
|
||||||
QPixmap m_lightningPix;
|
QPixmap m_lightningPix;
|
||||||
QPixmap m_reverseDirPix;
|
QPixmap m_reverseDirPix;
|
||||||
|
|
||||||
static constexpr int NormalStopHeight = 100;
|
static constexpr int NormalStopHeight = 100;
|
||||||
static constexpr int TransitStopHeight = 80;
|
static constexpr int TransitStopHeight = 80;
|
||||||
static constexpr int AddHereHeight = 30;
|
static constexpr int AddHereHeight = 30;
|
||||||
|
|
||||||
static constexpr int PixWidth = 35;
|
static constexpr int PixWidth = 35;
|
||||||
static constexpr int PixHeight = PixWidth;
|
static constexpr int PixHeight = PixWidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STOPDELEGATE_H
|
#endif // STOPDELEGATE_H
|
||||||
|
|
|
@ -33,43 +33,47 @@
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
StopEditingHelper::StopEditingHelper(database &db, StopModel *m,
|
StopEditingHelper::StopEditingHelper(database &db, StopModel *m, QSpinBox *outTrackSpin,
|
||||||
QSpinBox *outTrackSpin, QTimeEdit *arr, QTimeEdit *dep,
|
QTimeEdit *arr, QTimeEdit *dep, QWidget *editor) :
|
||||||
QWidget *editor) :
|
|
||||||
QObject(editor),
|
QObject(editor),
|
||||||
mEditor(editor),
|
mEditor(editor),
|
||||||
model(m),
|
model(m),
|
||||||
mTimerOutTrack(0)
|
mTimerOutTrack(0)
|
||||||
{
|
{
|
||||||
stationsMatchModel = new StationsMatchModel(db, this);
|
stationsMatchModel = new StationsMatchModel(db, this);
|
||||||
stationTrackMatchModel = new StationTracksMatchModel(db, this);
|
stationTrackMatchModel = new StationTracksMatchModel(db, this);
|
||||||
stationOutGateMatchModel = new StationGatesMatchModel(db, this);
|
stationOutGateMatchModel = new StationGatesMatchModel(db, this);
|
||||||
|
|
||||||
mStationEdit = new CustomCompletionLineEdit(stationsMatchModel, mEditor);
|
mStationEdit = new CustomCompletionLineEdit(stationsMatchModel, mEditor);
|
||||||
mStationEdit->setPlaceholderText(tr("Station name"));
|
mStationEdit->setPlaceholderText(tr("Station name"));
|
||||||
mStationEdit->setToolTip(mStationEdit->placeholderText());
|
mStationEdit->setToolTip(mStationEdit->placeholderText());
|
||||||
connect(mStationEdit, &CustomCompletionLineEdit::completionDone, this, &StopEditingHelper::onStationSelected);
|
connect(mStationEdit, &CustomCompletionLineEdit::completionDone, this,
|
||||||
|
&StopEditingHelper::onStationSelected);
|
||||||
|
|
||||||
mStTrackEdit = new CustomCompletionLineEdit(stationTrackMatchModel, mEditor);
|
mStTrackEdit = new CustomCompletionLineEdit(stationTrackMatchModel, mEditor);
|
||||||
mStTrackEdit->setPlaceholderText(tr("Track"));
|
mStTrackEdit->setPlaceholderText(tr("Track"));
|
||||||
mStTrackEdit->setToolTip(mStTrackEdit->placeholderText());
|
mStTrackEdit->setToolTip(mStTrackEdit->placeholderText());
|
||||||
connect(mStTrackEdit, &CustomCompletionLineEdit::completionDone, this, &StopEditingHelper::onTrackSelected);
|
connect(mStTrackEdit, &CustomCompletionLineEdit::completionDone, this,
|
||||||
|
&StopEditingHelper::onTrackSelected);
|
||||||
|
|
||||||
mOutGateEdit = new CustomCompletionLineEdit(stationOutGateMatchModel, mEditor);
|
mOutGateEdit = new CustomCompletionLineEdit(stationOutGateMatchModel, mEditor);
|
||||||
mOutGateEdit->setPlaceholderText(tr("Next segment"));
|
mOutGateEdit->setPlaceholderText(tr("Next segment"));
|
||||||
mOutGateEdit->setToolTip(mOutGateEdit->placeholderText());
|
mOutGateEdit->setToolTip(mOutGateEdit->placeholderText());
|
||||||
connect(mOutGateEdit, &CustomCompletionLineEdit::indexSelected, this, &StopEditingHelper::onOutGateSelected);
|
connect(mOutGateEdit, &CustomCompletionLineEdit::indexSelected, this,
|
||||||
|
&StopEditingHelper::onOutGateSelected);
|
||||||
|
|
||||||
mOutGateTrackSpin = outTrackSpin;
|
mOutGateTrackSpin = outTrackSpin;
|
||||||
mOutGateTrackSpin->setMaximum(0);
|
mOutGateTrackSpin->setMaximum(0);
|
||||||
mOutGateTrackSpin->setToolTip(tr("Out Gate track"));
|
mOutGateTrackSpin->setToolTip(tr("Out Gate track"));
|
||||||
connect(mOutGateTrackSpin, qOverload<int>(&QSpinBox::valueChanged), this, &StopEditingHelper::startOutTrackTimer);
|
connect(mOutGateTrackSpin, qOverload<int>(&QSpinBox::valueChanged), this,
|
||||||
connect(mOutGateTrackSpin, &QSpinBox::editingFinished, this, &StopEditingHelper::checkOutGateTrack);
|
&StopEditingHelper::startOutTrackTimer);
|
||||||
|
connect(mOutGateTrackSpin, &QSpinBox::editingFinished, this,
|
||||||
|
&StopEditingHelper::checkOutGateTrack);
|
||||||
|
|
||||||
arrEdit = arr;
|
arrEdit = arr;
|
||||||
depEdit = dep;
|
depEdit = dep;
|
||||||
|
|
||||||
//Do not set tooltip on arrEdit, it is done inside setStop() already
|
// Do not set tooltip on arrEdit, it is done inside setStop() already
|
||||||
depEdit->setToolTip(tr("Departure"));
|
depEdit->setToolTip(tr("Departure"));
|
||||||
|
|
||||||
connect(arrEdit, &QTimeEdit::timeChanged, this, &StopEditingHelper::arrivalChanged);
|
connect(arrEdit, &QTimeEdit::timeChanged, this, &StopEditingHelper::arrivalChanged);
|
||||||
|
@ -83,69 +87,70 @@ StopEditingHelper::~StopEditingHelper()
|
||||||
|
|
||||||
void StopEditingHelper::setStop(const StopItem &item, const StopItem &prev)
|
void StopEditingHelper::setStop(const StopItem &item, const StopItem &prev)
|
||||||
{
|
{
|
||||||
curStop = item;
|
curStop = item;
|
||||||
prevStop = prev;
|
prevStop = prev;
|
||||||
|
|
||||||
//Update match models
|
// Update match models
|
||||||
stationsMatchModel->setFilter(prevStop.stationId);
|
stationsMatchModel->setFilter(prevStop.stationId);
|
||||||
stationTrackMatchModel->setFilter(curStop.stationId);
|
stationTrackMatchModel->setFilter(curStop.stationId);
|
||||||
stationOutGateMatchModel->setFilter(curStop.stationId, true, prevStop.nextSegment.segmentId, true);
|
stationOutGateMatchModel->setFilter(curStop.stationId, true, prevStop.nextSegment.segmentId,
|
||||||
|
true);
|
||||||
|
|
||||||
//Check Arrival and Departure
|
// Check Arrival and Departure
|
||||||
QTime minArr, minDep;
|
QTime minArr, minDep;
|
||||||
if(curStop.type != StopType::First)
|
if (curStop.type != StopType::First)
|
||||||
{
|
{
|
||||||
//First stop: arrival is hidden, you can change only departure so do not set a minimum
|
// First stop: arrival is hidden, you can change only departure so do not set a minimum
|
||||||
|
|
||||||
//Next stop must be at least one minute after previous (minimum travel duration)
|
// Next stop must be at least one minute after previous (minimum travel duration)
|
||||||
//This is to prevent contemporary stops that will break ORDER BY arrival queries
|
// This is to prevent contemporary stops that will break ORDER BY arrival queries
|
||||||
minArr = prevStop.departure.addSecs(60);
|
minArr = prevStop.departure.addSecs(60);
|
||||||
|
|
||||||
//Normal stop: at least 1 minute stop
|
// Normal stop: at least 1 minute stop
|
||||||
//Transit, Last: departure = arrival
|
// Transit, Last: departure = arrival
|
||||||
minDep = curStop.arrival;
|
minDep = curStop.arrival;
|
||||||
if(curStop.type == StopType::Normal)
|
if (curStop.type == StopType::Normal)
|
||||||
minDep = minDep.addSecs(60);
|
minDep = minDep.addSecs(60);
|
||||||
|
|
||||||
if(curStop.arrival < minArr)
|
if (curStop.arrival < minArr)
|
||||||
curStop.arrival = minArr;
|
curStop.arrival = minArr;
|
||||||
|
|
||||||
if(curStop.departure < minDep)
|
if (curStop.departure < minDep)
|
||||||
curStop.arrival = minDep;
|
curStop.arrival = minDep;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Show/Hide relevant fields for current stop
|
// Show/Hide relevant fields for current stop
|
||||||
|
|
||||||
//First stop has no Arrival, only Departure
|
// First stop has no Arrival, only Departure
|
||||||
arrEdit->setEnabled(curStop.type != StopType::First);
|
arrEdit->setEnabled(curStop.type != StopType::First);
|
||||||
arrEdit->setVisible(curStop.type != StopType::First);
|
arrEdit->setVisible(curStop.type != StopType::First);
|
||||||
|
|
||||||
QString arrTootlip = tr("Arrival"); //No message by default
|
QString arrTootlip = tr("Arrival"); // No message by default
|
||||||
if(curStop.type == StopType::Normal)
|
if (curStop.type == StopType::Normal)
|
||||||
{
|
{
|
||||||
arrTootlip.append('\n'); //Separate from usage tooltip
|
arrTootlip.append('\n'); // Separate from usage tooltip
|
||||||
arrTootlip.append(tr("Press shift if you don't want to change also departure time."));
|
arrTootlip.append(tr("Press shift if you don't want to change also departure time."));
|
||||||
}
|
}
|
||||||
arrEdit->setToolTip(arrTootlip);
|
arrEdit->setToolTip(arrTootlip);
|
||||||
|
|
||||||
//Transit and Last stop only have Arrival
|
// Transit and Last stop only have Arrival
|
||||||
depEdit->setEnabled(curStop.type != StopType::Last && curStop.type != StopType::Transit);
|
depEdit->setEnabled(curStop.type != StopType::Last && curStop.type != StopType::Transit);
|
||||||
depEdit->setVisible(curStop.type != StopType::Last && curStop.type != StopType::Transit);
|
depEdit->setVisible(curStop.type != StopType::Last && curStop.type != StopType::Transit);
|
||||||
|
|
||||||
//Last stop has no Out Gate because there's no stop after last
|
// Last stop has no Out Gate because there's no stop after last
|
||||||
mOutGateEdit->setVisible(curStop.type != StopType::Last);
|
mOutGateEdit->setVisible(curStop.type != StopType::Last);
|
||||||
mOutGateTrackSpin->setVisible(curStop.type != StopType::Last);
|
mOutGateTrackSpin->setVisible(curStop.type != StopType::Last);
|
||||||
|
|
||||||
//Enable track edit only if station is selected
|
// Enable track edit only if station is selected
|
||||||
mStTrackEdit->setEnabled(curStop.stationId != 0);
|
mStTrackEdit->setEnabled(curStop.stationId != 0);
|
||||||
|
|
||||||
//Update UI fields
|
// Update UI fields
|
||||||
mStationEdit->setData(curStop.stationId);
|
mStationEdit->setData(curStop.stationId);
|
||||||
mStTrackEdit->setData(curStop.trackId);
|
mStTrackEdit->setData(curStop.trackId);
|
||||||
mOutGateEdit->setData(curStop.toGate.gateId);
|
mOutGateEdit->setData(curStop.toGate.gateId);
|
||||||
updateGateTrackSpin(curStop.toGate);
|
updateGateTrackSpin(curStop.toGate);
|
||||||
|
|
||||||
//Set Arrival and Departure
|
// Set Arrival and Departure
|
||||||
arrEdit->blockSignals(true);
|
arrEdit->blockSignals(true);
|
||||||
arrEdit->setMinimumTime(minArr);
|
arrEdit->setMinimumTime(minArr);
|
||||||
arrEdit->setTime(curStop.arrival);
|
arrEdit->setTime(curStop.arrival);
|
||||||
|
@ -159,39 +164,41 @@ void StopEditingHelper::setStop(const StopItem &item, const StopItem &prev)
|
||||||
|
|
||||||
void StopEditingHelper::popupSegmentCombo()
|
void StopEditingHelper::popupSegmentCombo()
|
||||||
{
|
{
|
||||||
//Look for all possible segments
|
// Look for all possible segments
|
||||||
stationOutGateMatchModel->autoSuggest(QString());
|
stationOutGateMatchModel->autoSuggest(QString());
|
||||||
|
|
||||||
const int count = stationOutGateMatchModel->rowCount();
|
const int count = stationOutGateMatchModel->rowCount();
|
||||||
if(count > 1 && !stationOutGateMatchModel->isEmptyRow(0)
|
if (count > 1 && !stationOutGateMatchModel->isEmptyRow(0)
|
||||||
&& (stationOutGateMatchModel->isEmptyRow(1) || stationOutGateMatchModel->isEllipsesRow(1)))
|
&& (stationOutGateMatchModel->isEmptyRow(1) || stationOutGateMatchModel->isEllipsesRow(1)))
|
||||||
{
|
{
|
||||||
//Only 1 segment available, use it
|
// Only 1 segment available, use it
|
||||||
db_id newSegId = stationOutGateMatchModel->getSegmentIdAtRow(0);
|
db_id newSegId = stationOutGateMatchModel->getSegmentIdAtRow(0);
|
||||||
|
|
||||||
db_id segOutGateId = 0;
|
db_id segOutGateId = 0;
|
||||||
db_id suggestedTrackId = 0;
|
db_id suggestedTrackId = 0;
|
||||||
if(model->trySelectNextSegment(curStop, newSegId, 0, 0, segOutGateId, suggestedTrackId))
|
if (model->trySelectNextSegment(curStop, newSegId, 0, 0, segOutGateId, suggestedTrackId))
|
||||||
{
|
{
|
||||||
//Success, close editor
|
// Success, close editor
|
||||||
emit nextSegmentChosen();
|
emit nextSegmentChosen();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//We have multiple segments, let the user choose
|
// We have multiple segments, let the user choose
|
||||||
mOutGateEdit->showPopup();
|
mOutGateEdit->showPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString StopEditingHelper::getGateString(db_id gateId, bool reversed)
|
QString StopEditingHelper::getGateString(db_id gateId, bool reversed)
|
||||||
{
|
{
|
||||||
QString str = QLatin1String("<b>");
|
QString str = QLatin1String("<b>");
|
||||||
if(gateId)
|
if (gateId)
|
||||||
{
|
{
|
||||||
str += stationOutGateMatchModel->getName(gateId);
|
str += stationOutGateMatchModel->getName(gateId);
|
||||||
if(reversed)
|
if (reversed)
|
||||||
str += tr(" (reversed)");
|
str += tr(" (reversed)");
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
str += tr("Not set!");
|
str += tr("Not set!");
|
||||||
}
|
}
|
||||||
str.append(QLatin1String("</b>"));
|
str.append(QLatin1String("</b>"));
|
||||||
|
@ -200,7 +207,7 @@ QString StopEditingHelper::getGateString(db_id gateId, bool reversed)
|
||||||
|
|
||||||
void StopEditingHelper::timerEvent(QTimerEvent *e)
|
void StopEditingHelper::timerEvent(QTimerEvent *e)
|
||||||
{
|
{
|
||||||
if(e->timerId() == mTimerOutTrack)
|
if (e->timerId() == mTimerOutTrack)
|
||||||
{
|
{
|
||||||
checkOutGateTrack();
|
checkOutGateTrack();
|
||||||
return;
|
return;
|
||||||
|
@ -213,32 +220,33 @@ void StopEditingHelper::onStationSelected()
|
||||||
{
|
{
|
||||||
db_id newStId = 0;
|
db_id newStId = 0;
|
||||||
QString tmp;
|
QString tmp;
|
||||||
if(!mStationEdit->getData(newStId, tmp))
|
if (!mStationEdit->getData(newStId, tmp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(newStId == curStop.stationId)
|
if (newStId == curStop.stationId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
curStop.stationId = newStId;
|
curStop.stationId = newStId;
|
||||||
|
|
||||||
//Update track
|
// Update track
|
||||||
stationTrackMatchModel->setFilter(curStop.stationId);
|
stationTrackMatchModel->setFilter(curStop.stationId);
|
||||||
mStTrackEdit->setEnabled(curStop.stationId != 0); //Enable only if station is selected
|
mStTrackEdit->setEnabled(curStop.stationId != 0); // Enable only if station is selected
|
||||||
|
|
||||||
if(curStop.stationId)
|
if (curStop.stationId)
|
||||||
{
|
{
|
||||||
if(!model->trySelectTrackForStop(curStop))
|
if (!model->trySelectTrackForStop(curStop))
|
||||||
curStop.trackId = 0; //Could not find a track
|
curStop.trackId = 0; // Could not find a track
|
||||||
|
|
||||||
mStTrackEdit->setData(curStop.trackId);
|
mStTrackEdit->setData(curStop.trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update prev segment
|
// Update prev segment
|
||||||
prevStop.nextSegment = StopItem::Segment{}; //Reset, will be reloaded by model
|
prevStop.nextSegment = StopItem::Segment{}; // Reset, will be reloaded by model
|
||||||
|
|
||||||
//Update next segment
|
// Update next segment
|
||||||
stationOutGateMatchModel->setFilter(curStop.stationId, true, prevStop.nextSegment.segmentId, true);
|
stationOutGateMatchModel->setFilter(curStop.stationId, true, prevStop.nextSegment.segmentId,
|
||||||
mOutGateEdit->setData(0); //Reset, user must choose again
|
true);
|
||||||
|
mOutGateEdit->setData(0); // Reset, user must choose again
|
||||||
|
|
||||||
curStop.nextSegment = StopItem::Segment{};
|
curStop.nextSegment = StopItem::Segment{};
|
||||||
|
|
||||||
|
@ -249,19 +257,19 @@ void StopEditingHelper::onTrackSelected()
|
||||||
{
|
{
|
||||||
db_id newTrackId = 0;
|
db_id newTrackId = 0;
|
||||||
QString str;
|
QString str;
|
||||||
if(!mStTrackEdit->getData(newTrackId, str))
|
if (!mStTrackEdit->getData(newTrackId, str))
|
||||||
return;
|
return;
|
||||||
str.clear();
|
str.clear();
|
||||||
|
|
||||||
//Check if track is connected to gates
|
// Check if track is connected to gates
|
||||||
if(!model->trySetTrackConnections(curStop, newTrackId, &str))
|
if (!model->trySetTrackConnections(curStop, newTrackId, &str))
|
||||||
{
|
{
|
||||||
//Show error to the user
|
// Show error to the user
|
||||||
bool stillSucceded = (curStop.trackId == newTrackId);
|
bool stillSucceded = (curStop.trackId == newTrackId);
|
||||||
QMessageBox::warning(mEditor, stillSucceded ? tr("Gate Warning") : tr("Track Error"), str);
|
QMessageBox::warning(mEditor, stillSucceded ? tr("Gate Warning") : tr("Track Error"), str);
|
||||||
|
|
||||||
if(!stillSucceded)
|
if (!stillSucceded)
|
||||||
mStTrackEdit->setData(curStop.trackId); //Reset to previous track
|
mStTrackEdit->setData(curStop.trackId); // Reset to previous track
|
||||||
}
|
}
|
||||||
|
|
||||||
emit stationTrackChosen();
|
emit stationTrackChosen();
|
||||||
|
@ -271,25 +279,26 @@ void StopEditingHelper::onOutGateSelected(const QModelIndex &idx)
|
||||||
{
|
{
|
||||||
db_id newGateId = 0;
|
db_id newGateId = 0;
|
||||||
QString gateSegmentName;
|
QString gateSegmentName;
|
||||||
if(!mOutGateEdit->getData(newGateId, gateSegmentName))
|
if (!mOutGateEdit->getData(newGateId, gateSegmentName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const db_id newSegId = stationOutGateMatchModel->getSegmentIdAtRow(idx.row());
|
const db_id newSegId = stationOutGateMatchModel->getSegmentIdAtRow(idx.row());
|
||||||
const db_id oldGateId = curStop.toGate.gateId;
|
const db_id oldGateId = curStop.toGate.gateId;
|
||||||
db_id segOutGateId = 0;
|
db_id segOutGateId = 0;
|
||||||
db_id suggestedTrackId = 0;
|
db_id suggestedTrackId = 0;
|
||||||
if(model->trySelectNextSegment(curStop, newSegId, 0, 0, segOutGateId, suggestedTrackId))
|
if (model->trySelectNextSegment(curStop, newSegId, 0, 0, segOutGateId, suggestedTrackId))
|
||||||
{
|
{
|
||||||
//Update gate track
|
// Update gate track
|
||||||
updateGateTrackSpin(curStop.toGate);
|
updateGateTrackSpin(curStop.toGate);
|
||||||
|
|
||||||
//Success, close editor
|
// Success, close editor
|
||||||
emit nextSegmentChosen();
|
emit nextSegmentChosen();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Warn user and reset to previous chosen segment if any
|
// Warn user and reset to previous chosen segment if any
|
||||||
QMessageBox::warning(mEditor, tr("Stop Error"), tr("Cannot set segment <b>%1</b>").arg(gateSegmentName));
|
QMessageBox::warning(mEditor, tr("Stop Error"),
|
||||||
|
tr("Cannot set segment <b>%1</b>").arg(gateSegmentName));
|
||||||
mOutGateEdit->setData(oldGateId);
|
mOutGateEdit->setData(oldGateId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,38 +307,40 @@ void StopEditingHelper::checkOutGateTrack()
|
||||||
{
|
{
|
||||||
stopOutTrackTimer();
|
stopOutTrackTimer();
|
||||||
|
|
||||||
if(!curStop.nextSegment.segmentId)
|
if (!curStop.nextSegment.segmentId)
|
||||||
return; //First we need to have a segment
|
return; // First we need to have a segment
|
||||||
|
|
||||||
int trackNum = mOutGateTrackSpin->value();
|
int trackNum = mOutGateTrackSpin->value();
|
||||||
curStop.toGate.gateTrackNum = trackNum; //Trigger checking of railway segment connections
|
curStop.toGate.gateTrackNum = trackNum; // Trigger checking of railway segment connections
|
||||||
|
|
||||||
db_id segOutGateId = 0;
|
db_id segOutGateId = 0;
|
||||||
db_id suggestedTrackId = 0;
|
db_id suggestedTrackId = 0;
|
||||||
if(model->trySelectNextSegment(curStop, curStop.nextSegment.segmentId, trackNum, 0, segOutGateId, suggestedTrackId))
|
if (model->trySelectNextSegment(curStop, curStop.nextSegment.segmentId, trackNum, 0,
|
||||||
|
segOutGateId, suggestedTrackId))
|
||||||
{
|
{
|
||||||
//Update gate track
|
// Update gate track
|
||||||
updateGateTrackSpin(curStop.toGate);
|
updateGateTrackSpin(curStop.toGate);
|
||||||
|
|
||||||
if(curStop.toGate.gateTrackNum != trackNum)
|
if (curStop.toGate.gateTrackNum != trackNum)
|
||||||
{
|
{
|
||||||
//It wasn't possible to set requested track
|
// It wasn't possible to set requested track
|
||||||
QMessageBox::warning(mEditor, tr("Stop Error"),
|
QMessageBox::warning(
|
||||||
tr("Requested gate out track <b>%1</b> is not connected to segment <b>%2</b>.<br>"
|
mEditor, tr("Stop Error"),
|
||||||
"Out track <b>%3</b> was chosen instead.<br>"
|
tr("Requested gate out track <b>%1</b> is not connected to segment <b>%2</b>.<br>"
|
||||||
"Look segment track connection from Stations Manager for more information"
|
"Out track <b>%3</b> was chosen instead.<br>"
|
||||||
" on available tracks.")
|
"Look segment track connection from Stations Manager for more information"
|
||||||
.arg(trackNum)
|
" on available tracks.")
|
||||||
.arg(mOutGateEdit->text())
|
.arg(trackNum)
|
||||||
.arg(curStop.toGate.gateTrackNum));
|
.arg(mOutGateEdit->text())
|
||||||
|
.arg(curStop.toGate.gateTrackNum));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Success, close editor
|
// Success, close editor
|
||||||
emit nextSegmentChosen();
|
emit nextSegmentChosen();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Warn user and reset to previous chosen segment if any
|
// Warn user and reset to previous chosen segment if any
|
||||||
QMessageBox::warning(mEditor, tr("Stop Error"), tr("Cannot set segment track!"));
|
QMessageBox::warning(mEditor, tr("Stop Error"), tr("Cannot set segment track!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,26 +348,26 @@ void StopEditingHelper::checkOutGateTrack()
|
||||||
void StopEditingHelper::arrivalChanged(const QTime &arrival)
|
void StopEditingHelper::arrivalChanged(const QTime &arrival)
|
||||||
{
|
{
|
||||||
bool shiftPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
bool shiftPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||||
QTime dep = depEdit->time();
|
QTime dep = depEdit->time();
|
||||||
if(!shiftPressed)
|
if (!shiftPressed)
|
||||||
{
|
{
|
||||||
//Shift departure by the same amount if SHIFT NOT pressed
|
// Shift departure by the same amount if SHIFT NOT pressed
|
||||||
int diff = curStop.arrival.msecsTo(arrival);
|
int diff = curStop.arrival.msecsTo(arrival);
|
||||||
dep = dep.addMSecs(diff);
|
dep = dep.addMSecs(diff);
|
||||||
}
|
}
|
||||||
QTime minDep = arrival;
|
QTime minDep = arrival;
|
||||||
if(curStop.type == StopType::Normal)
|
if (curStop.type == StopType::Normal)
|
||||||
{
|
{
|
||||||
minDep = arrival.addSecs(60); //At least stop for 1 minute in Normal stops
|
minDep = arrival.addSecs(60); // At least stop for 1 minute in Normal stops
|
||||||
}
|
}
|
||||||
|
|
||||||
depEdit->blockSignals(true);
|
depEdit->blockSignals(true);
|
||||||
depEdit->setMinimumTime(minDep); //Set minimum before setting value
|
depEdit->setMinimumTime(minDep); // Set minimum before setting value
|
||||||
depEdit->setTime(dep);
|
depEdit->setTime(dep);
|
||||||
depEdit->blockSignals(false);
|
depEdit->blockSignals(false);
|
||||||
|
|
||||||
//Reset diff to 0 for next call
|
// Reset diff to 0 for next call
|
||||||
curStop.arrival = arrival;
|
curStop.arrival = arrival;
|
||||||
curStop.departure = dep;
|
curStop.departure = dep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,16 +378,16 @@ void StopEditingHelper::departureChanged(const QTime &dep)
|
||||||
|
|
||||||
void StopEditingHelper::startOutTrackTimer()
|
void StopEditingHelper::startOutTrackTimer()
|
||||||
{
|
{
|
||||||
//Give user a small time to scroll values in out gate track QSpinBox
|
// Give user a small time to scroll values in out gate track QSpinBox
|
||||||
//This will skip eventual non available tracks (not connected)
|
// This will skip eventual non available tracks (not connected)
|
||||||
//On timeout check track and reset to old value if not available
|
// On timeout check track and reset to old value if not available
|
||||||
stopOutTrackTimer();
|
stopOutTrackTimer();
|
||||||
mTimerOutTrack = startTimer(700);
|
mTimerOutTrack = startTimer(700);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopEditingHelper::stopOutTrackTimer()
|
void StopEditingHelper::stopOutTrackTimer()
|
||||||
{
|
{
|
||||||
if(mTimerOutTrack)
|
if (mTimerOutTrack)
|
||||||
{
|
{
|
||||||
killTimer(mTimerOutTrack);
|
killTimer(mTimerOutTrack);
|
||||||
mTimerOutTrack = 0;
|
mTimerOutTrack = 0;
|
||||||
|
@ -388,12 +399,12 @@ void StopEditingHelper::updateGateTrackSpin(const StopItem::Gate &toGate)
|
||||||
stopOutTrackTimer();
|
stopOutTrackTimer();
|
||||||
|
|
||||||
int outTrackCount = 0;
|
int outTrackCount = 0;
|
||||||
if(toGate.gateId)
|
if (toGate.gateId)
|
||||||
outTrackCount = stationOutGateMatchModel->getGateTrackCount(toGate.gateId);
|
outTrackCount = stationOutGateMatchModel->getGateTrackCount(toGate.gateId);
|
||||||
|
|
||||||
//Prevent trigger valueChanged() signal
|
// Prevent trigger valueChanged() signal
|
||||||
mOutGateTrackSpin->blockSignals(true);
|
mOutGateTrackSpin->blockSignals(true);
|
||||||
mOutGateTrackSpin->setMaximum(qMax(0, outTrackCount - 1)); //At least one track numbered 0
|
mOutGateTrackSpin->setMaximum(qMax(0, outTrackCount - 1)); // At least one track numbered 0
|
||||||
mOutGateTrackSpin->setValue(toGate.gateTrackNum);
|
mOutGateTrackSpin->setValue(toGate.gateTrackNum);
|
||||||
mOutGateTrackSpin->blockSignals(false);
|
mOutGateTrackSpin->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,23 +43,37 @@ class StopEditingHelper : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
StopEditingHelper(sqlite3pp::database &db, StopModel *m,
|
StopEditingHelper(sqlite3pp::database &db, StopModel *m, QSpinBox *outTrackSpin, QTimeEdit *arr,
|
||||||
QSpinBox *outTrackSpin, QTimeEdit *arr, QTimeEdit *dep,
|
QTimeEdit *dep, QWidget *editor = nullptr);
|
||||||
QWidget *editor = nullptr);
|
|
||||||
~StopEditingHelper();
|
~StopEditingHelper();
|
||||||
|
|
||||||
void setStop(const StopItem& item, const StopItem& prev);
|
void setStop(const StopItem &item, const StopItem &prev);
|
||||||
|
|
||||||
void popupSegmentCombo();
|
void popupSegmentCombo();
|
||||||
|
|
||||||
QString getGateString(db_id gateId, bool reversed);
|
QString getGateString(db_id gateId, bool reversed);
|
||||||
|
|
||||||
inline CustomCompletionLineEdit *getStationEdit() const { return mStationEdit; }
|
inline CustomCompletionLineEdit *getStationEdit() const
|
||||||
inline CustomCompletionLineEdit *getStTrackEdit() const { return mStTrackEdit; }
|
{
|
||||||
inline CustomCompletionLineEdit *getOutGateEdit() const { return mOutGateEdit; }
|
return mStationEdit;
|
||||||
|
}
|
||||||
|
inline CustomCompletionLineEdit *getStTrackEdit() const
|
||||||
|
{
|
||||||
|
return mStTrackEdit;
|
||||||
|
}
|
||||||
|
inline CustomCompletionLineEdit *getOutGateEdit() const
|
||||||
|
{
|
||||||
|
return mOutGateEdit;
|
||||||
|
}
|
||||||
|
|
||||||
inline const StopItem& getCurItem() const { return curStop; }
|
inline const StopItem &getCurItem() const
|
||||||
inline const StopItem& getPrevItem() const { return prevStop; }
|
{
|
||||||
|
return curStop;
|
||||||
|
}
|
||||||
|
inline const StopItem &getPrevItem() const
|
||||||
|
{
|
||||||
|
return prevStop;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void timerEvent(QTimerEvent *e) override;
|
void timerEvent(QTimerEvent *e) override;
|
||||||
|
@ -82,7 +96,7 @@ public slots:
|
||||||
void stopOutTrackTimer();
|
void stopOutTrackTimer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateGateTrackSpin(const StopItem::Gate& toGate);
|
void updateGateTrackSpin(const StopItem::Gate &toGate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget *mEditor;
|
QWidget *mEditor;
|
||||||
|
|
|
@ -27,19 +27,17 @@
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
|
||||||
|
|
||||||
StopEditor::StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent) :
|
StopEditor::StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent) :
|
||||||
QFrame(parent),
|
QFrame(parent),
|
||||||
m_closeOnSegmentChosen(false)
|
m_closeOnSegmentChosen(false)
|
||||||
{
|
{
|
||||||
mOutGateTrackSpin = new QSpinBox;
|
mOutGateTrackSpin = new QSpinBox;
|
||||||
arrEdit = new QTimeEdit;
|
arrEdit = new QTimeEdit;
|
||||||
depEdit = new QTimeEdit;
|
depEdit = new QTimeEdit;
|
||||||
|
|
||||||
helper = new StopEditingHelper(db, m,
|
helper = new StopEditingHelper(db, m, mOutGateTrackSpin, arrEdit, depEdit, this);
|
||||||
mOutGateTrackSpin, arrEdit, depEdit,
|
connect(helper, &StopEditingHelper::nextSegmentChosen, this,
|
||||||
this);
|
&StopEditor::onHelperSegmentChoosen);
|
||||||
connect(helper, &StopEditingHelper::nextSegmentChosen, this, &StopEditor::onHelperSegmentChoosen);
|
|
||||||
|
|
||||||
#ifdef PRINT_DBG_MSG
|
#ifdef PRINT_DBG_MSG
|
||||||
setObjectName(QStringLiteral("StopEditor (%1)").arg(qintptr(this)));
|
setObjectName(QStringLiteral("StopEditor (%1)").arg(qintptr(this)));
|
||||||
|
@ -51,7 +49,7 @@ StopEditor::StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent) :
|
||||||
CustomCompletionLineEdit *mStTrackEdit = helper->getStTrackEdit();
|
CustomCompletionLineEdit *mStTrackEdit = helper->getStTrackEdit();
|
||||||
CustomCompletionLineEdit *mOutGateEdit = helper->getOutGateEdit();
|
CustomCompletionLineEdit *mOutGateEdit = helper->getOutGateEdit();
|
||||||
|
|
||||||
lay = new QGridLayout(this);
|
lay = new QGridLayout(this);
|
||||||
lay->addWidget(mStationEdit, 0, 0);
|
lay->addWidget(mStationEdit, 0, 0);
|
||||||
lay->addWidget(arrEdit, 0, 1);
|
lay->addWidget(arrEdit, 0, 1);
|
||||||
lay->addWidget(depEdit, 0, 2);
|
lay->addWidget(depEdit, 0, 2);
|
||||||
|
@ -63,7 +61,8 @@ StopEditor::StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent) :
|
||||||
setTabOrder(arrEdit, depEdit);
|
setTabOrder(arrEdit, depEdit);
|
||||||
setTabOrder(depEdit, mOutGateEdit);
|
setTabOrder(depEdit, mOutGateEdit);
|
||||||
|
|
||||||
setToolTip(tr("To avoid recalculation of travel times when saving changes, hold SHIFT modifier while closing editor"));
|
setToolTip(tr("To avoid recalculation of travel times when saving changes, hold SHIFT modifier "
|
||||||
|
"while closing editor"));
|
||||||
}
|
}
|
||||||
|
|
||||||
StopEditor::~StopEditor()
|
StopEditor::~StopEditor()
|
||||||
|
@ -76,7 +75,7 @@ void StopEditor::setStop(const StopItem &item, const StopItem &prev)
|
||||||
{
|
{
|
||||||
helper->setStop(item, prev);
|
helper->setStop(item, prev);
|
||||||
|
|
||||||
if(item.stationId == 0)
|
if (item.stationId == 0)
|
||||||
setFocusProxy(helper->getStationEdit());
|
setFocusProxy(helper->getStationEdit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,21 +96,21 @@ void StopEditor::setCloseOnSegmentChosen(bool value)
|
||||||
|
|
||||||
void StopEditor::popupSegmentCombo()
|
void StopEditor::popupSegmentCombo()
|
||||||
{
|
{
|
||||||
//This code is used when adding a new stop.
|
// This code is used when adding a new stop.
|
||||||
//When user clicks on 'AddHere' a new stop is added
|
// When user clicks on 'AddHere' a new stop is added
|
||||||
//but before editing it, user must choose the railway segment
|
// but before editing it, user must choose the railway segment
|
||||||
//that the job will take from former Last Stop.
|
// that the job will take from former Last Stop.
|
||||||
//(It was Last Stop before we added this stop, so it didn't have a 'next segment')
|
//(It was Last Stop before we added this stop, so it didn't have a 'next segment')
|
||||||
|
|
||||||
//1 - We popup lines combo from former last stop
|
// 1 - We popup lines combo from former last stop
|
||||||
//2 - When user chooses a line we close the editor (emit lineChosen())
|
// 2 - When user chooses a line we close the editor (emit lineChosen())
|
||||||
//3 - We edit edit new Last Stop (EditNextItem)
|
// 3 - We edit edit new Last Stop (EditNextItem)
|
||||||
setCloseOnSegmentChosen(true);
|
setCloseOnSegmentChosen(true);
|
||||||
helper->popupSegmentCombo();
|
helper->popupSegmentCombo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopEditor::onHelperSegmentChoosen()
|
void StopEditor::onHelperSegmentChoosen()
|
||||||
{
|
{
|
||||||
//Forward signal and pass self instance
|
// Forward signal and pass self instance
|
||||||
emit nextSegmentChosen(this);
|
emit nextSegmentChosen(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,16 +49,19 @@ public:
|
||||||
StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent = nullptr);
|
StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent = nullptr);
|
||||||
~StopEditor();
|
~StopEditor();
|
||||||
|
|
||||||
void setStop(const StopItem& item, const StopItem& prev);
|
void setStop(const StopItem &item, const StopItem &prev);
|
||||||
|
|
||||||
const StopItem& getCurItem() const;
|
const StopItem &getCurItem() const;
|
||||||
const StopItem& getPrevItem() const;
|
const StopItem &getPrevItem() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief closeOnSegmentChosen
|
* \brief closeOnSegmentChosen
|
||||||
* \return true if editor should be closed after user has chosen a valid next segment
|
* \return true if editor should be closed after user has chosen a valid next segment
|
||||||
*/
|
*/
|
||||||
inline bool closeOnSegmentChosen() const { return m_closeOnSegmentChosen; };
|
inline bool closeOnSegmentChosen() const
|
||||||
|
{
|
||||||
|
return m_closeOnSegmentChosen;
|
||||||
|
};
|
||||||
void setCloseOnSegmentChosen(bool value);
|
void setCloseOnSegmentChosen(bool value);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -21,78 +21,74 @@
|
||||||
|
|
||||||
JobCrossingErrorMap::JobCrossingErrorMap()
|
JobCrossingErrorMap::JobCrossingErrorMap()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobCrossingErrorMap::removeJob(db_id jobId)
|
void JobCrossingErrorMap::removeJob(db_id jobId)
|
||||||
{
|
{
|
||||||
auto job = map.find(jobId);
|
auto job = map.find(jobId);
|
||||||
if(job == map.end())
|
if (job == map.end())
|
||||||
return; //Not contained in map
|
return; // Not contained in map
|
||||||
|
|
||||||
//Remove all errors referencing to us
|
// Remove all errors referencing to us
|
||||||
for(const JobCrossingErrorData& err : qAsConst(job->errors))
|
for (const JobCrossingErrorData &err : qAsConst(job->errors))
|
||||||
{
|
{
|
||||||
auto otherJob = map.find(err.otherJob.jobId);
|
auto otherJob = map.find(err.otherJob.jobId);
|
||||||
if(otherJob == map.end())
|
if (otherJob == map.end())
|
||||||
continue; //Maybe already remove, skip
|
continue; // Maybe already remove, skip
|
||||||
|
|
||||||
//Remove all errors regarding job in otherJob
|
// Remove all errors regarding job in otherJob
|
||||||
std::remove_if(otherJob->errors.begin(),
|
std::remove_if(otherJob->errors.begin(), otherJob->errors.end(),
|
||||||
otherJob->errors.end(),
|
[jobId](const JobCrossingErrorData &otherErr) -> bool
|
||||||
[jobId](const JobCrossingErrorData& otherErr) -> bool
|
{ return otherErr.otherJob.jobId == jobId; });
|
||||||
{
|
|
||||||
return otherErr.otherJob.jobId == jobId;
|
|
||||||
});
|
|
||||||
|
|
||||||
if(otherJob->errors.isEmpty())
|
if (otherJob->errors.isEmpty())
|
||||||
{
|
{
|
||||||
//otherJob has no errors, remove it
|
// otherJob has no errors, remove it
|
||||||
map.erase(otherJob);
|
map.erase(otherJob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove job
|
// Remove job
|
||||||
map.erase(job);
|
map.erase(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobCrossingErrorMap::renameJob(db_id newJobId, db_id oldJobId)
|
void JobCrossingErrorMap::renameJob(db_id newJobId, db_id oldJobId)
|
||||||
{
|
{
|
||||||
auto job = map.find(oldJobId);
|
auto job = map.find(oldJobId);
|
||||||
if(job == map.end())
|
if (job == map.end())
|
||||||
return; //Not contained in map
|
return; // Not contained in map
|
||||||
|
|
||||||
//Uodate all errors referencing to us
|
// Uodate all errors referencing to us
|
||||||
for(const JobCrossingErrorData& err : qAsConst(job->errors))
|
for (const JobCrossingErrorData &err : qAsConst(job->errors))
|
||||||
{
|
{
|
||||||
auto otherJob = map.find(err.otherJob.jobId);
|
auto otherJob = map.find(err.otherJob.jobId);
|
||||||
if(otherJob == map.end())
|
if (otherJob == map.end())
|
||||||
continue; //Maybe already remove, skip
|
continue; // Maybe already remove, skip
|
||||||
|
|
||||||
for(JobCrossingErrorData& otherErr : otherJob->errors)
|
for (JobCrossingErrorData &otherErr : otherJob->errors)
|
||||||
{
|
{
|
||||||
if(otherErr.otherJob.jobId == oldJobId)
|
if (otherErr.otherJob.jobId == oldJobId)
|
||||||
{
|
{
|
||||||
otherErr.otherJob.jobId = newJobId;
|
otherErr.otherJob.jobId = newJobId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update job
|
// Update job
|
||||||
auto errList = map.take(oldJobId);
|
auto errList = map.take(oldJobId);
|
||||||
errList.job.jobId = newJobId;
|
errList.job.jobId = newJobId;
|
||||||
map.insert(newJobId, errList);
|
map.insert(newJobId, errList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobCrossingErrorMap::merge(const ErrorMap &results)
|
void JobCrossingErrorMap::merge(const ErrorMap &results)
|
||||||
{
|
{
|
||||||
for(const JobCrossingErrorList& list : results)
|
for (const JobCrossingErrorList &list : results)
|
||||||
{
|
{
|
||||||
//First clear Job
|
// First clear Job
|
||||||
removeJob(list.job.jobId);
|
removeJob(list.job.jobId);
|
||||||
|
|
||||||
//Then add new errors if not empty (already duplicated)
|
// Then add new errors if not empty (already duplicated)
|
||||||
if(!list.errors.isEmpty())
|
if (!list.errors.isEmpty())
|
||||||
map.insert(list.job.jobId, list);
|
map.insert(list.job.jobId, list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,16 +22,16 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include <QMap>
|
# include <QMap>
|
||||||
#include <QTime>
|
# include <QTime>
|
||||||
|
|
||||||
#include "utils/types.h"
|
# include "utils/types.h"
|
||||||
|
|
||||||
struct JobCrossingErrorData
|
struct JobCrossingErrorData
|
||||||
{
|
{
|
||||||
db_id jobId = 0;
|
db_id jobId = 0;
|
||||||
|
|
||||||
db_id stopId = 0;
|
db_id stopId = 0;
|
||||||
db_id stationId = 0;
|
db_id stationId = 0;
|
||||||
|
|
||||||
JobStopEntry otherJob;
|
JobStopEntry otherJob;
|
||||||
|
@ -44,7 +44,8 @@ struct JobCrossingErrorData
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
NoError = 0,
|
NoError = 0,
|
||||||
JobCrossing, //NOTE: arrival refers to next job stop so it comes after departure (same for otherArr/Dep)
|
JobCrossing, // NOTE: arrival refers to next job stop so it comes after departure (same for
|
||||||
|
// otherArr/Dep)
|
||||||
JobPassing
|
JobPassing
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,8 +57,14 @@ struct JobCrossingErrorList
|
||||||
JobEntry job;
|
JobEntry job;
|
||||||
QVector<JobCrossingErrorData> errors;
|
QVector<JobCrossingErrorData> errors;
|
||||||
|
|
||||||
inline int childCount() const { return errors.size(); }
|
inline int childCount() const
|
||||||
inline const JobCrossingErrorData *ptrForRow(int row) const { return &errors.at(row); }
|
{
|
||||||
|
return errors.size();
|
||||||
|
}
|
||||||
|
inline const JobCrossingErrorData *ptrForRow(int row) const
|
||||||
|
{
|
||||||
|
return &errors.at(row);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -74,11 +81,14 @@ public:
|
||||||
|
|
||||||
JobCrossingErrorMap();
|
JobCrossingErrorMap();
|
||||||
|
|
||||||
inline int topLevelCount() const { return map.size(); }
|
inline int topLevelCount() const
|
||||||
|
{
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
inline const JobCrossingErrorList *getTopLevelAtRow(int row) const
|
inline const JobCrossingErrorList *getTopLevelAtRow(int row) const
|
||||||
{
|
{
|
||||||
if(row >= topLevelCount())
|
if (row >= topLevelCount())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &(map.constBegin() + row).value();
|
return &(map.constBegin() + row).value();
|
||||||
}
|
}
|
||||||
|
@ -86,7 +96,7 @@ public:
|
||||||
inline const JobCrossingErrorList *getParent(JobCrossingErrorData *child) const
|
inline const JobCrossingErrorList *getParent(JobCrossingErrorData *child) const
|
||||||
{
|
{
|
||||||
auto it = map.constFind(child->jobId);
|
auto it = map.constFind(child->jobId);
|
||||||
if(it == map.constEnd())
|
if (it == map.constEnd())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &it.value();
|
return &it.value();
|
||||||
}
|
}
|
||||||
|
@ -94,7 +104,7 @@ public:
|
||||||
inline int getParentRow(JobCrossingErrorData *child) const
|
inline int getParentRow(JobCrossingErrorData *child) const
|
||||||
{
|
{
|
||||||
auto it = map.constFind(child->jobId);
|
auto it = map.constFind(child->jobId);
|
||||||
if(it == map.constEnd())
|
if (it == map.constEnd())
|
||||||
return -1;
|
return -1;
|
||||||
return std::distance(map.constBegin(), it);
|
return std::distance(map.constBegin(), it);
|
||||||
}
|
}
|
||||||
|
@ -103,7 +113,7 @@ public:
|
||||||
|
|
||||||
void renameJob(db_id newJobId, db_id oldJobId);
|
void renameJob(db_id newJobId, db_id oldJobId);
|
||||||
|
|
||||||
void merge(const ErrorMap& results);
|
void merge(const ErrorMap &results);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ErrorMap map;
|
ErrorMap map;
|
||||||
|
|
|
@ -19,22 +19,22 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include "jobcrossingchecker.h"
|
# include "jobcrossingchecker.h"
|
||||||
|
|
||||||
#include "jobcrossingtask.h"
|
# include "jobcrossingtask.h"
|
||||||
#include "jobcrossingmodel.h"
|
# include "jobcrossingmodel.h"
|
||||||
|
|
||||||
#include "app/session.h"
|
# include "app/session.h"
|
||||||
#include "viewmanager/viewmanager.h"
|
# include "viewmanager/viewmanager.h"
|
||||||
|
|
||||||
#include "utils/owningqpointer.h"
|
# include "utils/owningqpointer.h"
|
||||||
#include <QMenu>
|
# include <QMenu>
|
||||||
|
|
||||||
JobCrossingChecker::JobCrossingChecker(sqlite3pp::database &db, QObject *parent) :
|
JobCrossingChecker::JobCrossingChecker(sqlite3pp::database &db, QObject *parent) :
|
||||||
IBackgroundChecker(db, parent),
|
IBackgroundChecker(db, parent),
|
||||||
mDb(db)
|
mDb(db)
|
||||||
{
|
{
|
||||||
eventType = int(JobCrossingResultEvent::_Type);
|
eventType = int(JobCrossingResultEvent::_Type);
|
||||||
errorsModel = new JobCrossingModel(this);
|
errorsModel = new JobCrossingModel(this);
|
||||||
|
|
||||||
connect(Session, &MeetingSession::jobChanged, this, &JobCrossingChecker::onJobChanged);
|
connect(Session, &MeetingSession::jobChanged, this, &JobCrossingChecker::onJobChanged);
|
||||||
|
@ -51,36 +51,37 @@ void JobCrossingChecker::clearModel()
|
||||||
static_cast<JobCrossingModel *>(errorsModel)->clear();
|
static_cast<JobCrossingModel *>(errorsModel)->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobCrossingChecker::showContextMenu(QWidget *panel, const QPoint &pos, const QModelIndex &idx) const
|
void JobCrossingChecker::showContextMenu(QWidget *panel, const QPoint &pos,
|
||||||
|
const QModelIndex &idx) const
|
||||||
{
|
{
|
||||||
const JobCrossingModel *model = static_cast<const JobCrossingModel *>(errorsModel);
|
const JobCrossingModel *model = static_cast<const JobCrossingModel *>(errorsModel);
|
||||||
auto item = model->getItem(idx);
|
auto item = model->getItem(idx);
|
||||||
if(!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OwningQPointer<QMenu> menu = new QMenu(panel);
|
OwningQPointer<QMenu> menu = new QMenu(panel);
|
||||||
|
|
||||||
QAction *showInJobEditor = new QAction(tr("Show in Job Editor"), menu);
|
QAction *showInJobEditor = new QAction(tr("Show in Job Editor"), menu);
|
||||||
QAction *showInGraph = new QAction(tr("Show in graph"), menu);
|
QAction *showInGraph = new QAction(tr("Show in graph"), menu);
|
||||||
|
|
||||||
menu->addAction(showInJobEditor);
|
menu->addAction(showInJobEditor);
|
||||||
menu->addAction(showInGraph);
|
menu->addAction(showInGraph);
|
||||||
|
|
||||||
QAction *act = menu->exec(pos);
|
QAction *act = menu->exec(pos);
|
||||||
if(act == showInJobEditor)
|
if (act == showInJobEditor)
|
||||||
{
|
{
|
||||||
Session->getViewManager()->requestJobEditor(item->jobId, item->stopId);
|
Session->getViewManager()->requestJobEditor(item->jobId, item->stopId);
|
||||||
}
|
}
|
||||||
else if(act == showInGraph)
|
else if (act == showInGraph)
|
||||||
{
|
{
|
||||||
//TODO: pass stopId
|
// TODO: pass stopId
|
||||||
Session->getViewManager()->requestJobSelection(item->jobId, true, true);
|
Session->getViewManager()->requestJobSelection(item->jobId, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobCrossingChecker::sessionLoadedHandler()
|
void JobCrossingChecker::sessionLoadedHandler()
|
||||||
{
|
{
|
||||||
if(AppSettings.getCheckCrossingWhenOpeningDB())
|
if (AppSettings.getCheckCrossingWhenOpeningDB())
|
||||||
startWorker();
|
startWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,8 +93,8 @@ IQuittableTask *JobCrossingChecker::createMainWorker()
|
||||||
void JobCrossingChecker::setErrors(QEvent *e, bool merge)
|
void JobCrossingChecker::setErrors(QEvent *e, bool merge)
|
||||||
{
|
{
|
||||||
auto model = static_cast<JobCrossingModel *>(errorsModel);
|
auto model = static_cast<JobCrossingModel *>(errorsModel);
|
||||||
auto ev = static_cast<JobCrossingResultEvent *>(e);
|
auto ev = static_cast<JobCrossingResultEvent *>(e);
|
||||||
if(merge)
|
if (merge)
|
||||||
model->mergeErrors(ev->results);
|
model->mergeErrors(ev->results);
|
||||||
else
|
else
|
||||||
model->setErrors(ev->results);
|
model->setErrors(ev->results);
|
||||||
|
@ -104,8 +105,8 @@ void JobCrossingChecker::onJobChanged(db_id newJobId, db_id oldJobId)
|
||||||
auto model = static_cast<JobCrossingModel *>(errorsModel);
|
auto model = static_cast<JobCrossingModel *>(errorsModel);
|
||||||
model->renameJob(oldJobId, newJobId);
|
model->renameJob(oldJobId, newJobId);
|
||||||
|
|
||||||
//After renaming check job
|
// After renaming check job
|
||||||
if(AppSettings.getCheckCrossingOnJobEdit())
|
if (AppSettings.getCheckCrossingOnJobEdit())
|
||||||
startWorker();
|
startWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include "backgroundmanager/ibackgroundchecker.h"
|
# include "backgroundmanager/ibackgroundchecker.h"
|
||||||
|
|
||||||
#include "utils/types.h"
|
# include "utils/types.h"
|
||||||
|
|
||||||
class JobCrossingChecker : public IBackgroundChecker
|
class JobCrossingChecker : public IBackgroundChecker
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@ public:
|
||||||
|
|
||||||
QString getName() const override;
|
QString getName() const override;
|
||||||
void clearModel() override;
|
void clearModel() override;
|
||||||
void showContextMenu(QWidget *panel, const QPoint& pos, const QModelIndex& idx) const override;
|
void showContextMenu(QWidget *panel, const QPoint &pos, const QModelIndex &idx) const override;
|
||||||
|
|
||||||
void sessionLoadedHandler() override;
|
void sessionLoadedHandler() override;
|
||||||
|
|
||||||
|
|
|
@ -21,25 +21,23 @@
|
||||||
|
|
||||||
#include "utils/jobcategorystrings.h"
|
#include "utils/jobcategorystrings.h"
|
||||||
|
|
||||||
static const char* error_texts[] = {
|
static const char *error_texts[] = {
|
||||||
nullptr,
|
nullptr, QT_TRANSLATE_NOOP("JobErrors", "Job crosses another Job on same track."),
|
||||||
QT_TRANSLATE_NOOP("JobErrors", "Job crosses another Job on same track."),
|
QT_TRANSLATE_NOOP("JobErrors", "Job passes another Job on same track.")};
|
||||||
QT_TRANSLATE_NOOP("JobErrors", "Job passes another Job on same track.")
|
|
||||||
};
|
|
||||||
|
|
||||||
class JobErrors
|
class JobErrors
|
||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(JobErrors)
|
Q_DECLARE_TR_FUNCTIONS(JobErrors)
|
||||||
};
|
};
|
||||||
|
|
||||||
JobCrossingModel::JobCrossingModel(QObject *parent) : JobCrossingModelBase(parent)
|
JobCrossingModel::JobCrossingModel(QObject *parent) :
|
||||||
|
JobCrossingModelBase(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant JobCrossingModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant JobCrossingModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
{
|
{
|
||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
|
@ -63,11 +61,11 @@ QVariant JobCrossingModel::headerData(int section, Qt::Orientation orientation,
|
||||||
|
|
||||||
QVariant JobCrossingModel::data(const QModelIndex &idx, int role) const
|
QVariant JobCrossingModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
if(!idx.isValid() || role != Qt::DisplayRole)
|
if (!idx.isValid() || role != Qt::DisplayRole)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
const JobCrossingErrorData *item = getItem(idx);
|
const JobCrossingErrorData *item = getItem(idx);
|
||||||
if(item)
|
if (item)
|
||||||
{
|
{
|
||||||
switch (idx.column())
|
switch (idx.column())
|
||||||
{
|
{
|
||||||
|
@ -87,8 +85,8 @@ QVariant JobCrossingModel::data(const QModelIndex &idx, int role) const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Caption
|
// Caption
|
||||||
if(idx.row() >= m_data.topLevelCount() || idx.column() != 0)
|
if (idx.row() >= m_data.topLevelCount() || idx.column() != 0)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
auto topLevel = m_data.getTopLevelAtRow(idx.row());
|
auto topLevel = m_data.getTopLevelAtRow(idx.row());
|
||||||
|
@ -135,5 +133,4 @@ void JobCrossingModel::renameJob(db_id newJobId, db_id oldJobId)
|
||||||
|
|
||||||
void JobCrossingModel::renameStation(db_id stationId, const QString &name)
|
void JobCrossingModel::renameStation(db_id stationId, const QString &name)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,15 @@
|
||||||
|
|
||||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
||||||
#include "utils/singledepthtreemodelhelper.h"
|
# include "utils/singledepthtreemodelhelper.h"
|
||||||
|
|
||||||
#include "job_crossing_data.h"
|
# include "job_crossing_data.h"
|
||||||
|
|
||||||
class JobCrossingModel;
|
class JobCrossingModel;
|
||||||
typedef SingleDepthTreeModelHelper<JobCrossingModel, JobCrossingErrorMap, JobCrossingErrorData> JobCrossingModelBase;
|
typedef SingleDepthTreeModelHelper<JobCrossingModel, JobCrossingErrorMap, JobCrossingErrorData>
|
||||||
|
JobCrossingModelBase;
|
||||||
|
|
||||||
//TODO: make on-demand
|
// TODO: make on-demand
|
||||||
class JobCrossingModel : public JobCrossingModelBase
|
class JobCrossingModel : public JobCrossingModelBase
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -48,7 +49,8 @@ public:
|
||||||
JobCrossingModel(QObject *parent = nullptr);
|
JobCrossingModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
// Header:
|
// Header:
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
@ -62,7 +64,7 @@ public:
|
||||||
|
|
||||||
void renameJob(db_id newJobId, db_id oldJobId);
|
void renameJob(db_id newJobId, db_id oldJobId);
|
||||||
|
|
||||||
void renameStation(db_id stationId, const QString& name);
|
void renameStation(db_id stationId, const QString &name);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ENABLE_BACKGROUND_MANAGER
|
#endif // ENABLE_BACKGROUND_MANAGER
|
||||||
|
|
|
@ -22,41 +22,42 @@
|
||||||
#include <sqlite3pp/sqlite3pp.h>
|
#include <sqlite3pp/sqlite3pp.h>
|
||||||
using namespace sqlite3pp;
|
using namespace sqlite3pp;
|
||||||
|
|
||||||
inline bool fillCrossingErrorData(query::rows& job, JobCrossingErrorData& err, bool first, JobCategory &outCat)
|
inline bool fillCrossingErrorData(query::rows &job, JobCrossingErrorData &err, bool first,
|
||||||
|
JobCategory &outCat)
|
||||||
{
|
{
|
||||||
err.stopId = job.get<db_id>(0);
|
err.stopId = job.get<db_id>(0);
|
||||||
err.otherJob.stopId = job.get<db_id>(1);
|
err.otherJob.stopId = job.get<db_id>(1);
|
||||||
err.jobId = job.get<db_id>(2);
|
err.jobId = job.get<db_id>(2);
|
||||||
outCat = JobCategory(job.get<int>(3));
|
outCat = JobCategory(job.get<int>(3));
|
||||||
err.otherJob.jobId = job.get<db_id>(4);
|
err.otherJob.jobId = job.get<db_id>(4);
|
||||||
err.otherJob.category = JobCategory(job.get<int>(5));
|
err.otherJob.category = JobCategory(job.get<int>(5));
|
||||||
err.departure = job.get<QTime>(6);
|
err.departure = job.get<QTime>(6);
|
||||||
err.arrival = job.get<QTime>(7);
|
err.arrival = job.get<QTime>(7);
|
||||||
err.otherDep = job.get<QTime>(8);
|
err.otherDep = job.get<QTime>(8);
|
||||||
err.otherArr = job.get<QTime>(9);
|
err.otherArr = job.get<QTime>(9);
|
||||||
bool passing = job.get<int>(10) == 1;
|
bool passing = job.get<int>(10) == 1;
|
||||||
err.stationId = job.get<db_id>(11);
|
err.stationId = job.get<db_id>(11);
|
||||||
err.stationName = job.get<QString>(12);
|
err.stationName = job.get<QString>(12);
|
||||||
|
|
||||||
if(passing)
|
if (passing)
|
||||||
{
|
{
|
||||||
//In passings:
|
// In passings:
|
||||||
//job A starts before B but gets passed and ends after B
|
// job A starts before B but gets passed and ends after B
|
||||||
//job B starts after A but ends before
|
// job B starts after A but ends before
|
||||||
//B travel period is contained in A travel period
|
// B travel period is contained in A travel period
|
||||||
|
|
||||||
//We need stricter checking of time, one travel must be contained in the other
|
// We need stricter checking of time, one travel must be contained in the other
|
||||||
if(err.departure < err.otherDep && err.arrival < err.otherArr)
|
if (err.departure < err.otherDep && err.arrival < err.otherArr)
|
||||||
return false; //A travels before B, no passing
|
return false; // A travels before B, no passing
|
||||||
if(err.departure > err.otherDep && err.arrival > err.otherArr)
|
if (err.departure > err.otherDep && err.arrival > err.otherArr)
|
||||||
return false; //A travels after B, no passing
|
return false; // A travels after B, no passing
|
||||||
}
|
}
|
||||||
|
|
||||||
err.type = passing ? JobCrossingErrorData::JobPassing : JobCrossingErrorData::JobCrossing;
|
err.type = passing ? JobCrossingErrorData::JobPassing : JobCrossingErrorData::JobCrossing;
|
||||||
|
|
||||||
if(!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
//Swap points of view
|
// Swap points of view
|
||||||
qSwap(err.jobId, err.otherJob.jobId);
|
qSwap(err.jobId, err.otherJob.jobId);
|
||||||
qSwap(outCat, err.otherJob.category);
|
qSwap(outCat, err.otherJob.category);
|
||||||
qSwap(err.stopId, err.otherJob.stopId);
|
qSwap(err.stopId, err.otherJob.stopId);
|
||||||
|
@ -67,43 +68,45 @@ inline bool fillCrossingErrorData(query::rows& job, JobCrossingErrorData& err, b
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JobCrossingResultEvent::JobCrossingResultEvent(JobCrossingTask *worker, const JobCrossingErrorMap::ErrorMap &data, bool merge) :
|
JobCrossingResultEvent::JobCrossingResultEvent(JobCrossingTask *worker,
|
||||||
|
const JobCrossingErrorMap::ErrorMap &data,
|
||||||
|
bool merge) :
|
||||||
GenericTaskEvent(_Type, worker),
|
GenericTaskEvent(_Type, worker),
|
||||||
results(data),
|
results(data),
|
||||||
mergeErrors(merge)
|
mergeErrors(merge)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JobCrossingTask::JobCrossingTask(sqlite3pp::database &db, QObject *receiver, const QVector<db_id>& jobs) :
|
JobCrossingTask::JobCrossingTask(sqlite3pp::database &db, QObject *receiver,
|
||||||
|
const QVector<db_id> &jobs) :
|
||||||
IQuittableTask(receiver),
|
IQuittableTask(receiver),
|
||||||
mDb(db),
|
mDb(db),
|
||||||
jobsToCheck(jobs)
|
jobsToCheck(jobs)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobCrossingTask::run()
|
void JobCrossingTask::run()
|
||||||
{
|
{
|
||||||
//TODO: allow checking a single job
|
// TODO: allow checking a single job
|
||||||
|
|
||||||
//Look for passing or crossings on same segment
|
// Look for passing or crossings on same segment
|
||||||
query q(mDb, "SELECT s1.id, s2.id, s1.job_id, j1.category, s2.job_id, j2.category,"
|
query q(mDb,
|
||||||
"s1.departure, MIN(s1_next.arrival),"
|
"SELECT s1.id, s2.id, s1.job_id, j1.category, s2.job_id, j2.category,"
|
||||||
"s2.departure, MIN(s2_next.arrival),"
|
"s1.departure, MIN(s1_next.arrival),"
|
||||||
"g1.gate_id=g2.gate_id," //1 = passing, 0 = crossing (opposite direction)
|
"s2.departure, MIN(s2_next.arrival),"
|
||||||
"s1.station_id, stations.name"
|
"g1.gate_id=g2.gate_id," // 1 = passing, 0 = crossing (opposite direction)
|
||||||
" FROM stops s1"
|
"s1.station_id, stations.name"
|
||||||
" JOIN stops s1_next ON s1_next.job_id=s1.job_id AND s1_next.arrival>s1.arrival"
|
" FROM stops s1"
|
||||||
" JOIN stops s2 ON s2.next_segment_conn_id=s1.next_segment_conn_id AND s2.id<>s1.id"
|
" JOIN stops s1_next ON s1_next.job_id=s1.job_id AND s1_next.arrival>s1.arrival"
|
||||||
" JOIN stops s2_next ON s2_next.job_id=s2.job_id AND s2_next.arrival>s2.arrival"
|
" JOIN stops s2 ON s2.next_segment_conn_id=s1.next_segment_conn_id AND s2.id<>s1.id"
|
||||||
" JOIN jobs j1 ON j1.id=s1.job_id"
|
" JOIN stops s2_next ON s2_next.job_id=s2.job_id AND s2_next.arrival>s2.arrival"
|
||||||
" JOIN jobs j2 ON j2.id=s2.job_id"
|
" JOIN jobs j1 ON j1.id=s1.job_id"
|
||||||
" JOIN station_gate_connections g1 ON g1.id=s1.out_gate_conn"
|
" JOIN jobs j2 ON j2.id=s2.job_id"
|
||||||
" JOIN station_gate_connections g2 ON g2.id=s2.out_gate_conn"
|
" JOIN station_gate_connections g1 ON g1.id=s1.out_gate_conn"
|
||||||
" JOIN stations ON stations.id=s1.station_id"
|
" JOIN station_gate_connections g2 ON g2.id=s2.out_gate_conn"
|
||||||
" GROUP BY s1.id,s2.id"
|
" JOIN stations ON stations.id=s1.station_id"
|
||||||
" HAVING s1.departure<=s2_next.arrival AND s1_next.arrival>=s2.departure");
|
" GROUP BY s1.id,s2.id"
|
||||||
|
" HAVING s1.departure<=s2_next.arrival AND s1_next.arrival>=s2.departure");
|
||||||
|
|
||||||
QMap<db_id, JobCrossingErrorList> errorMap;
|
QMap<db_id, JobCrossingErrorList> errorMap;
|
||||||
checkCrossAndPassSegments(errorMap, q);
|
checkCrossAndPassSegments(errorMap, q);
|
||||||
|
@ -147,25 +150,26 @@ void JobCrossingTask::run()
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobCrossingTask::checkCrossAndPassSegments(JobCrossingErrorMap::ErrorMap &errMap, sqlite3pp::query &q)
|
void JobCrossingTask::checkCrossAndPassSegments(JobCrossingErrorMap::ErrorMap &errMap,
|
||||||
|
sqlite3pp::query &q)
|
||||||
{
|
{
|
||||||
for(auto job : q)
|
for (auto job : q)
|
||||||
{
|
{
|
||||||
JobCrossingErrorData err;
|
JobCrossingErrorData err;
|
||||||
JobCategory category = JobCategory::NCategories;
|
JobCategory category = JobCategory::NCategories;
|
||||||
|
|
||||||
if(!fillCrossingErrorData(job, err, true, category))
|
if (!fillCrossingErrorData(job, err, true, category))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto it = errMap.find(err.jobId);
|
auto it = errMap.find(err.jobId);
|
||||||
if(it == errMap.end())
|
if (it == errMap.end())
|
||||||
{
|
{
|
||||||
//Insert Job into map for first time
|
// Insert Job into map for first time
|
||||||
JobCrossingErrorList list;
|
JobCrossingErrorList list;
|
||||||
list.job.jobId = err.jobId;
|
list.job.jobId = err.jobId;
|
||||||
list.job.category = category;
|
list.job.category = category;
|
||||||
|
|
||||||
it = errMap.insert(list.job.jobId, list);
|
it = errMap.insert(list.job.jobId, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
it.value().errors.append(err);
|
it.value().errors.append(err);
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
namespace sqlite3pp {
|
namespace sqlite3pp {
|
||||||
class database;
|
class database;
|
||||||
class query;
|
class query;
|
||||||
}
|
} // namespace sqlite3pp
|
||||||
|
|
||||||
class JobCrossingTask;
|
class JobCrossingTask;
|
||||||
|
|
||||||
|
@ -40,7 +40,8 @@ class JobCrossingResultEvent : public GenericTaskEvent
|
||||||
public:
|
public:
|
||||||
static const Type _Type = Type(CustomEvents::JobsCrossingCheckResult);
|
static const Type _Type = Type(CustomEvents::JobsCrossingCheckResult);
|
||||||
|
|
||||||
JobCrossingResultEvent(JobCrossingTask *worker, const JobCrossingErrorMap::ErrorMap &data, bool merge);
|
JobCrossingResultEvent(JobCrossingTask *worker, const JobCrossingErrorMap::ErrorMap &data,
|
||||||
|
bool merge);
|
||||||
|
|
||||||
QMap<db_id, JobCrossingErrorList> results;
|
QMap<db_id, JobCrossingErrorList> results;
|
||||||
bool mergeErrors;
|
bool mergeErrors;
|
||||||
|
@ -49,11 +50,11 @@ public:
|
||||||
class JobCrossingTask : public IQuittableTask
|
class JobCrossingTask : public IQuittableTask
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
JobCrossingTask(sqlite3pp::database &db, QObject *receiver, const QVector<db_id>& jobs);
|
JobCrossingTask(sqlite3pp::database &db, QObject *receiver, const QVector<db_id> &jobs);
|
||||||
|
|
||||||
void run() override;
|
void run() override;
|
||||||
|
|
||||||
void checkCrossAndPassSegments(JobCrossingErrorMap::ErrorMap& errMap, sqlite3pp::query &q);
|
void checkCrossAndPassSegments(JobCrossingErrorMap::ErrorMap &errMap, sqlite3pp::query &q);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sqlite3pp::database &mDb;
|
sqlite3pp::database &mDb;
|
||||||
|
|
|
@ -45,15 +45,17 @@ JobsManager::JobsManager(QWidget *parent) :
|
||||||
QVBoxLayout *l = new QVBoxLayout(this);
|
QVBoxLayout *l = new QVBoxLayout(this);
|
||||||
setMinimumSize(750, 300);
|
setMinimumSize(750, 300);
|
||||||
|
|
||||||
QToolBar *toolBar = new QToolBar(this);
|
QToolBar *toolBar = new QToolBar(this);
|
||||||
QAction *actNewJob = toolBar->addAction(tr("New Job"), this, &JobsManager::onNewJob);
|
QAction *actNewJob = toolBar->addAction(tr("New Job"), this, &JobsManager::onNewJob);
|
||||||
actRemoveJob = toolBar->addAction(tr("Remove"), this, &JobsManager::onRemove);
|
actRemoveJob = toolBar->addAction(tr("Remove"), this, &JobsManager::onRemove);
|
||||||
actNewJobSamePath = toolBar->addAction(tr("New Same Path"), this, &JobsManager::onNewJobSamePath);
|
actNewJobSamePath =
|
||||||
|
toolBar->addAction(tr("New Same Path"), this, &JobsManager::onNewJobSamePath);
|
||||||
toolBar->addSeparator();
|
toolBar->addSeparator();
|
||||||
actEditJob = toolBar->addAction(tr("Edit"), this, &JobsManager::onEditJob);
|
actEditJob = toolBar->addAction(tr("Edit"), this, &JobsManager::onEditJob);
|
||||||
actShowJobInGraph = toolBar->addAction(tr("Show Graph"), this, &JobsManager::onShowJobGraph);
|
actShowJobInGraph = toolBar->addAction(tr("Show Graph"), this, &JobsManager::onShowJobGraph);
|
||||||
toolBar->addSeparator();
|
toolBar->addSeparator();
|
||||||
QAction *actRemoveAll = toolBar->addAction(tr("Remove All"), this, &JobsManager::onRemoveAllJobs);
|
QAction *actRemoveAll =
|
||||||
|
toolBar->addAction(tr("Remove All"), this, &JobsManager::onRemoveAllJobs);
|
||||||
l->addWidget(toolBar);
|
l->addWidget(toolBar);
|
||||||
|
|
||||||
view = new QTableView;
|
view = new QTableView;
|
||||||
|
@ -61,7 +63,7 @@ JobsManager::JobsManager(QWidget *parent) :
|
||||||
connect(view, &QTableView::doubleClicked, this, &JobsManager::editJobAtRow);
|
connect(view, &QTableView::doubleClicked, this, &JobsManager::editJobAtRow);
|
||||||
l->addWidget(view);
|
l->addWidget(view);
|
||||||
|
|
||||||
//Custom sorting and filtering
|
// Custom sorting and filtering
|
||||||
FilterHeaderView *header = new FilterHeaderView(view);
|
FilterHeaderView *header = new FilterHeaderView(view);
|
||||||
header->installOnTable(view);
|
header->installOnTable(view);
|
||||||
|
|
||||||
|
@ -72,12 +74,13 @@ JobsManager::JobsManager(QWidget *parent) :
|
||||||
l->addWidget(ps);
|
l->addWidget(ps);
|
||||||
ps->setModel(jobsModel);
|
ps->setModel(jobsModel);
|
||||||
|
|
||||||
connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, this, &JobsManager::onSelectionChanged);
|
connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||||
|
&JobsManager::onSelectionChanged);
|
||||||
connect(jobsModel, &QAbstractItemModel::modelReset, this, &JobsManager::onSelectionChanged);
|
connect(jobsModel, &QAbstractItemModel::modelReset, this, &JobsManager::onSelectionChanged);
|
||||||
|
|
||||||
jobsModel->refreshData();
|
jobsModel->refreshData();
|
||||||
|
|
||||||
//Action Tooltips
|
// Action Tooltips
|
||||||
actNewJob->setToolTip(tr("Create new Job and open Job Editor"));
|
actNewJob->setToolTip(tr("Create new Job and open Job Editor"));
|
||||||
actRemoveJob->setToolTip(tr("Delete selected Job"));
|
actRemoveJob->setToolTip(tr("Delete selected Job"));
|
||||||
actNewJobSamePath->setToolTip(tr("Create new Job with same path of selected one"));
|
actNewJobSamePath->setToolTip(tr("Create new Job with same path of selected one"));
|
||||||
|
@ -89,10 +92,10 @@ JobsManager::JobsManager(QWidget *parent) :
|
||||||
setWindowTitle("Jobs Manager");
|
setWindowTitle("Jobs Manager");
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobsManager::editJobAtRow(const QModelIndex& idx)
|
void JobsManager::editJobAtRow(const QModelIndex &idx)
|
||||||
{
|
{
|
||||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||||
if(!jobId)
|
if (!jobId)
|
||||||
return;
|
return;
|
||||||
Session->getViewManager()->requestJobEditor(jobId);
|
Session->getViewManager()->requestJobEditor(jobId);
|
||||||
}
|
}
|
||||||
|
@ -105,64 +108,65 @@ void JobsManager::onNewJob()
|
||||||
void JobsManager::onRemove()
|
void JobsManager::onRemove()
|
||||||
{
|
{
|
||||||
QModelIndex idx = view->currentIndex();
|
QModelIndex idx = view->currentIndex();
|
||||||
if(!idx.isValid())
|
if (!idx.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||||
JobCategory jobCat = jobsModel->getShiftAnCatAtRow(idx.row()).second;
|
JobCategory jobCat = jobsModel->getShiftAnCatAtRow(idx.row()).second;
|
||||||
QString jobName = JobCategoryName::jobName(jobId, jobCat);
|
QString jobName = JobCategoryName::jobName(jobId, jobCat);
|
||||||
|
|
||||||
int ret = QMessageBox::question(this,
|
int ret = QMessageBox::question(this, tr("Job deletion"),
|
||||||
tr("Job deletion"),
|
tr("Are you sure to delete job %1?").arg(jobName),
|
||||||
tr("Are you sure to delete job %1?").arg(jobName),
|
QMessageBox::Yes | QMessageBox::Cancel);
|
||||||
QMessageBox::Yes | QMessageBox::Cancel);
|
if (ret == QMessageBox::Yes)
|
||||||
if(ret == QMessageBox::Yes)
|
|
||||||
{
|
{
|
||||||
if(!JobsHelper::removeJob(Session->m_Db, jobId))
|
if (!JobsHelper::removeJob(Session->m_Db, jobId))
|
||||||
{
|
{
|
||||||
qWarning() << "Error while deleting job:" << jobId << "from JobManager" << Session->m_Db.error_msg();
|
qWarning() << "Error while deleting job:" << jobId << "from JobManager"
|
||||||
//ERRORMSG: message box or statusbar
|
<< Session->m_Db.error_msg();
|
||||||
|
// ERRORMSG: message box or statusbar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobsManager::onRemoveAllJobs()
|
void JobsManager::onRemoveAllJobs()
|
||||||
{
|
{
|
||||||
int ret = QMessageBox::question(this, tr("Delete all jobs?"),
|
int ret = QMessageBox::question(
|
||||||
tr("Are you really sure you want to delete all jobs from this session?"));
|
this, tr("Delete all jobs?"),
|
||||||
if(ret == QMessageBox::Yes)
|
tr("Are you really sure you want to delete all jobs from this session?"));
|
||||||
|
if (ret == QMessageBox::Yes)
|
||||||
JobsHelper::removeAllJobs(Session->m_Db);
|
JobsHelper::removeAllJobs(Session->m_Db);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobsManager::onNewJobSamePath()
|
void JobsManager::onNewJobSamePath()
|
||||||
{
|
{
|
||||||
QModelIndex idx = view->currentIndex();
|
QModelIndex idx = view->currentIndex();
|
||||||
if(!idx.isValid())
|
if (!idx.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||||
if(!jobId)
|
if (!jobId)
|
||||||
return;
|
return;
|
||||||
JobCategory jobCat = jobsModel->getShiftAnCatAtRow(idx.row()).second;
|
JobCategory jobCat = jobsModel->getShiftAnCatAtRow(idx.row()).second;
|
||||||
auto times = jobsModel->getOrigAndDestTimeAtRow(idx.row());
|
auto times = jobsModel->getOrigAndDestTimeAtRow(idx.row());
|
||||||
|
|
||||||
OwningQPointer<NewJobSamePathDlg> dlg = new NewJobSamePathDlg(this);
|
OwningQPointer<NewJobSamePathDlg> dlg = new NewJobSamePathDlg(this);
|
||||||
dlg->setSourceJob(jobId, jobCat, times.first, times.second);
|
dlg->setSourceJob(jobId, jobCat, times.first, times.second);
|
||||||
|
|
||||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QTime newStart = dlg->getNewStartTime();
|
const QTime newStart = dlg->getNewStartTime();
|
||||||
const int secsOffset = times.first.secsTo(newStart);
|
const int secsOffset = times.first.secsTo(newStart);
|
||||||
|
|
||||||
db_id newJobId = 0;
|
db_id newJobId = 0;
|
||||||
if(!JobsHelper::createNewJob(Session->m_Db, newJobId, jobCat))
|
if (!JobsHelper::createNewJob(Session->m_Db, newJobId, jobCat))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JobsHelper::copyStops(Session->m_Db, jobId, newJobId, secsOffset,
|
JobsHelper::copyStops(Session->m_Db, jobId, newJobId, secsOffset, dlg->shouldCopyRs(),
|
||||||
dlg->shouldCopyRs(), dlg->shouldReversePath());
|
dlg->shouldReversePath());
|
||||||
|
|
||||||
//Let user edit newly created job
|
// Let user edit newly created job
|
||||||
Session->getViewManager()->requestJobEditor(newJobId);
|
Session->getViewManager()->requestJobEditor(newJobId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,16 +178,16 @@ void JobsManager::onEditJob()
|
||||||
void JobsManager::onShowJobGraph()
|
void JobsManager::onShowJobGraph()
|
||||||
{
|
{
|
||||||
QModelIndex idx = view->currentIndex();
|
QModelIndex idx = view->currentIndex();
|
||||||
if(!idx.isValid())
|
if (!idx.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||||
if(!jobId)
|
if (!jobId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Session->getViewManager()->requestJobSelection(jobId, true, true);
|
Session->getViewManager()->requestJobSelection(jobId, true, true);
|
||||||
|
|
||||||
//Minimize JobsManager to make graph visible
|
// Minimize JobsManager to make graph visible
|
||||||
showMinimized();
|
showMinimized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,9 +46,9 @@ JobListModel::JobListModel(sqlite3pp::database &db, QObject *parent) :
|
||||||
|
|
||||||
QVariant JobListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant JobListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if(role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole)
|
||||||
{
|
{
|
||||||
if(orientation == Qt::Horizontal)
|
if (orientation == Qt::Horizontal)
|
||||||
{
|
{
|
||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
|
@ -84,16 +84,16 @@ QVariant JobListModel::data(const QModelIndex &idx, int role) const
|
||||||
if (!idx.isValid() || row >= curItemCount || idx.column() >= NCols)
|
if (!idx.isValid() || row >= curItemCount || idx.column() >= NCols)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
if(row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
if (row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
||||||
{
|
{
|
||||||
//Fetch above or below current cache
|
// Fetch above or below current cache
|
||||||
const_cast<JobListModel *>(this)->fetchRow(row);
|
const_cast<JobListModel *>(this)->fetchRow(row);
|
||||||
|
|
||||||
//Temporarily return null
|
// Temporarily return null
|
||||||
return role == Qt::DisplayRole ? QVariant("...") : QVariant();
|
return role == Qt::DisplayRole ? QVariant("...") : QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
const JobItem& item = cache.at(row - cacheFirstRow);
|
const JobItem &item = cache.at(row - cacheFirstRow);
|
||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
|
@ -122,7 +122,7 @@ QVariant JobListModel::data(const QModelIndex &idx, int role) const
|
||||||
}
|
}
|
||||||
case Qt::TextAlignmentRole:
|
case Qt::TextAlignmentRole:
|
||||||
{
|
{
|
||||||
if(idx.column() == IdCol)
|
if (idx.column() == IdCol)
|
||||||
{
|
{
|
||||||
return Qt::AlignVCenter + Qt::AlignRight;
|
return Qt::AlignVCenter + Qt::AlignRight;
|
||||||
}
|
}
|
||||||
|
@ -135,14 +135,14 @@ QVariant JobListModel::data(const QModelIndex &idx, int role) const
|
||||||
|
|
||||||
void JobListModel::setSortingColumn(int col)
|
void JobListModel::setSortingColumn(int col)
|
||||||
{
|
{
|
||||||
if(sortColumn == col || col == OriginSt || col == DestinationSt || col >= NCols)
|
if (sortColumn == col || col == OriginSt || col == DestinationSt || col >= NCols)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clearCache();
|
clearCache();
|
||||||
sortColumn = col;
|
sortColumn = col;
|
||||||
|
|
||||||
QModelIndex first = index(0, 0);
|
QModelIndex first = index(0, 0);
|
||||||
QModelIndex last = index(curItemCount - 1, NCols - 1);
|
QModelIndex last = index(curItemCount - 1, NCols - 1);
|
||||||
emit dataChanged(first, last);
|
emit dataChanged(first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +167,8 @@ bool JobListModel::setFilterAtCol(int col, const QString &str)
|
||||||
{
|
{
|
||||||
case IdCol:
|
case IdCol:
|
||||||
{
|
{
|
||||||
if(isNull)
|
if (isNull)
|
||||||
return false; //Cannot have NULL Job ID
|
return false; // Cannot have NULL Job ID
|
||||||
m_jobIdFilter = str;
|
m_jobIdFilter = str;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ bool JobListModel::setFilterAtCol(int col, const QString &str)
|
||||||
|
|
||||||
void JobListModel::onJobAddedOrRemoved()
|
void JobListModel::onJobAddedOrRemoved()
|
||||||
{
|
{
|
||||||
refreshData(); //Recalc row count
|
refreshData(); // Recalc row count
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 JobListModel::recalcTotalItemCount()
|
qint64 JobListModel::recalcTotalItemCount()
|
||||||
|
@ -203,7 +203,7 @@ qint64 JobListModel::recalcTotalItemCount()
|
||||||
void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool fullData)
|
void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool fullData)
|
||||||
{
|
{
|
||||||
QByteArray sql;
|
QByteArray sql;
|
||||||
if(fullData)
|
if (fullData)
|
||||||
{
|
{
|
||||||
sql = "SELECT jobs.id, jobs.category, jobs.shift_id, jobshifts.name,"
|
sql = "SELECT jobs.id, jobs.category, jobs.shift_id, jobshifts.name,"
|
||||||
"MIN(s1.departure), s1.station_id, MAX(s2.arrival), s2.station_id"
|
"MIN(s1.departure), s1.station_id, MAX(s2.arrival), s2.station_id"
|
||||||
|
@ -216,44 +216,44 @@ void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool
|
||||||
sql = "SELECT COUNT(1) FROM jobs";
|
sql = "SELECT COUNT(1) FROM jobs";
|
||||||
}
|
}
|
||||||
|
|
||||||
//If counting but filtering by shift name (not null) we need to JOIN jobshifts
|
// If counting but filtering by shift name (not null) we need to JOIN jobshifts
|
||||||
bool shiftFilterIsNull = m_shiftFilter.startsWith(nullFilterStr, Qt::CaseInsensitive);
|
bool shiftFilterIsNull = m_shiftFilter.startsWith(nullFilterStr, Qt::CaseInsensitive);
|
||||||
if(fullData || (!shiftFilterIsNull && !m_shiftFilter.isEmpty()))
|
if (fullData || (!shiftFilterIsNull && !m_shiftFilter.isEmpty()))
|
||||||
sql += " LEFT JOIN jobshifts ON jobshifts.id=jobs.shift_id";
|
sql += " LEFT JOIN jobshifts ON jobshifts.id=jobs.shift_id";
|
||||||
|
|
||||||
bool whereClauseAdded = false;
|
bool whereClauseAdded = false;
|
||||||
|
|
||||||
if(!m_jobIdFilter.isEmpty())
|
if (!m_jobIdFilter.isEmpty())
|
||||||
{
|
{
|
||||||
sql.append(" WHERE jobs.id LIKE ?3");
|
sql.append(" WHERE jobs.id LIKE ?3");
|
||||||
whereClauseAdded = true;
|
whereClauseAdded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!m_shiftFilter.isEmpty())
|
if (!m_shiftFilter.isEmpty())
|
||||||
{
|
{
|
||||||
if(whereClauseAdded)
|
if (whereClauseAdded)
|
||||||
sql.append(" AND ");
|
sql.append(" AND ");
|
||||||
else
|
else
|
||||||
sql.append(" WHERE ");
|
sql.append(" WHERE ");
|
||||||
|
|
||||||
if(shiftFilterIsNull)
|
if (shiftFilterIsNull)
|
||||||
sql.append("jobs.shift_id IS NULL");
|
sql.append("jobs.shift_id IS NULL");
|
||||||
else
|
else
|
||||||
sql.append("jobshifts.name LIKE ?4");
|
sql.append("jobshifts.name LIKE ?4");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fullData)
|
if (fullData)
|
||||||
{
|
{
|
||||||
//Group by Job
|
// Group by Job
|
||||||
sql.append(" GROUP BY jobs.id");
|
sql.append(" GROUP BY jobs.id");
|
||||||
|
|
||||||
//Apply sorting
|
// Apply sorting
|
||||||
const char *sortColExpr = nullptr;
|
const char *sortColExpr = nullptr;
|
||||||
switch (sortCol)
|
switch (sortCol)
|
||||||
{
|
{
|
||||||
case IdCol:
|
case IdCol:
|
||||||
{
|
{
|
||||||
sortColExpr = "jobs.id"; //Order by 1 column, no where clause
|
sortColExpr = "jobs.id"; // Order by 1 column, no where clause
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Category:
|
case Category:
|
||||||
|
@ -282,23 +282,23 @@ void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool
|
||||||
sql += sortColExpr;
|
sql += sortColExpr;
|
||||||
|
|
||||||
sql += " LIMIT ?1";
|
sql += " LIMIT ?1";
|
||||||
if(offset)
|
if (offset)
|
||||||
sql += " OFFSET ?2";
|
sql += " OFFSET ?2";
|
||||||
}
|
}
|
||||||
|
|
||||||
q.prepare(sql);
|
q.prepare(sql);
|
||||||
|
|
||||||
if(fullData)
|
if (fullData)
|
||||||
{
|
{
|
||||||
//Apply offset and batch size
|
// Apply offset and batch size
|
||||||
q.bind(1, BatchSize);
|
q.bind(1, BatchSize);
|
||||||
if(offset)
|
if (offset)
|
||||||
q.bind(2, offset);
|
q.bind(2, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Apply filters
|
// Apply filters
|
||||||
QByteArray jobFilter;
|
QByteArray jobFilter;
|
||||||
if(!m_jobIdFilter.isEmpty())
|
if (!m_jobIdFilter.isEmpty())
|
||||||
{
|
{
|
||||||
jobFilter.reserve(m_jobIdFilter.size() + 2);
|
jobFilter.reserve(m_jobIdFilter.size() + 2);
|
||||||
jobFilter.append('%');
|
jobFilter.append('%');
|
||||||
|
@ -308,7 +308,7 @@ void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray shiftFilter;
|
QByteArray shiftFilter;
|
||||||
if(!m_shiftFilter.isEmpty() && !shiftFilterIsNull)
|
if (!m_shiftFilter.isEmpty() && !shiftFilterIsNull)
|
||||||
{
|
{
|
||||||
shiftFilter.reserve(m_shiftFilter.size() + 2);
|
shiftFilter.reserve(m_shiftFilter.size() + 2);
|
||||||
shiftFilter.append('%');
|
shiftFilter.append('%');
|
||||||
|
@ -318,7 +318,7 @@ void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const QVariant &/*val*/)
|
void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const QVariant & /*val*/)
|
||||||
{
|
{
|
||||||
query q(mDb);
|
query q(mDb);
|
||||||
|
|
||||||
|
@ -331,29 +331,29 @@ void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const Q
|
||||||
|
|
||||||
QVector<JobItem> vec(BatchSize);
|
QVector<JobItem> vec(BatchSize);
|
||||||
|
|
||||||
//QString are implicitly shared, use QHash to temporary store them instead
|
// QString are implicitly shared, use QHash to temporary store them instead
|
||||||
//of creating new ones for each JobItem
|
// of creating new ones for each JobItem
|
||||||
QHash<db_id, QString> shiftHash;
|
QHash<db_id, QString> shiftHash;
|
||||||
QHash<db_id, QString> stationHash;
|
QHash<db_id, QString> stationHash;
|
||||||
|
|
||||||
auto it = q.begin();
|
auto it = q.begin();
|
||||||
const auto end = q.end();
|
const auto end = q.end();
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const int increment = 1;
|
const int increment = 1;
|
||||||
|
|
||||||
for(; it != end; ++it)
|
for (; it != end; ++it)
|
||||||
{
|
{
|
||||||
auto r = *it;
|
auto r = *it;
|
||||||
JobItem &item = vec[i];
|
JobItem &item = vec[i];
|
||||||
item.jobId = r.get<db_id>(0);
|
item.jobId = r.get<db_id>(0);
|
||||||
item.category = JobCategory(r.get<int>(1));
|
item.category = JobCategory(r.get<int>(1));
|
||||||
item.shiftId = r.get<db_id>(2);
|
item.shiftId = r.get<db_id>(2);
|
||||||
|
|
||||||
if(item.shiftId)
|
if (item.shiftId)
|
||||||
{
|
{
|
||||||
auto shift = shiftHash.constFind(item.shiftId);
|
auto shift = shiftHash.constFind(item.shiftId);
|
||||||
if(shift == shiftHash.constEnd())
|
if (shift == shiftHash.constEnd())
|
||||||
{
|
{
|
||||||
shift = shiftHash.insert(item.shiftId, r.get<QString>(3));
|
shift = shiftHash.insert(item.shiftId, r.get<QString>(3));
|
||||||
}
|
}
|
||||||
|
@ -362,13 +362,13 @@ void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const Q
|
||||||
|
|
||||||
item.originTime = r.get<QTime>(4);
|
item.originTime = r.get<QTime>(4);
|
||||||
item.originStId = r.get<db_id>(5);
|
item.originStId = r.get<db_id>(5);
|
||||||
item.destTime = r.get<QTime>(6);
|
item.destTime = r.get<QTime>(6);
|
||||||
item.destStId = r.get<db_id>(7);
|
item.destStId = r.get<db_id>(7);
|
||||||
|
|
||||||
if(item.originStId)
|
if (item.originStId)
|
||||||
{
|
{
|
||||||
auto st = stationHash.constFind(item.originStId);
|
auto st = stationHash.constFind(item.originStId);
|
||||||
if(st == stationHash.constEnd())
|
if (st == stationHash.constEnd())
|
||||||
{
|
{
|
||||||
q_stationName.bind(1, item.originStId);
|
q_stationName.bind(1, item.originStId);
|
||||||
q_stationName.step();
|
q_stationName.step();
|
||||||
|
@ -378,10 +378,10 @@ void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const Q
|
||||||
item.origStName = st.value();
|
item.origStName = st.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item.destStId)
|
if (item.destStId)
|
||||||
{
|
{
|
||||||
auto st = stationHash.constFind(item.destStId);
|
auto st = stationHash.constFind(item.destStId);
|
||||||
if(st == stationHash.constEnd())
|
if (st == stationHash.constEnd())
|
||||||
{
|
{
|
||||||
q_stationName.bind(1, item.destStId);
|
q_stationName.bind(1, item.destStId);
|
||||||
q_stationName.step();
|
q_stationName.step();
|
||||||
|
@ -394,7 +394,7 @@ void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const Q
|
||||||
i += increment;
|
i += increment;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i < BatchSize)
|
if (i < BatchSize)
|
||||||
vec.remove(i, BatchSize - i);
|
vec.remove(i, BatchSize - i);
|
||||||
|
|
||||||
postResult(vec, first);
|
postResult(vec, first);
|
||||||
|
|
|
@ -48,9 +48,13 @@ class JobListModel : public IPagedItemModelImpl<JobListModel, JobListModelItem>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum { BatchSize = 100 };
|
enum
|
||||||
|
{
|
||||||
|
BatchSize = 100
|
||||||
|
};
|
||||||
|
|
||||||
enum Columns {
|
enum Columns
|
||||||
|
{
|
||||||
IdCol = 0,
|
IdCol = 0,
|
||||||
Category,
|
Category,
|
||||||
ShiftCol,
|
ShiftCol,
|
||||||
|
@ -69,7 +73,8 @@ public:
|
||||||
// QAbstractTableModel
|
// QAbstractTableModel
|
||||||
|
|
||||||
// Header:
|
// Header:
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
@ -77,35 +82,35 @@ public:
|
||||||
|
|
||||||
virtual void setSortingColumn(int col) override;
|
virtual void setSortingColumn(int col) override;
|
||||||
|
|
||||||
//Filter
|
// Filter
|
||||||
std::pair<QString, FilterFlags> getFilterAtCol(int col) override;
|
std::pair<QString, FilterFlags> getFilterAtCol(int col) override;
|
||||||
bool setFilterAtCol(int col, const QString& str) override;
|
bool setFilterAtCol(int col, const QString &str) override;
|
||||||
|
|
||||||
// Convinience
|
// Convinience
|
||||||
inline db_id getIdAtRow(int row) const
|
inline db_id getIdAtRow(int row) const
|
||||||
{
|
{
|
||||||
if (row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
if (row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
||||||
return 0; //Invalid
|
return 0; // Invalid
|
||||||
|
|
||||||
const JobItem& item = cache.at(row - cacheFirstRow);
|
const JobItem &item = cache.at(row - cacheFirstRow);
|
||||||
return item.jobId;
|
return item.jobId;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QPair<db_id, JobCategory> getShiftAnCatAtRow(int row) const
|
inline QPair<db_id, JobCategory> getShiftAnCatAtRow(int row) const
|
||||||
{
|
{
|
||||||
if (row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
if (row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
||||||
return {0, JobCategory::NCategories}; //Invalid
|
return {0, JobCategory::NCategories}; // Invalid
|
||||||
|
|
||||||
const JobItem& item = cache.at(row - cacheFirstRow);
|
const JobItem &item = cache.at(row - cacheFirstRow);
|
||||||
return {item.shiftId, item.category};
|
return {item.shiftId, item.category};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QPair<QTime, QTime> getOrigAndDestTimeAtRow(int row) const
|
inline QPair<QTime, QTime> getOrigAndDestTimeAtRow(int row) const
|
||||||
{
|
{
|
||||||
if (row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
if (row < cacheFirstRow || row >= cacheFirstRow + cache.size())
|
||||||
return {}; //Invalid
|
return {}; // Invalid
|
||||||
|
|
||||||
const JobItem& item = cache.at(row - cacheFirstRow);
|
const JobItem &item = cache.at(row - cacheFirstRow);
|
||||||
return {item.originTime, item.destTime};
|
return {item.originTime, item.destTime};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,11 @@ JobMatchModel::JobMatchModel(database &db, QObject *parent) :
|
||||||
|
|
||||||
int JobMatchModel::columnCount(const QModelIndex &p) const
|
int JobMatchModel::columnCount(const QModelIndex &p) const
|
||||||
{
|
{
|
||||||
if(p.isValid())
|
if (p.isValid())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(!m_stopStationId)
|
if (!m_stopStationId)
|
||||||
return NCols - 1; //Hide stop arrival if no station filter is set
|
return NCols - 1; // Hide stop arrival if no station filter is set
|
||||||
return NCols;
|
return NCols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
case JobCategoryCol:
|
case JobCategoryCol:
|
||||||
{
|
{
|
||||||
if(isEllipsesRow(idx.row()))
|
if (isEllipsesRow(idx.row()))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
||||||
}
|
}
|
||||||
case JobNumber:
|
case JobNumber:
|
||||||
{
|
{
|
||||||
if(isEllipsesRow(idx.row()))
|
if (isEllipsesRow(idx.row()))
|
||||||
{
|
{
|
||||||
return ellipsesString;
|
return ellipsesString;
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,8 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
||||||
}
|
}
|
||||||
case StopArrivalCol:
|
case StopArrivalCol:
|
||||||
{
|
{
|
||||||
if(!m_stopStationId)
|
if (!m_stopStationId)
|
||||||
break; //Do not show stop arrival if not filtering by station
|
break; // Do not show stop arrival if not filtering by station
|
||||||
|
|
||||||
return items[idx.row()].stopArrival;
|
return items[idx.row()].stopArrival;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
||||||
}
|
}
|
||||||
case Qt::ForegroundRole:
|
case Qt::ForegroundRole:
|
||||||
{
|
{
|
||||||
if(isEllipsesRow(idx.row()))
|
if (isEllipsesRow(idx.row()))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
||||||
void JobMatchModel::autoSuggest(const QString &text)
|
void JobMatchModel::autoSuggest(const QString &text)
|
||||||
{
|
{
|
||||||
mQuery.clear();
|
mQuery.clear();
|
||||||
if(!text.isEmpty())
|
if (!text.isEmpty())
|
||||||
{
|
{
|
||||||
mQuery.reserve(text.size() + 2);
|
mQuery.reserve(text.size() + 2);
|
||||||
mQuery.append('%');
|
mQuery.append('%');
|
||||||
|
@ -137,36 +137,36 @@ void JobMatchModel::autoSuggest(const QString &text)
|
||||||
|
|
||||||
void JobMatchModel::refreshData()
|
void JobMatchModel::refreshData()
|
||||||
{
|
{
|
||||||
if(!mDb.db())
|
if (!mDb.db())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
char emptyQuery = '%';
|
char emptyQuery = '%';
|
||||||
|
|
||||||
if(mQuery.isEmpty())
|
if (mQuery.isEmpty())
|
||||||
sqlite3_bind_text(q_getMatches.stmt(), 1, &emptyQuery, 1, SQLITE_STATIC);
|
sqlite3_bind_text(q_getMatches.stmt(), 1, &emptyQuery, 1, SQLITE_STATIC);
|
||||||
else
|
else
|
||||||
sqlite3_bind_text(q_getMatches.stmt(), 1, mQuery, mQuery.size(), SQLITE_STATIC);
|
sqlite3_bind_text(q_getMatches.stmt(), 1, mQuery, mQuery.size(), SQLITE_STATIC);
|
||||||
|
|
||||||
if(m_exceptJobId)
|
if (m_exceptJobId)
|
||||||
q_getMatches.bind(2, m_exceptJobId);
|
q_getMatches.bind(2, m_exceptJobId);
|
||||||
|
|
||||||
if(m_stopStationId)
|
if (m_stopStationId)
|
||||||
{
|
{
|
||||||
q_getMatches.bind(3, m_stopStationId);
|
q_getMatches.bind(3, m_stopStationId);
|
||||||
if(!m_maxStopArrival.isNull())
|
if (!m_maxStopArrival.isNull())
|
||||||
q_getMatches.bind(4, m_maxStopArrival);
|
q_getMatches.bind(4, m_maxStopArrival);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto end = q_getMatches.end();
|
auto end = q_getMatches.end();
|
||||||
auto it = q_getMatches.begin();
|
auto it = q_getMatches.begin();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(; i < MaxMatchItems && it != end; i++)
|
for (; i < MaxMatchItems && it != end; i++)
|
||||||
{
|
{
|
||||||
items[i].stop.jobId = (*it).get<db_id>(0);
|
items[i].stop.jobId = (*it).get<db_id>(0);
|
||||||
items[i].stop.category = JobCategory((*it).get<int>(1));
|
items[i].stop.category = JobCategory((*it).get<int>(1));
|
||||||
if(m_stopStationId)
|
if (m_stopStationId)
|
||||||
{
|
{
|
||||||
items[i].stop.stopId = (*it).get<db_id>(2);
|
items[i].stop.stopId = (*it).get<db_id>(2);
|
||||||
items[i].stopArrival = (*it).get<QTime>(3);
|
items[i].stopArrival = (*it).get<QTime>(3);
|
||||||
|
@ -176,13 +176,13 @@ void JobMatchModel::refreshData()
|
||||||
}
|
}
|
||||||
|
|
||||||
size = i;
|
size = i;
|
||||||
if(hasEmptyRow)
|
if (hasEmptyRow)
|
||||||
size++; //Items + Empty, add 1 row
|
size++; // Items + Empty, add 1 row
|
||||||
|
|
||||||
if(it != end)
|
if (it != end)
|
||||||
{
|
{
|
||||||
//There would be still rows, show Ellipses
|
// There would be still rows, show Ellipses
|
||||||
size++; //Items + Empty + Ellispses
|
size++; // Items + Empty + Ellispses
|
||||||
}
|
}
|
||||||
|
|
||||||
q_getMatches.reset();
|
q_getMatches.reset();
|
||||||
|
@ -193,12 +193,12 @@ void JobMatchModel::refreshData()
|
||||||
|
|
||||||
QString JobMatchModel::getName(db_id jobId) const
|
QString JobMatchModel::getName(db_id jobId) const
|
||||||
{
|
{
|
||||||
if(!mDb.db())
|
if (!mDb.db())
|
||||||
return QString();
|
return QString();
|
||||||
|
|
||||||
query q(mDb, "SELECT category FROM jobs WHERE id=?");
|
query q(mDb, "SELECT category FROM jobs WHERE id=?");
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
if(q.step() != SQLITE_ROW)
|
if (q.step() != SQLITE_ROW)
|
||||||
return QString();
|
return QString();
|
||||||
|
|
||||||
JobCategory jobCat = JobCategory(q.getRows().get<int>(0));
|
JobCategory jobCat = JobCategory(q.getRows().get<int>(0));
|
||||||
|
@ -207,32 +207,31 @@ QString JobMatchModel::getName(db_id jobId) const
|
||||||
|
|
||||||
db_id JobMatchModel::getIdAtRow(int row) const
|
db_id JobMatchModel::getIdAtRow(int row) const
|
||||||
{
|
{
|
||||||
if(m_defaultId == StopId)
|
if (m_defaultId == StopId)
|
||||||
return items[row].stop.stopId;
|
return items[row].stop.stopId;
|
||||||
return items[row].stop.jobId;
|
return items[row].stop.jobId;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString JobMatchModel::getNameAtRow(int row) const
|
QString JobMatchModel::getNameAtRow(int row) const
|
||||||
{
|
{
|
||||||
return JobCategoryName::jobName(items[row].stop.jobId,
|
return JobCategoryName::jobName(items[row].stop.jobId, items[row].stop.category);
|
||||||
items[row].stop.category);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobMatchModel::setFilter(db_id exceptJobId, db_id stopsInStationId, const QTime &maxStopArr)
|
void JobMatchModel::setFilter(db_id exceptJobId, db_id stopsInStationId, const QTime &maxStopArr)
|
||||||
{
|
{
|
||||||
m_exceptJobId = exceptJobId;
|
m_exceptJobId = exceptJobId;
|
||||||
m_stopStationId = stopsInStationId;
|
m_stopStationId = stopsInStationId;
|
||||||
m_maxStopArrival = maxStopArr;
|
m_maxStopArrival = maxStopArr;
|
||||||
|
|
||||||
QByteArray sql;
|
QByteArray sql;
|
||||||
if(m_stopStationId)
|
if (m_stopStationId)
|
||||||
{
|
{
|
||||||
//Filter by stopping station
|
// Filter by stopping station
|
||||||
sql = "SELECT stops.job_id, jobs.category, stops.id, stops.arrival"
|
sql = "SELECT stops.job_id, jobs.category, stops.id, stops.arrival"
|
||||||
" FROM stops JOIN jobs ON jobs.id=stops.job_id"
|
" FROM stops JOIN jobs ON jobs.id=stops.job_id"
|
||||||
" WHERE stops.station_id=?3 AND";
|
" WHERE stops.station_id=?3 AND";
|
||||||
|
|
||||||
if(!m_maxStopArrival.isNull())
|
if (!m_maxStopArrival.isNull())
|
||||||
sql += " stops.arrival < ?4 AND";
|
sql += " stops.arrival < ?4 AND";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -240,18 +239,18 @@ void JobMatchModel::setFilter(db_id exceptJobId, db_id stopsInStationId, const Q
|
||||||
sql = "SELECT jobs.id, jobs.category FROM jobs WHERE";
|
sql = "SELECT jobs.id, jobs.category FROM jobs WHERE";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(exceptJobId)
|
if (exceptJobId)
|
||||||
{
|
{
|
||||||
//Filter out unwanted job ID
|
// Filter out unwanted job ID
|
||||||
sql += " jobs.id<>?2 AND";
|
sql += " jobs.id<>?2 AND";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Filter by name (job ID number)
|
// Filter by name (job ID number)
|
||||||
//FIXME: filter also by category with regexp
|
// FIXME: filter also by category with regexp
|
||||||
sql += " jobs.id LIKE ?1";
|
sql += " jobs.id LIKE ?1";
|
||||||
|
|
||||||
sql += " ORDER BY ";
|
sql += " ORDER BY ";
|
||||||
if(m_stopStationId)
|
if (m_stopStationId)
|
||||||
{
|
{
|
||||||
sql += "stops.arrival, ";
|
sql += "stops.arrival, ";
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
#include <sqlite3pp/sqlite3pp.h>
|
#include <sqlite3pp/sqlite3pp.h>
|
||||||
using namespace sqlite3pp;
|
using namespace sqlite3pp;
|
||||||
|
|
||||||
//TODO: share common code with SearchResultModel
|
// TODO: share common code with SearchResultModel
|
||||||
//TODO: allow filter byy job category
|
// TODO: allow filter byy job category
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Match model for Jobs
|
* \brief Match model for Jobs
|
||||||
|
@ -67,7 +67,7 @@ public:
|
||||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
// ISqlFKMatchModel:
|
// ISqlFKMatchModel:
|
||||||
void autoSuggest(const QString& text) override;
|
void autoSuggest(const QString &text) override;
|
||||||
virtual void refreshData() override;
|
virtual void refreshData() override;
|
||||||
QString getName(db_id jobId) const override;
|
QString getName(db_id jobId) const override;
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ public:
|
||||||
QString getNameAtRow(int row) const override;
|
QString getNameAtRow(int row) const override;
|
||||||
|
|
||||||
// JobMatchModel:
|
// JobMatchModel:
|
||||||
void setFilter(db_id exceptJobId, db_id stopsInStationId, const QTime& maxStopArr);
|
void setFilter(db_id exceptJobId, db_id stopsInStationId, const QTime &maxStopArr);
|
||||||
|
|
||||||
void setDefaultId(DefaultId defaultId);
|
void setDefaultId(DefaultId defaultId);
|
||||||
|
|
||||||
|
|
|
@ -28,20 +28,20 @@
|
||||||
bool JobsHelper::createNewJob(sqlite3pp::database &db, db_id &outJobId, JobCategory cat)
|
bool JobsHelper::createNewJob(sqlite3pp::database &db, db_id &outJobId, JobCategory cat)
|
||||||
{
|
{
|
||||||
sqlite3pp::command q_newJob(db, "INSERT INTO jobs(id,category,shift_id) VALUES(?,?,NULL)");
|
sqlite3pp::command q_newJob(db, "INSERT INTO jobs(id,category,shift_id) VALUES(?,?,NULL)");
|
||||||
if(outJobId)
|
if (outJobId)
|
||||||
q_newJob.bind(1, outJobId);
|
q_newJob.bind(1, outJobId);
|
||||||
else
|
else
|
||||||
q_newJob.bind(1); //Bind NULL
|
q_newJob.bind(1); // Bind NULL
|
||||||
q_newJob.bind(2, int(cat));
|
q_newJob.bind(2, int(cat));
|
||||||
|
|
||||||
sqlite3_mutex *mutex = sqlite3_db_mutex(db.db());
|
sqlite3_mutex *mutex = sqlite3_db_mutex(db.db());
|
||||||
sqlite3_mutex_enter(mutex);
|
sqlite3_mutex_enter(mutex);
|
||||||
int rc = q_newJob.execute();
|
int rc = q_newJob.execute();
|
||||||
db_id jobId = db.last_insert_rowid();
|
db_id jobId = db.last_insert_rowid();
|
||||||
sqlite3_mutex_leave(mutex);
|
sqlite3_mutex_leave(mutex);
|
||||||
q_newJob.reset();
|
q_newJob.reset();
|
||||||
|
|
||||||
if(rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << rc << db.error_msg();
|
qWarning() << rc << db.error_msg();
|
||||||
outJobId = 0;
|
outJobId = 0;
|
||||||
|
@ -59,44 +59,45 @@ bool JobsHelper::removeJob(sqlite3pp::database &db, db_id jobId)
|
||||||
{
|
{
|
||||||
sqlite3pp::query q(db, "SELECT shift_id FROM jobs WHERE id=?");
|
sqlite3pp::query q(db, "SELECT shift_id FROM jobs WHERE id=?");
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
if(q.step() != SQLITE_ROW)
|
if (q.step() != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
return false; //Job doesn't exist
|
return false; // Job doesn't exist
|
||||||
}
|
}
|
||||||
db_id shiftId = q.getRows().get<db_id>(0);
|
db_id shiftId = q.getRows().get<db_id>(0);
|
||||||
q.reset();
|
q.reset();
|
||||||
|
|
||||||
if(shiftId != 0)
|
if (shiftId != 0)
|
||||||
{
|
{
|
||||||
//Remove job from shift
|
// Remove job from shift
|
||||||
emit Session->shiftJobsChanged(shiftId, jobId);
|
emit Session->shiftJobsChanged(shiftId, jobId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get stations in which job stopped or transited
|
// Get stations in which job stopped or transited
|
||||||
QSet<db_id> stationsToUpdate;
|
QSet<db_id> stationsToUpdate;
|
||||||
q.prepare("SELECT station_id FROM stops WHERE job_id=?"
|
q.prepare("SELECT station_id FROM stops WHERE job_id=?"
|
||||||
" UNION "
|
" UNION "
|
||||||
"SELECT station_id FROM old_stops WHERE job_id=?");
|
"SELECT station_id FROM old_stops WHERE job_id=?");
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
for(auto st : q)
|
for (auto st : q)
|
||||||
{
|
{
|
||||||
stationsToUpdate.insert(st.get<db_id>(0));
|
stationsToUpdate.insert(st.get<db_id>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get Rollingstock used by job
|
// Get Rollingstock used by job
|
||||||
QSet<db_id> rsToUpdate;
|
QSet<db_id> rsToUpdate;
|
||||||
q.prepare("SELECT coupling.rs_id FROM stops JOIN coupling ON coupling.stop_id=stops.id"
|
q.prepare("SELECT coupling.rs_id FROM stops JOIN coupling ON coupling.stop_id=stops.id"
|
||||||
" WHERE stops.job_id=?"
|
" WHERE stops.job_id=?"
|
||||||
" UNION "
|
" UNION "
|
||||||
"SELECT old_coupling.rs_id FROM old_stops JOIN old_coupling ON old_coupling.stop_id=old_stops.id"
|
"SELECT old_coupling.rs_id FROM old_stops JOIN old_coupling ON "
|
||||||
|
"old_coupling.stop_id=old_stops.id"
|
||||||
" WHERE old_stops.job_id=?");
|
" WHERE old_stops.job_id=?");
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
for(auto rs : q)
|
for (auto rs : q)
|
||||||
{
|
{
|
||||||
rsToUpdate.insert(rs.get<db_id>(0));
|
rsToUpdate.insert(rs.get<db_id>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove job
|
// Remove job
|
||||||
db.execute("BEGIN TRANSACTION");
|
db.execute("BEGIN TRANSACTION");
|
||||||
|
|
||||||
q.prepare("DELETE FROM stops WHERE job_id=?");
|
q.prepare("DELETE FROM stops WHERE job_id=?");
|
||||||
|
@ -105,16 +106,16 @@ bool JobsHelper::removeJob(sqlite3pp::database &db, db_id jobId)
|
||||||
int ret = q.step();
|
int ret = q.step();
|
||||||
q.reset();
|
q.reset();
|
||||||
|
|
||||||
if(ret == SQLITE_OK || ret == SQLITE_DONE)
|
if (ret == SQLITE_OK || ret == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
//Remove possible left over from editing
|
// Remove possible left over from editing
|
||||||
q.prepare("DELETE FROM old_stops WHERE job_id=?");
|
q.prepare("DELETE FROM old_stops WHERE job_id=?");
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
ret = q.step();
|
ret = q.step();
|
||||||
q.reset();
|
q.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ret == SQLITE_OK || ret == SQLITE_DONE)
|
if (ret == SQLITE_OK || ret == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
q.prepare("DELETE FROM jobs WHERE id=?");
|
q.prepare("DELETE FROM jobs WHERE id=?");
|
||||||
q.bind(1, jobId);
|
q.bind(1, jobId);
|
||||||
|
@ -122,23 +123,24 @@ bool JobsHelper::removeJob(sqlite3pp::database &db, db_id jobId)
|
||||||
q.reset();
|
q.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ret == SQLITE_OK || ret == SQLITE_DONE)
|
if (ret == SQLITE_OK || ret == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
db.execute("COMMIT");
|
db.execute("COMMIT");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "Error while removing Job:" << jobId << ret << db.error_msg() << db.extended_error_code();
|
qDebug() << "Error while removing Job:" << jobId << ret << db.error_msg()
|
||||||
|
<< db.extended_error_code();
|
||||||
db.execute("ROLLBACK");
|
db.execute("ROLLBACK");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit Session->jobRemoved(jobId);
|
emit Session->jobRemoved(jobId);
|
||||||
|
|
||||||
//Refresh graphs and station views
|
// Refresh graphs and station views
|
||||||
emit Session->stationJobsPlanChanged(stationsToUpdate);
|
emit Session->stationJobsPlanChanged(stationsToUpdate);
|
||||||
|
|
||||||
//Refresh Rollingstock views
|
// Refresh Rollingstock views
|
||||||
emit Session->rollingStockPlanChanged(rsToUpdate);
|
emit Session->rollingStockPlanChanged(rsToUpdate);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -146,21 +148,21 @@ bool JobsHelper::removeJob(sqlite3pp::database &db, db_id jobId)
|
||||||
|
|
||||||
bool JobsHelper::removeAllJobs(sqlite3pp::database &db)
|
bool JobsHelper::removeAllJobs(sqlite3pp::database &db)
|
||||||
{
|
{
|
||||||
//Old
|
// Old
|
||||||
sqlite3pp::command cmd(db, "DELETE FROM old_coupling");
|
sqlite3pp::command cmd(db, "DELETE FROM old_coupling");
|
||||||
cmd.execute();
|
cmd.execute();
|
||||||
|
|
||||||
cmd.prepare("DELETE FROM old_stops");
|
cmd.prepare("DELETE FROM old_stops");
|
||||||
cmd.execute();
|
cmd.execute();
|
||||||
|
|
||||||
//Current
|
// Current
|
||||||
cmd.prepare("DELETE FROM coupling");
|
cmd.prepare("DELETE FROM coupling");
|
||||||
cmd.execute();
|
cmd.execute();
|
||||||
|
|
||||||
cmd.prepare("DELETE FROM stops");
|
cmd.prepare("DELETE FROM stops");
|
||||||
cmd.execute();
|
cmd.execute();
|
||||||
|
|
||||||
//Delete jobs
|
// Delete jobs
|
||||||
cmd.prepare("DELETE FROM jobs");
|
cmd.prepare("DELETE FROM jobs");
|
||||||
cmd.execute();
|
cmd.execute();
|
||||||
|
|
||||||
|
@ -169,13 +171,14 @@ bool JobsHelper::removeAllJobs(sqlite3pp::database &db)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTime calcReversedTime(const QTime& start, const QTime& end, const QTime& value)
|
QTime calcReversedTime(const QTime &start, const QTime &end, const QTime &value)
|
||||||
{
|
{
|
||||||
const int msecsFromStart = start.msecsTo(value);
|
const int msecsFromStart = start.msecsTo(value);
|
||||||
return end.addMSecs(-msecsFromStart);
|
return end.addMSecs(-msecsFromStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JobsHelper::copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJobId, int secsOffset, bool copyRsOps, bool reversePath)
|
bool JobsHelper::copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJobId, int secsOffset,
|
||||||
|
bool copyRsOps, bool reversePath)
|
||||||
{
|
{
|
||||||
query q_getStops(db, "SELECT id,station_id,arrival,departure,type,"
|
query q_getStops(db, "SELECT id,station_id,arrival,departure,type,"
|
||||||
"description,in_gate_conn,out_gate_conn,next_segment_conn_id"
|
"description,in_gate_conn,out_gate_conn,next_segment_conn_id"
|
||||||
|
@ -191,9 +194,9 @@ bool JobsHelper::copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJob
|
||||||
QSet<db_id> rsToUpdate;
|
QSet<db_id> rsToUpdate;
|
||||||
|
|
||||||
QTime start, end;
|
QTime start, end;
|
||||||
if(reversePath)
|
if (reversePath)
|
||||||
{
|
{
|
||||||
//Get first departure and last arrival to compute reversed time
|
// Get first departure and last arrival to compute reversed time
|
||||||
query q(db, "SELECT MIN(departure) FROM stops WHERE job_id=?");
|
query q(db, "SELECT MIN(departure) FROM stops WHERE job_id=?");
|
||||||
q.bind(1, fromJobId);
|
q.bind(1, fromJobId);
|
||||||
q.step();
|
q.step();
|
||||||
|
@ -205,54 +208,54 @@ bool JobsHelper::copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJob
|
||||||
end = q.getRows().get<QTime>(0);
|
end = q.getRows().get<QTime>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Store last next segment when reversing path
|
// Store last next segment when reversing path
|
||||||
db_id lastNextSegmentConn = 0;
|
db_id lastNextSegmentConn = 0;
|
||||||
|
|
||||||
q_getStops.bind(1, fromJobId);
|
q_getStops.bind(1, fromJobId);
|
||||||
for(auto stop : q_getStops)
|
for (auto stop : q_getStops)
|
||||||
{
|
{
|
||||||
db_id origStopId = stop.get<db_id>(0);
|
db_id origStopId = stop.get<db_id>(0);
|
||||||
db_id stationId = stop.get<db_id>(1);
|
db_id stationId = stop.get<db_id>(1);
|
||||||
QTime arrival = stop.get<QTime>(2);
|
QTime arrival = stop.get<QTime>(2);
|
||||||
QTime departure = stop.get<QTime>(3);
|
QTime departure = stop.get<QTime>(3);
|
||||||
int type = stop.get<int>(4);
|
int type = stop.get<int>(4);
|
||||||
|
|
||||||
//Avoid memory copy
|
// Avoid memory copy
|
||||||
const unsigned char *description = sqlite3_column_text(q_getStops.stmt(), 5);
|
const unsigned char *description = sqlite3_column_text(q_getStops.stmt(), 5);
|
||||||
const int descrLen = sqlite3_column_bytes(q_getStops.stmt(), 5);
|
const int descrLen = sqlite3_column_bytes(q_getStops.stmt(), 5);
|
||||||
|
|
||||||
db_id in_gate_conn = stop.get<db_id>(6);
|
db_id in_gate_conn = stop.get<db_id>(6);
|
||||||
db_id out_gate_conn = stop.get<db_id>(7);
|
db_id out_gate_conn = stop.get<db_id>(7);
|
||||||
db_id next_seg_conn = stop.get<db_id>(8);
|
db_id next_seg_conn = stop.get<db_id>(8);
|
||||||
|
|
||||||
if(reversePath)
|
if (reversePath)
|
||||||
{
|
{
|
||||||
//Calculate reversed time
|
// Calculate reversed time
|
||||||
const QTime origArr = arrival;
|
const QTime origArr = arrival;
|
||||||
const QTime origDep = departure;
|
const QTime origDep = departure;
|
||||||
|
|
||||||
//Arrival and departure get swapped
|
// Arrival and departure get swapped
|
||||||
arrival = calcReversedTime(start, end, origDep);
|
arrival = calcReversedTime(start, end, origDep);
|
||||||
departure = calcReversedTime(start, end, origArr);
|
departure = calcReversedTime(start, end, origArr);
|
||||||
|
|
||||||
//Swap current next segment with the one of previous stop
|
// Swap current next segment with the one of previous stop
|
||||||
qSwap(lastNextSegmentConn, next_seg_conn);
|
qSwap(lastNextSegmentConn, next_seg_conn);
|
||||||
|
|
||||||
//Swap gate connections
|
// Swap gate connections
|
||||||
qSwap(in_gate_conn, out_gate_conn);
|
qSwap(in_gate_conn, out_gate_conn);
|
||||||
|
|
||||||
//First stop, set in_gate = out_gate so track matches
|
// First stop, set in_gate = out_gate so track matches
|
||||||
//TODO: this shouldn't be needed but seems to not cause harm
|
// TODO: this shouldn't be needed but seems to not cause harm
|
||||||
if(!in_gate_conn)
|
if (!in_gate_conn)
|
||||||
in_gate_conn = out_gate_conn;
|
in_gate_conn = out_gate_conn;
|
||||||
|
|
||||||
//If we do not go past this station (Last stop) then we do not set out gate
|
// If we do not go past this station (Last stop) then we do not set out gate
|
||||||
if(!next_seg_conn)
|
if (!next_seg_conn)
|
||||||
out_gate_conn = 0;
|
out_gate_conn = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Apply time shift
|
// Apply time shift
|
||||||
arrival = arrival.addSecs(secsOffset);
|
arrival = arrival.addSecs(secsOffset);
|
||||||
departure = departure.addSecs(secsOffset);
|
departure = departure.addSecs(secsOffset);
|
||||||
|
|
||||||
q_setStop.bind(1, toJobId);
|
q_setStop.bind(1, toJobId);
|
||||||
|
@ -260,34 +263,35 @@ bool JobsHelper::copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJob
|
||||||
q_setStop.bind(3, arrival);
|
q_setStop.bind(3, arrival);
|
||||||
q_setStop.bind(4, departure);
|
q_setStop.bind(4, departure);
|
||||||
q_setStop.bind(5, type);
|
q_setStop.bind(5, type);
|
||||||
//Pass SQLITE_STATIC because description is valid until next loop cycle, so avoid copy
|
// Pass SQLITE_STATIC because description is valid until next loop cycle, so avoid copy
|
||||||
sqlite3_bind_text(q_setStop.stmt(), 6, reinterpret_cast<const char *>(description), descrLen, SQLITE_STATIC);
|
sqlite3_bind_text(q_setStop.stmt(), 6, reinterpret_cast<const char *>(description),
|
||||||
|
descrLen, SQLITE_STATIC);
|
||||||
q_setStop.bindOrNull(7, in_gate_conn);
|
q_setStop.bindOrNull(7, in_gate_conn);
|
||||||
q_setStop.bindOrNull(8, out_gate_conn);
|
q_setStop.bindOrNull(8, out_gate_conn);
|
||||||
q_setStop.bindOrNull(9, next_seg_conn);
|
q_setStop.bindOrNull(9, next_seg_conn);
|
||||||
if(q_setStop.execute() != SQLITE_OK)
|
if (q_setStop.execute() != SQLITE_OK)
|
||||||
{
|
{
|
||||||
qWarning() << "JobsHelper::copyStops() error setting stop" << origStopId << "To:" << toJobId << secsOffset
|
qWarning() << "JobsHelper::copyStops() error setting stop" << origStopId
|
||||||
<< db.error_msg();
|
<< "To:" << toJobId << secsOffset << db.error_msg();
|
||||||
continue; //Skip stop
|
continue; // Skip stop
|
||||||
}
|
}
|
||||||
db_id newStopId = db.last_insert_rowid();
|
db_id newStopId = db.last_insert_rowid();
|
||||||
q_setStop.reset();
|
q_setStop.reset();
|
||||||
|
|
||||||
if(copyRsOps)
|
if (copyRsOps)
|
||||||
{
|
{
|
||||||
q_getRsOp.bind(1, origStopId);
|
q_getRsOp.bind(1, origStopId);
|
||||||
for(auto rs : q_getRsOp)
|
for (auto rs : q_getRsOp)
|
||||||
{
|
{
|
||||||
db_id rsId = rs.get<db_id>(0);
|
db_id rsId = rs.get<db_id>(0);
|
||||||
RsOp op = RsOp(rs.get<int>(1));
|
RsOp op = RsOp(rs.get<int>(1));
|
||||||
|
|
||||||
if(reversePath)
|
if (reversePath)
|
||||||
{
|
{
|
||||||
//Reverse operations (Couple -> Uncouple and viceversa)
|
// Reverse operations (Couple -> Uncouple and viceversa)
|
||||||
if(op == RsOp::Coupled)
|
if (op == RsOp::Coupled)
|
||||||
op = RsOp::Uncoupled;
|
op = RsOp::Uncoupled;
|
||||||
else if(op == RsOp::Uncoupled)
|
else if (op == RsOp::Uncoupled)
|
||||||
op = RsOp::Coupled;
|
op = RsOp::Coupled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,20 +301,20 @@ bool JobsHelper::copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJob
|
||||||
q_setRsOp.execute();
|
q_setRsOp.execute();
|
||||||
q_setRsOp.reset();
|
q_setRsOp.reset();
|
||||||
|
|
||||||
//Store rollingstock ID to update it later
|
// Store rollingstock ID to update it later
|
||||||
rsToUpdate.insert(rsId);
|
rsToUpdate.insert(rsId);
|
||||||
}
|
}
|
||||||
q_getRsOp.reset();
|
q_getRsOp.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Store station to update it later
|
// Store station to update it later
|
||||||
stationsToUpdate.insert(stationId);
|
stationsToUpdate.insert(stationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Refresh graphs and station views
|
// Refresh graphs and station views
|
||||||
emit Session->stationJobsPlanChanged(stationsToUpdate);
|
emit Session->stationJobsPlanChanged(stationsToUpdate);
|
||||||
|
|
||||||
//Refresh Rollingstock views
|
// Refresh Rollingstock views
|
||||||
emit Session->rollingStockPlanChanged(rsToUpdate);
|
emit Session->rollingStockPlanChanged(rsToUpdate);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -333,7 +337,7 @@ JobStopDirectionHelper::JobStopDirectionHelper(sqlite3pp::database &db) :
|
||||||
" LEFT JOIN station_gates g1 ON g1.id=c1.gate_id"
|
" LEFT JOIN station_gates g1 ON g1.id=c1.gate_id"
|
||||||
" LEFT JOIN station_gates g2 ON g2.id=c2.gate_id"
|
" LEFT JOIN station_gates g2 ON g2.id=c2.gate_id"
|
||||||
" WHERE stops.id=?");
|
" WHERE stops.id=?");
|
||||||
if(ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
qWarning() << "JobStopDirectionHelper cannot prepare query";
|
qWarning() << "JobStopDirectionHelper cannot prepare query";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,27 +350,27 @@ JobStopDirectionHelper::~JobStopDirectionHelper()
|
||||||
utils::Side JobStopDirectionHelper::getStopOutSide(db_id stopId)
|
utils::Side JobStopDirectionHelper::getStopOutSide(db_id stopId)
|
||||||
{
|
{
|
||||||
m_query->bind(1, stopId);
|
m_query->bind(1, stopId);
|
||||||
if(m_query->step() != SQLITE_ROW)
|
if (m_query->step() != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
//Stop doesn't exist
|
// Stop doesn't exist
|
||||||
return utils::Side::NSides;
|
return utils::Side::NSides;
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::Side in_side = utils::Side::NSides;
|
utils::Side in_side = utils::Side::NSides;
|
||||||
utils::Side out_side = utils::Side::NSides;
|
utils::Side out_side = utils::Side::NSides;
|
||||||
|
|
||||||
auto r = m_query->getRows();
|
auto r = m_query->getRows();
|
||||||
if(r.column_type(0) != SQLITE_NULL)
|
if (r.column_type(0) != SQLITE_NULL)
|
||||||
in_side = utils::Side(r.get<int>(0));
|
in_side = utils::Side(r.get<int>(0));
|
||||||
if(r.column_type(1) != SQLITE_NULL)
|
if (r.column_type(1) != SQLITE_NULL)
|
||||||
out_side = utils::Side(r.get<int>(1));
|
out_side = utils::Side(r.get<int>(1));
|
||||||
|
|
||||||
//Prefer out side
|
// Prefer out side
|
||||||
if(out_side != utils::Side::NSides)
|
if (out_side != utils::Side::NSides)
|
||||||
return out_side;
|
return out_side;
|
||||||
|
|
||||||
//We only have in side, invert it
|
// We only have in side, invert it
|
||||||
if(in_side == utils::Side::NSides)
|
if (in_side == utils::Side::NSides)
|
||||||
return in_side;
|
return in_side;
|
||||||
|
|
||||||
return in_side == utils::Side::East ? utils::Side::West : utils::Side::East;
|
return in_side == utils::Side::East ? utils::Side::West : utils::Side::East;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
namespace sqlite3pp {
|
namespace sqlite3pp {
|
||||||
class database;
|
class database;
|
||||||
class query;
|
class query;
|
||||||
}
|
} // namespace sqlite3pp
|
||||||
|
|
||||||
class JobsHelper
|
class JobsHelper
|
||||||
{
|
{
|
||||||
|
@ -42,12 +42,13 @@ public:
|
||||||
* If the Job ID is already in use, the function fails and no new Job is created.
|
* If the Job ID is already in use, the function fails and no new Job is created.
|
||||||
* If 0 is passed, the function creates a new Job with arbitrary free ID from database
|
* If 0 is passed, the function creates a new Job with arbitrary free ID from database
|
||||||
*/
|
*/
|
||||||
static bool createNewJob(sqlite3pp::database &db, db_id &outJobId, JobCategory cat = JobCategory::FREIGHT);
|
static bool createNewJob(sqlite3pp::database &db, db_id &outJobId,
|
||||||
|
JobCategory cat = JobCategory::FREIGHT);
|
||||||
static bool removeJob(sqlite3pp::database &db, db_id jobId);
|
static bool removeJob(sqlite3pp::database &db, db_id jobId);
|
||||||
static bool removeAllJobs(sqlite3pp::database &db);
|
static bool removeAllJobs(sqlite3pp::database &db);
|
||||||
|
|
||||||
static bool copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJobId,
|
static bool copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJobId, int secsOffset,
|
||||||
int secsOffset, bool copyRsOps, bool reversePath);
|
bool copyRsOps, bool reversePath);
|
||||||
|
|
||||||
static bool checkShiftsExist(sqlite3pp::database &db);
|
static bool checkShiftsExist(sqlite3pp::database &db);
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,7 +33,7 @@ NewJobSamePathDlg::NewJobSamePathDlg(QWidget *parent) :
|
||||||
QDialog(parent)
|
QDialog(parent)
|
||||||
{
|
{
|
||||||
QVBoxLayout *lay = new QVBoxLayout(this);
|
QVBoxLayout *lay = new QVBoxLayout(this);
|
||||||
label = new QLabel;
|
label = new QLabel;
|
||||||
label->setTextFormat(Qt::RichText);
|
label->setTextFormat(Qt::RichText);
|
||||||
lay->addWidget(label);
|
lay->addWidget(label);
|
||||||
|
|
||||||
|
@ -41,11 +41,11 @@ NewJobSamePathDlg::NewJobSamePathDlg(QWidget *parent) :
|
||||||
lay->addWidget(startTimeEdit);
|
lay->addWidget(startTimeEdit);
|
||||||
|
|
||||||
copyRsCheck = new QCheckBox(tr("Copy Rollingstock items"));
|
copyRsCheck = new QCheckBox(tr("Copy Rollingstock items"));
|
||||||
copyRsCheck->setChecked(true); //Enabled by default
|
copyRsCheck->setChecked(true); // Enabled by default
|
||||||
lay->addWidget(copyRsCheck);
|
lay->addWidget(copyRsCheck);
|
||||||
|
|
||||||
reversePathCheck = new QCheckBox(tr("Reverse path"));
|
reversePathCheck = new QCheckBox(tr("Reverse path"));
|
||||||
reversePathCheck->setChecked(false); //Disabled by default
|
reversePathCheck->setChecked(false); // Disabled by default
|
||||||
lay->addWidget(reversePathCheck);
|
lay->addWidget(reversePathCheck);
|
||||||
|
|
||||||
QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
@ -60,21 +60,21 @@ NewJobSamePathDlg::NewJobSamePathDlg(QWidget *parent) :
|
||||||
setWindowTitle(tr("New Job With Same Path"));
|
setWindowTitle(tr("New Job With Same Path"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewJobSamePathDlg::setSourceJob(db_id jobId, JobCategory cat, const QTime &start, const QTime &end)
|
void NewJobSamePathDlg::setSourceJob(db_id jobId, JobCategory cat, const QTime &start,
|
||||||
|
const QTime &end)
|
||||||
{
|
{
|
||||||
sourceJobId = jobId;
|
sourceJobId = jobId;
|
||||||
sourceJobCat = cat;
|
sourceJobCat = cat;
|
||||||
sourceStart = start;
|
sourceStart = start;
|
||||||
sourceEnd = end;
|
sourceEnd = end;
|
||||||
|
|
||||||
label->setText(tr("Create a new job with same path of <b>%1</b>.<br>"
|
label->setText(tr("Create a new job with same path of <b>%1</b>.<br>"
|
||||||
"Original job starts at <b>%2</b> and ends at <b>%3</b>.<br>"
|
"Original job starts at <b>%2</b> and ends at <b>%3</b>.<br>"
|
||||||
"Please select below when the new job should start.")
|
"Please select below when the new job should start.")
|
||||||
.arg(JobCategoryName::jobName(sourceJobId, sourceJobCat),
|
.arg(JobCategoryName::jobName(sourceJobId, sourceJobCat),
|
||||||
sourceStart.toString("HH:mm"),
|
sourceStart.toString("HH:mm"), sourceEnd.toString("HH:mm")));
|
||||||
sourceEnd.toString("HH:mm")));
|
|
||||||
|
|
||||||
//Prevent calling checkTimeIsValid()
|
// Prevent calling checkTimeIsValid()
|
||||||
QSignalBlocker blk(startTimeEdit);
|
QSignalBlocker blk(startTimeEdit);
|
||||||
startTimeEdit->setTime(sourceStart);
|
startTimeEdit->setTime(sourceStart);
|
||||||
}
|
}
|
||||||
|
@ -96,21 +96,21 @@ bool NewJobSamePathDlg::shouldReversePath() const
|
||||||
|
|
||||||
void NewJobSamePathDlg::checkTimeIsValid()
|
void NewJobSamePathDlg::checkTimeIsValid()
|
||||||
{
|
{
|
||||||
const QTime lastValidTime = QTime(23, 59);
|
const QTime lastValidTime = QTime(23, 59);
|
||||||
const int travelDurationMsecs = sourceStart.msecsTo(sourceEnd);
|
const int travelDurationMsecs = sourceStart.msecsTo(sourceEnd);
|
||||||
|
|
||||||
QTime newStart = startTimeEdit->time();
|
QTime newStart = startTimeEdit->time();
|
||||||
int msecsToMidnight = newStart.msecsTo(lastValidTime);
|
int msecsToMidnight = newStart.msecsTo(lastValidTime);
|
||||||
if(travelDurationMsecs > msecsToMidnight)
|
if (travelDurationMsecs > msecsToMidnight)
|
||||||
{
|
{
|
||||||
//New job would end after midnigth
|
// New job would end after midnigth
|
||||||
QMessageBox::warning(this, tr("Invalid Start Time"),
|
QMessageBox::warning(this, tr("Invalid Start Time"),
|
||||||
tr("New job would end past midnight."));
|
tr("New job would end past midnight."));
|
||||||
|
|
||||||
//Go back from midnight to get maximum start value
|
// Go back from midnight to get maximum start value
|
||||||
newStart = lastValidTime.addMSecs(-travelDurationMsecs);
|
newStart = lastValidTime.addMSecs(-travelDurationMsecs);
|
||||||
|
|
||||||
//Prevent recursion
|
// Prevent recursion
|
||||||
QSignalBlocker blk(startTimeEdit);
|
QSignalBlocker blk(startTimeEdit);
|
||||||
startTimeEdit->setTime(newStart);
|
startTimeEdit->setTime(newStart);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ class NewJobSamePathDlg : public QDialog
|
||||||
public:
|
public:
|
||||||
explicit NewJobSamePathDlg(QWidget *parent = nullptr);
|
explicit NewJobSamePathDlg(QWidget *parent = nullptr);
|
||||||
|
|
||||||
void setSourceJob(db_id jobId, JobCategory cat, const QTime& start, const QTime& end);
|
void setSourceJob(db_id jobId, JobCategory cat, const QTime &start, const QTime &end);
|
||||||
|
|
||||||
QTime getNewStartTime() const;
|
QTime getNewStartTime() const;
|
||||||
bool shouldCopyRs() const;
|
bool shouldCopyRs() const;
|
||||||
|
@ -50,7 +50,7 @@ private:
|
||||||
QCheckBox *copyRsCheck;
|
QCheckBox *copyRsCheck;
|
||||||
QCheckBox *reversePathCheck;
|
QCheckBox *reversePathCheck;
|
||||||
|
|
||||||
db_id sourceJobId = 0;
|
db_id sourceJobId = 0;
|
||||||
JobCategory sourceJobCat = JobCategory::NCategories;
|
JobCategory sourceJobCat = JobCategory::NCategories;
|
||||||
QTime sourceStart;
|
QTime sourceStart;
|
||||||
QTime sourceEnd;
|
QTime sourceEnd;
|
||||||
|
|
|
@ -29,66 +29,62 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
void writeJobSummary(QXmlStreamWriter &xml, const QString &from, const QString &dep,
|
||||||
void writeJobSummary(QXmlStreamWriter& xml,
|
const QString &to, const QString &arr, int axes)
|
||||||
const QString& from, const QString& dep,
|
|
||||||
const QString& to, const QString& arr,
|
|
||||||
int axes)
|
|
||||||
{
|
{
|
||||||
//Table 'job_summary'
|
// Table 'job_summary'
|
||||||
xml.writeStartElement("table:table");
|
xml.writeStartElement("table:table");
|
||||||
xml.writeAttribute("table:name", "job_summary");
|
xml.writeAttribute("table:name", "job_summary");
|
||||||
xml.writeAttribute("table:style-name", "job_5f_summary");
|
xml.writeAttribute("table:style-name", "job_5f_summary");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //A
|
xml.writeEmptyElement("table:table-column"); // A
|
||||||
xml.writeAttribute("table:style-name", "job_5f_summary.A");
|
xml.writeAttribute("table:style-name", "job_5f_summary.A");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //B
|
xml.writeEmptyElement("table:table-column"); // B
|
||||||
xml.writeAttribute("table:style-name", "job_5f_summary.B");
|
xml.writeAttribute("table:style-name", "job_5f_summary.B");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //C
|
xml.writeEmptyElement("table:table-column"); // C
|
||||||
xml.writeAttribute("table:style-name", "job_5f_summary.C");
|
xml.writeAttribute("table:style-name", "job_5f_summary.C");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //D
|
xml.writeEmptyElement("table:table-column"); // D
|
||||||
xml.writeAttribute("table:style-name", "job_5f_summary.D");
|
xml.writeAttribute("table:style-name", "job_5f_summary.D");
|
||||||
|
|
||||||
//Row
|
// Row
|
||||||
xml.writeStartElement("table:table-row");
|
xml.writeStartElement("table:table-row");
|
||||||
|
|
||||||
//Cells
|
// Cells
|
||||||
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryFrom));
|
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryFrom));
|
||||||
writeCell(xml, "job_5f_summary_cell", "P3", from);
|
writeCell(xml, "job_5f_summary_cell", "P3", from);
|
||||||
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryDep));
|
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryDep));
|
||||||
writeCell(xml, "job_5f_summary_cell", "P3", dep);
|
writeCell(xml, "job_5f_summary_cell", "P3", dep);
|
||||||
|
|
||||||
xml.writeEndElement(); //table-row
|
xml.writeEndElement(); // table-row
|
||||||
|
|
||||||
//Row 2
|
// Row 2
|
||||||
xml.writeStartElement("table:table-row");
|
xml.writeStartElement("table:table-row");
|
||||||
|
|
||||||
//Cells
|
// Cells
|
||||||
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryTo));
|
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryTo));
|
||||||
writeCell(xml, "job_5f_summary_cell", "P3", to);
|
writeCell(xml, "job_5f_summary_cell", "P3", to);
|
||||||
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryArr));
|
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryArr));
|
||||||
writeCell(xml, "job_5f_summary_cell", "P3", arr);
|
writeCell(xml, "job_5f_summary_cell", "P3", arr);
|
||||||
|
|
||||||
xml.writeEndElement(); //table-row
|
xml.writeEndElement(); // table-row
|
||||||
|
|
||||||
//Row 3
|
// Row 3
|
||||||
xml.writeStartElement("table:table-row");
|
xml.writeStartElement("table:table-row");
|
||||||
|
|
||||||
//Cells
|
// Cells
|
||||||
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryAxes));
|
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryAxes));
|
||||||
writeCell(xml, "job_5f_summary_cell", "P3", QString::number(axes));
|
writeCell(xml, "job_5f_summary_cell", "P3", QString::number(axes));
|
||||||
writeCell(xml, "job_5f_summary_cell", "P2", QString());
|
writeCell(xml, "job_5f_summary_cell", "P2", QString());
|
||||||
writeCell(xml, "job_5f_summary_cell", "P3", QString());
|
writeCell(xml, "job_5f_summary_cell", "P3", QString());
|
||||||
|
|
||||||
xml.writeEndElement(); //table-row
|
xml.writeEndElement(); // table-row
|
||||||
|
|
||||||
xml.writeEndElement(); //table:table END
|
xml.writeEndElement(); // table:table END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JobWriter::JobWriter(database &db) :
|
JobWriter::JobWriter(database &db) :
|
||||||
mDb(db),
|
mDb(db),
|
||||||
q_getJobStops(mDb, "SELECT stops.id,"
|
q_getJobStops(mDb, "SELECT stops.id,"
|
||||||
|
@ -128,7 +124,8 @@ JobWriter::JobWriter(database &db) :
|
||||||
"stops.arrival,stops.departure"
|
"stops.arrival,stops.departure"
|
||||||
" FROM stops"
|
" FROM stops"
|
||||||
" JOIN jobs ON jobs.id=stops.job_id"
|
" JOIN jobs ON jobs.id=stops.job_id"
|
||||||
" WHERE stops.station_id=? AND stops.departure>=? AND stops.arrival<=? AND stops.job_id<>?"),
|
" WHERE stops.station_id=? AND stops.departure>=? AND stops.arrival<=? "
|
||||||
|
"AND stops.job_id<>?"),
|
||||||
|
|
||||||
q_getStopCouplings(mDb, "SELECT coupling.rs_id,"
|
q_getStopCouplings(mDb, "SELECT coupling.rs_id,"
|
||||||
"rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
"rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
||||||
|
@ -141,21 +138,21 @@ JobWriter::JobWriter(database &db) :
|
||||||
|
|
||||||
void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
//job_summary columns
|
// job_summary columns
|
||||||
writeColumnStyle(xml, "job_5f_summary.A", "1.60cm");
|
writeColumnStyle(xml, "job_5f_summary.A", "1.60cm");
|
||||||
writeColumnStyle(xml, "job_5f_summary.B", "8.30cm");
|
writeColumnStyle(xml, "job_5f_summary.B", "8.30cm");
|
||||||
writeColumnStyle(xml, "job_5f_summary.C", "2.90cm");
|
writeColumnStyle(xml, "job_5f_summary.C", "2.90cm");
|
||||||
writeColumnStyle(xml, "job_5f_summary.D", "4.20cm");
|
writeColumnStyle(xml, "job_5f_summary.D", "4.20cm");
|
||||||
|
|
||||||
//job_stops columns
|
// job_stops columns
|
||||||
writeColumnStyle(xml, "job_5f_stops.A", "2.60cm"); //Station (IT: Stazione)
|
writeColumnStyle(xml, "job_5f_stops.A", "2.60cm"); // Station (IT: Stazione)
|
||||||
writeColumnStyle(xml, "job_5f_stops.B", "1.60cm"); //Arrival (IT: Arrivo)
|
writeColumnStyle(xml, "job_5f_stops.B", "1.60cm"); // Arrival (IT: Arrivo)
|
||||||
writeColumnStyle(xml, "job_5f_stops.C", "2.10cm"); //Departure (IT: Partenza)
|
writeColumnStyle(xml, "job_5f_stops.C", "2.10cm"); // Departure (IT: Partenza)
|
||||||
writeColumnStyle(xml, "job_5f_stops.D", "1.cm"); //Platorm 'Platf' (IT: Binario 'Bin')
|
writeColumnStyle(xml, "job_5f_stops.D", "1.cm"); // Platorm 'Platf' (IT: Binario 'Bin')
|
||||||
writeColumnStyle(xml, "job_5f_stops.E", "3.00cm"); //Rollingstock (IT: Rotabili)
|
writeColumnStyle(xml, "job_5f_stops.E", "3.00cm"); // Rollingstock (IT: Rotabili)
|
||||||
writeColumnStyle(xml, "job_5f_stops.F", "2.30cm"); //Crossings
|
writeColumnStyle(xml, "job_5f_stops.F", "2.30cm"); // Crossings
|
||||||
writeColumnStyle(xml, "job_5f_stops.G", "2.30cm"); //Passings
|
writeColumnStyle(xml, "job_5f_stops.G", "2.30cm"); // Passings
|
||||||
writeColumnStyle(xml, "job_5f_stops.H", "3.20cm"); //Description (IT: Note)
|
writeColumnStyle(xml, "job_5f_stops.H", "3.20cm"); // Description (IT: Note)
|
||||||
|
|
||||||
/* Style: job_5f_stops.A1
|
/* Style: job_5f_stops.A1
|
||||||
*
|
*
|
||||||
|
@ -181,8 +178,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-right", "none");
|
xml.writeAttribute("fo:border-right", "none");
|
||||||
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_stops.H1
|
/* Style: job_5f_stops.H1
|
||||||
*
|
*
|
||||||
|
@ -206,8 +203,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:padding-bottom", "0.15cm");
|
xml.writeAttribute("fo:padding-bottom", "0.15cm");
|
||||||
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_stops.A2
|
/* Style: job_5f_stops.A2
|
||||||
*
|
*
|
||||||
|
@ -230,8 +227,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-top", "none");
|
xml.writeAttribute("fo:border-top", "none");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_stops.H2
|
/* Style: job_5f_stops.H2
|
||||||
*
|
*
|
||||||
|
@ -254,10 +251,10 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-top", "none");
|
xml.writeAttribute("fo:border-top", "none");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
//job_5f_asset columns
|
// job_5f_asset columns
|
||||||
writeColumnStyle(xml, "job_5f_asset.A", "3.0cm");
|
writeColumnStyle(xml, "job_5f_asset.A", "3.0cm");
|
||||||
writeColumnStyle(xml, "job_5f_asset.B", "14.0cm");
|
writeColumnStyle(xml, "job_5f_asset.B", "14.0cm");
|
||||||
|
|
||||||
|
@ -281,8 +278,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-right", "none");
|
xml.writeAttribute("fo:border-right", "none");
|
||||||
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_asset.B1
|
/* Style: job_5f_asset.B1
|
||||||
*
|
*
|
||||||
|
@ -302,8 +299,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:padding", "0.049cm");
|
xml.writeAttribute("fo:padding", "0.049cm");
|
||||||
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_asset.A2
|
/* Style: job_5f_asset.A2
|
||||||
*
|
*
|
||||||
|
@ -326,8 +323,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-top", "none");
|
xml.writeAttribute("fo:border-top", "none");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_asset.B2
|
/* Style: job_5f_asset.B2
|
||||||
*
|
*
|
||||||
|
@ -350,11 +347,11 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-top", "none");
|
xml.writeAttribute("fo:border-top", "none");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
void JobWriter::writeJobStyles(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
/* Style: job_5f_summary
|
/* Style: job_5f_summary
|
||||||
*
|
*
|
||||||
|
@ -374,8 +371,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeAttribute("style:shadow", "none");
|
xml.writeAttribute("style:shadow", "none");
|
||||||
xml.writeAttribute("table:align", "left");
|
xml.writeAttribute("table:align", "left");
|
||||||
xml.writeAttribute("style:width", "8.0cm");
|
xml.writeAttribute("style:width", "8.0cm");
|
||||||
xml.writeEndElement(); //style:table-properties
|
xml.writeEndElement(); // style:table-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_summary_cell
|
/* Style: job_5f_summary_cell
|
||||||
*
|
*
|
||||||
|
@ -393,8 +390,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeStartElement("style:table-cell-properties");
|
xml.writeStartElement("style:table-cell-properties");
|
||||||
xml.writeAttribute("fo:border", "none");
|
xml.writeAttribute("fo:border", "none");
|
||||||
xml.writeAttribute("fo:padding", "0.097cm");
|
xml.writeAttribute("fo:padding", "0.097cm");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_stops
|
/* Style: job_5f_stops
|
||||||
*
|
*
|
||||||
|
@ -414,19 +411,19 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeAttribute("table:align", "left");
|
xml.writeAttribute("table:align", "left");
|
||||||
xml.writeAttribute("style:width", "16.0cm");
|
xml.writeAttribute("style:width", "16.0cm");
|
||||||
|
|
||||||
xml.writeEndElement(); //style:table-properties
|
xml.writeEndElement(); // style:table-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: job_5f_asset
|
/* Style: job_5f_asset
|
||||||
*
|
*
|
||||||
* Type: table
|
* Type: table
|
||||||
* Display name: job_asset
|
* Display name: job_asset
|
||||||
* Align: left
|
* Align: left
|
||||||
* Width: 16.0cm
|
* Width: 16.0cm
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* - job_stops table: displays job rollingstock asset summary
|
* - job_stops table: displays job rollingstock asset summary
|
||||||
*/
|
*/
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:family", "table");
|
xml.writeAttribute("style:family", "table");
|
||||||
xml.writeAttribute("style:name", "job_5f_asset");
|
xml.writeAttribute("style:name", "job_5f_asset");
|
||||||
|
@ -435,8 +432,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeAttribute("table:align", "left");
|
xml.writeAttribute("table:align", "left");
|
||||||
xml.writeAttribute("style:width", "16.0cm");
|
xml.writeAttribute("style:width", "16.0cm");
|
||||||
|
|
||||||
xml.writeEndElement(); //style:table-properties
|
xml.writeEndElement(); // style:table-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style P2
|
/* Style P2
|
||||||
* type: paragraph
|
* type: paragraph
|
||||||
|
@ -454,14 +451,14 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "start");
|
xml.writeAttribute("fo:text-align", "start");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "16pt");
|
xml.writeAttribute("fo:font-size", "16pt");
|
||||||
xml.writeAttribute("fo:font-weight", "bold");
|
xml.writeAttribute("fo:font-weight", "bold");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
/* Style P3
|
/* Style P3
|
||||||
* type: paragraph
|
* type: paragraph
|
||||||
|
@ -481,13 +478,13 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "start");
|
xml.writeAttribute("fo:text-align", "start");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "16pt");
|
xml.writeAttribute("fo:font-size", "16pt");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
/* Style P5
|
/* Style P5
|
||||||
* type: paragraph
|
* type: paragraph
|
||||||
|
@ -498,7 +495,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
* Like P4 but not bold
|
* Like P4 but not bold
|
||||||
*
|
*
|
||||||
* Usages:
|
* Usages:
|
||||||
* - job_stops: stop cell text for normal stops and transit Rollingstock/Crossings/Passings/Description
|
* - job_stops: stop cell text for normal stops and transit
|
||||||
|
* Rollingstock/Crossings/Passings/Description
|
||||||
*/
|
*/
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:family", "paragraph");
|
xml.writeAttribute("style:family", "paragraph");
|
||||||
|
@ -507,13 +505,13 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "center");
|
xml.writeAttribute("fo:text-align", "center");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "12pt");
|
xml.writeAttribute("fo:font-size", "12pt");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
/* Style P6
|
/* Style P6
|
||||||
* type: paragraph
|
* type: paragraph
|
||||||
|
@ -526,7 +524,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
* (P4 + Italic, not bold)
|
* (P4 + Italic, not bold)
|
||||||
*
|
*
|
||||||
* Usages:
|
* Usages:
|
||||||
* - job_stops: stop cell text for transit stops except for Rollingstock/Crossings/Passings/Description columns which have P5
|
* - job_stops: stop cell text for transit stops except for
|
||||||
|
* Rollingstock/Crossings/Passings/Description columns which have P5
|
||||||
*/
|
*/
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:family", "paragraph");
|
xml.writeAttribute("style:family", "paragraph");
|
||||||
|
@ -535,18 +534,17 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "center");
|
xml.writeAttribute("fo:text-align", "center");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "12pt");
|
xml.writeAttribute("fo:font-size", "12pt");
|
||||||
xml.writeAttribute("fo:font-style", "italic");
|
xml.writeAttribute("fo:font-style", "italic");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
|
// stile interruzione di pagina
|
||||||
//stile interruzione di pagina
|
// TODO: quando useremo 'Page master style' vedere se vanno in conflitto
|
||||||
//TODO: quando useremo 'Page master style' vedere se vanno in conflitto
|
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:family", "paragraph");
|
xml.writeAttribute("style:family", "paragraph");
|
||||||
xml.writeAttribute("style:name", "interruzione");
|
xml.writeAttribute("style:name", "interruzione");
|
||||||
|
@ -554,16 +552,16 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "start");
|
xml.writeAttribute("fo:text-align", "start");
|
||||||
xml.writeAttribute("fo:break-after", "page");
|
xml.writeAttribute("fo:break-after", "page");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "1pt");
|
xml.writeAttribute("fo:font-size", "1pt");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
void JobWriter::writeJob(QXmlStreamWriter &xml, db_id jobId, JobCategory jobCat)
|
||||||
{
|
{
|
||||||
query q_getRSInfo(mDb, "SELECT rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
query q_getRSInfo(mDb, "SELECT rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
||||||
" FROM rs_list"
|
" FROM rs_list"
|
||||||
|
@ -572,33 +570,34 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
|
|
||||||
QList<QPair<QString, QList<db_id>>> stopsRS;
|
QList<QPair<QString, QList<db_id>>> stopsRS;
|
||||||
|
|
||||||
//Title
|
// Title
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "P1");
|
xml.writeAttribute("text:style-name", "P1");
|
||||||
xml.writeCharacters(JobCategoryName::jobNameSpaced(jobId, jobCat));
|
xml.writeCharacters(JobCategoryName::jobNameSpaced(jobId, jobCat));
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
|
||||||
//Vertical space
|
// Vertical space
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "P1");
|
xml.writeAttribute("text:style-name", "P1");
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
|
||||||
db_id firstStopId = 0;
|
db_id firstStopId = 0;
|
||||||
db_id lastStopId = 0;
|
db_id lastStopId = 0;
|
||||||
|
|
||||||
QTime start, end;
|
QTime start, end;
|
||||||
QString fromStation, toStation;
|
QString fromStation, toStation;
|
||||||
int axesCount = 0;
|
int axesCount = 0;
|
||||||
|
|
||||||
//Job summary
|
// Job summary
|
||||||
q_getFirstStop.bind(1, jobId);
|
q_getFirstStop.bind(1, jobId);
|
||||||
if(q_getFirstStop.step() == SQLITE_ROW && q_getFirstStop.getRows().column_type(0) != SQLITE_NULL)
|
if (q_getFirstStop.step() == SQLITE_ROW
|
||||||
|
&& q_getFirstStop.getRows().column_type(0) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
auto r = q_getFirstStop.getRows();
|
auto r = q_getFirstStop.getRows();
|
||||||
|
|
||||||
firstStopId = r.get<db_id>(0);
|
firstStopId = r.get<db_id>(0);
|
||||||
fromStation = r.get<QString>(1);
|
fromStation = r.get<QString>(1);
|
||||||
start = r.get<QTime>(2);
|
start = r.get<QTime>(2);
|
||||||
|
|
||||||
q_initialJobAxes.bind(1, firstStopId);
|
q_initialJobAxes.bind(1, firstStopId);
|
||||||
q_initialJobAxes.step();
|
q_initialJobAxes.step();
|
||||||
|
@ -608,21 +607,19 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
q_getFirstStop.reset();
|
q_getFirstStop.reset();
|
||||||
|
|
||||||
q_getLastStop.bind(1, jobId);
|
q_getLastStop.bind(1, jobId);
|
||||||
if(q_getLastStop.step() == SQLITE_ROW && q_getLastStop.getRows().column_type(0) != SQLITE_NULL)
|
if (q_getLastStop.step() == SQLITE_ROW && q_getLastStop.getRows().column_type(0) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
auto r = q_getLastStop.getRows();
|
auto r = q_getLastStop.getRows();
|
||||||
|
|
||||||
lastStopId = r.get<db_id>(0);
|
lastStopId = r.get<db_id>(0);
|
||||||
toStation = r.get<QString>(1);
|
toStation = r.get<QString>(1);
|
||||||
end = r.get<QTime>(2);
|
end = r.get<QTime>(2);
|
||||||
}
|
}
|
||||||
q_getLastStop.reset();
|
q_getLastStop.reset();
|
||||||
|
|
||||||
if(firstStopId && lastStopId)
|
if (firstStopId && lastStopId)
|
||||||
{
|
{
|
||||||
writeJobSummary(xml,
|
writeJobSummary(xml, fromStation, start.toString("HH:mm"), toStation, end.toString("HH:mm"),
|
||||||
fromStation, start.toString("HH:mm"),
|
|
||||||
toStation, end.toString("HH:mm"),
|
|
||||||
axesCount);
|
axesCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -633,41 +630,41 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
writeJobSummary(xml, err, err, err, err, 0);
|
writeJobSummary(xml, err, err, err, err, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Vertical space
|
// Vertical space
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "P1");
|
xml.writeAttribute("text:style-name", "P1");
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
|
||||||
//Table 'job_stops'
|
// Table 'job_stops'
|
||||||
xml.writeStartElement("table:table");
|
xml.writeStartElement("table:table");
|
||||||
xml.writeAttribute("table:name", "job_stops");
|
xml.writeAttribute("table:name", "job_stops");
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops");
|
xml.writeAttribute("table:style-name", "job_5f_stops");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Station
|
xml.writeEmptyElement("table:table-column"); // Station
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops.A");
|
xml.writeAttribute("table:style-name", "job_5f_stops.A");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Arrival
|
xml.writeEmptyElement("table:table-column"); // Arrival
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops.B");
|
xml.writeAttribute("table:style-name", "job_5f_stops.B");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Departure
|
xml.writeEmptyElement("table:table-column"); // Departure
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops.C");
|
xml.writeAttribute("table:style-name", "job_5f_stops.C");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Platform (Platf)
|
xml.writeEmptyElement("table:table-column"); // Platform (Platf)
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops.D");
|
xml.writeAttribute("table:style-name", "job_5f_stops.D");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Rollingstock
|
xml.writeEmptyElement("table:table-column"); // Rollingstock
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops.E");
|
xml.writeAttribute("table:style-name", "job_5f_stops.E");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Crossings
|
xml.writeEmptyElement("table:table-column"); // Crossings
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops.F");
|
xml.writeAttribute("table:style-name", "job_5f_stops.F");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Passings
|
xml.writeEmptyElement("table:table-column"); // Passings
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops.G");
|
xml.writeAttribute("table:style-name", "job_5f_stops.G");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Description
|
xml.writeEmptyElement("table:table-column"); // Description
|
||||||
xml.writeAttribute("table:style-name", "job_5f_stops.H");
|
xml.writeAttribute("table:style-name", "job_5f_stops.H");
|
||||||
|
|
||||||
//Row 1 (Heading)
|
// Row 1 (Heading)
|
||||||
xml.writeStartElement("table:table-header-rows");
|
xml.writeStartElement("table:table-header-rows");
|
||||||
xml.writeStartElement("table:table-row");
|
xml.writeStartElement("table:table-row");
|
||||||
|
|
||||||
|
@ -679,40 +676,41 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
writeCell(xml, "job_5f_stops.A1", P4_Style, Odt::text(Odt::rollingstock));
|
writeCell(xml, "job_5f_stops.A1", P4_Style, Odt::text(Odt::rollingstock));
|
||||||
writeCell(xml, "job_5f_stops.A1", P4_Style, Odt::text(Odt::jobStopCross));
|
writeCell(xml, "job_5f_stops.A1", P4_Style, Odt::text(Odt::jobStopCross));
|
||||||
writeCell(xml, "job_5f_stops.A1", P4_Style, Odt::text(Odt::jobStopPassings));
|
writeCell(xml, "job_5f_stops.A1", P4_Style, Odt::text(Odt::jobStopPassings));
|
||||||
writeCell(xml, "job_5f_stops.H1", P4_Style, Odt::text(Odt::notes)); //Description
|
writeCell(xml, "job_5f_stops.H1", P4_Style, Odt::text(Odt::notes)); // Description
|
||||||
|
|
||||||
xml.writeEndElement(); //end of row
|
xml.writeEndElement(); // end of row
|
||||||
xml.writeEndElement(); //header section
|
xml.writeEndElement(); // header section
|
||||||
|
|
||||||
QList<db_id> rsAsset;
|
QList<db_id> rsAsset;
|
||||||
|
|
||||||
const QString P5_style = "P5";
|
const QString P5_style = "P5";
|
||||||
|
|
||||||
//Fill stops table
|
// Fill stops table
|
||||||
q_getJobStops.bind(1, jobId);
|
q_getJobStops.bind(1, jobId);
|
||||||
for(auto stop : q_getJobStops)
|
for (auto stop : q_getJobStops)
|
||||||
{
|
{
|
||||||
db_id stopId = stop.get<db_id>(0);
|
db_id stopId = stop.get<db_id>(0);
|
||||||
db_id stationId = stop.get<db_id>(1);
|
db_id stationId = stop.get<db_id>(1);
|
||||||
QString stationName = stop.get<QString>(2);
|
QString stationName = stop.get<QString>(2);
|
||||||
QTime arr = stop.get<QTime>(3);
|
QTime arr = stop.get<QTime>(3);
|
||||||
QTime dep = stop.get<QTime>(4);
|
QTime dep = stop.get<QTime>(4);
|
||||||
const int stopType = stop.get<int>(5);
|
const int stopType = stop.get<int>(5);
|
||||||
QString descr = stop.get<QString>(6);
|
QString descr = stop.get<QString>(6);
|
||||||
|
|
||||||
QString trackName = stop.get<QString>(7);
|
QString trackName = stop.get<QString>(7);
|
||||||
if(trackName.isEmpty())
|
if (trackName.isEmpty())
|
||||||
trackName = stop.get<QString>(8); //Use out gate to get track name
|
trackName = stop.get<QString>(8); // Use out gate to get track name
|
||||||
|
|
||||||
utils::Side entranceSide = utils::Side(stop.get<int>(9));
|
utils::Side entranceSide = utils::Side(stop.get<int>(9));
|
||||||
utils::Side exitSide = utils::Side(stop.get<int>(10));
|
utils::Side exitSide = utils::Side(stop.get<int>(10));
|
||||||
|
|
||||||
if(entranceSide == exitSide && stop.column_type(9) != SQLITE_NULL && stop.column_type(10) != SQLITE_NULL)
|
if (entranceSide == exitSide && stop.column_type(9) != SQLITE_NULL
|
||||||
|
&& stop.column_type(10) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
//Train enters and leaves from same track side, add reversal to description
|
// Train enters and leaves from same track side, add reversal to description
|
||||||
QString descr2 = Odt::text(Odt::jobReverseDirection);
|
QString descr2 = Odt::text(Odt::jobReverseDirection);
|
||||||
if(!descr.isEmpty())
|
if (!descr.isEmpty())
|
||||||
descr2.append('\n'); //Separate from manually set description
|
descr2.append('\n'); // Separate from manually set description
|
||||||
descr2.append(descr);
|
descr2.append(descr);
|
||||||
descr = descr2;
|
descr = descr2;
|
||||||
}
|
}
|
||||||
|
@ -721,58 +719,59 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
|
|
||||||
qDebug() << "(Loop) Job:" << jobId << "Stop:" << stopId;
|
qDebug() << "(Loop) Job:" << jobId << "Stop:" << stopId;
|
||||||
|
|
||||||
xml.writeStartElement("table:table-row"); //start new row
|
xml.writeStartElement("table:table-row"); // start new row
|
||||||
|
|
||||||
const QString styleName = isTransit ? "P6" : P5_style; //If it's transit use italic style
|
const QString styleName = isTransit ? "P6" : P5_style; // If it's transit use italic style
|
||||||
|
|
||||||
//Station
|
// Station
|
||||||
writeCell(xml, "job_5f_stops.A2", styleName, stationName);
|
writeCell(xml, "job_5f_stops.A2", styleName, stationName);
|
||||||
|
|
||||||
//Arrival
|
// Arrival
|
||||||
writeCell(xml, "job_5f_stops.A2", styleName, stopId == firstStopId ? QString() : arr.toString("HH:mm"));
|
writeCell(xml, "job_5f_stops.A2", styleName,
|
||||||
|
stopId == firstStopId ? QString() : arr.toString("HH:mm"));
|
||||||
|
|
||||||
//Departure
|
// Departure
|
||||||
//If it's transit then and arrival is equal to departure (should be always but if is different show both to warn user about the error)
|
// If it's transit then and arrival is equal to departure (should be always but if is
|
||||||
//then show only arrival
|
// different show both to warn user about the error) then show only arrival
|
||||||
writeCell(xml, "job_5f_stops.A2", styleName, (stopId == lastStopId || (isTransit && arr == dep)) ? QString() : dep.toString("HH:mm"));
|
writeCell(xml, "job_5f_stops.A2", styleName,
|
||||||
|
(stopId == lastStopId || (isTransit && arr == dep)) ? QString()
|
||||||
|
: dep.toString("HH:mm"));
|
||||||
|
|
||||||
//Platform
|
// Platform
|
||||||
writeCell(xml, "job_5f_stops.A2", styleName, trackName);
|
writeCell(xml, "job_5f_stops.A2", styleName, trackName);
|
||||||
|
|
||||||
//Rollingstock
|
// Rollingstock
|
||||||
sqlite3_stmt *stmt = q_getStopCouplings.stmt();
|
sqlite3_stmt *stmt = q_getStopCouplings.stmt();
|
||||||
writeCellListStart(xml, "job_5f_stops.A2", P5_style);
|
writeCellListStart(xml, "job_5f_stops.A2", P5_style);
|
||||||
|
|
||||||
//Coupled rollingstock
|
// Coupled rollingstock
|
||||||
bool firstCoupRow = true;
|
bool firstCoupRow = true;
|
||||||
q_getStopCouplings.bind(1, stopId);
|
q_getStopCouplings.bind(1, stopId);
|
||||||
q_getStopCouplings.bind(2, int(RsOp::Coupled));
|
q_getStopCouplings.bind(2, int(RsOp::Coupled));
|
||||||
for(auto coup : q_getStopCouplings)
|
for (auto coup : q_getStopCouplings)
|
||||||
{
|
{
|
||||||
db_id rsId = coup.get<db_id>(0);
|
db_id rsId = coup.get<db_id>(0);
|
||||||
rsAsset.append(rsId);
|
rsAsset.append(rsId);
|
||||||
|
|
||||||
int number = coup.get<int>(1);
|
int number = coup.get<int>(1);
|
||||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 3));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 3));
|
||||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||||
|
|
||||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||||
number,
|
modelSuffix, modelSuffixLen, type);
|
||||||
modelSuffix, modelSuffixLen,
|
|
||||||
type);
|
|
||||||
|
|
||||||
if(firstCoupRow)
|
if (firstCoupRow)
|
||||||
{
|
{
|
||||||
firstCoupRow = false;
|
firstCoupRow = false;
|
||||||
//Use bold font
|
// Use bold font
|
||||||
xml.writeStartElement("text:span");
|
xml.writeStartElement("text:span");
|
||||||
xml.writeAttribute("text:style-name", "T1");
|
xml.writeAttribute("text:style-name", "T1");
|
||||||
xml.writeCharacters(Odt::text(Odt::CoupledAbbr));
|
xml.writeCharacters(Odt::text(Odt::CoupledAbbr));
|
||||||
xml.writeEndElement(); //test:span
|
xml.writeEndElement(); // test:span
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
@ -780,38 +779,36 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
}
|
}
|
||||||
q_getStopCouplings.reset();
|
q_getStopCouplings.reset();
|
||||||
|
|
||||||
//Unoupled rollingstock
|
// Unoupled rollingstock
|
||||||
bool firstUncoupRow = true;
|
bool firstUncoupRow = true;
|
||||||
q_getStopCouplings.bind(1, stopId);
|
q_getStopCouplings.bind(1, stopId);
|
||||||
q_getStopCouplings.bind(2, int(RsOp::Uncoupled));
|
q_getStopCouplings.bind(2, int(RsOp::Uncoupled));
|
||||||
for(auto coup : q_getStopCouplings)
|
for (auto coup : q_getStopCouplings)
|
||||||
{
|
{
|
||||||
db_id rsId = coup.get<db_id>(0);
|
db_id rsId = coup.get<db_id>(0);
|
||||||
rsAsset.removeAll(rsId);
|
rsAsset.removeAll(rsId);
|
||||||
|
|
||||||
int number = coup.get<int>(1);
|
int number = coup.get<int>(1);
|
||||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 3));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 3));
|
||||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||||
|
|
||||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||||
number,
|
modelSuffix, modelSuffixLen, type);
|
||||||
modelSuffix, modelSuffixLen,
|
|
||||||
type);
|
|
||||||
|
|
||||||
if(firstUncoupRow)
|
if (firstUncoupRow)
|
||||||
{
|
{
|
||||||
if(!firstCoupRow) //Not first row, there were coupled rs
|
if (!firstCoupRow) // Not first row, there were coupled rs
|
||||||
xml.writeEmptyElement("text:line-break"); //Separate from coupled
|
xml.writeEmptyElement("text:line-break"); // Separate from coupled
|
||||||
firstUncoupRow = false;
|
firstUncoupRow = false;
|
||||||
//Use bold font
|
// Use bold font
|
||||||
xml.writeStartElement("text:span");
|
xml.writeStartElement("text:span");
|
||||||
xml.writeAttribute("text:style-name", "T1");
|
xml.writeAttribute("text:style-name", "T1");
|
||||||
xml.writeCharacters(Odt::text(Odt::UncoupledAbbr));
|
xml.writeCharacters(Odt::text(Odt::UncoupledAbbr));
|
||||||
xml.writeEndElement(); //test:span
|
xml.writeEndElement(); // test:span
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
@ -822,7 +819,7 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
|
|
||||||
stopsRS.append({stationName, rsAsset});
|
stopsRS.append({stationName, rsAsset});
|
||||||
|
|
||||||
//Crossings / Passings
|
// Crossings / Passings
|
||||||
|
|
||||||
JobStopDirectionHelper dirHelper(mDb);
|
JobStopDirectionHelper dirHelper(mDb);
|
||||||
|
|
||||||
|
@ -835,25 +832,25 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
q_selectPassings.bind(3, dep);
|
q_selectPassings.bind(3, dep);
|
||||||
q_selectPassings.bind(4, jobId);
|
q_selectPassings.bind(4, jobId);
|
||||||
|
|
||||||
//Incroci
|
// Incroci
|
||||||
firstCoupRow = true;
|
firstCoupRow = true;
|
||||||
writeCellListStart(xml, "job_5f_stops.A2", P5_style);
|
writeCellListStart(xml, "job_5f_stops.A2", P5_style);
|
||||||
for(auto pass : q_selectPassings)
|
for (auto pass : q_selectPassings)
|
||||||
{
|
{
|
||||||
db_id otherStopId = pass.get<db_id>(0);
|
db_id otherStopId = pass.get<db_id>(0);
|
||||||
db_id otherJobId = pass.get<db_id>(1);
|
db_id otherJobId = pass.get<db_id>(1);
|
||||||
JobCategory otherJobCat = JobCategory(pass.get<int>(2));
|
JobCategory otherJobCat = JobCategory(pass.get<int>(2));
|
||||||
|
|
||||||
//QTime otherArr = pass.get<QTime>(3);
|
// QTime otherArr = pass.get<QTime>(3);
|
||||||
//QTime otherDep = pass.get<QTime>(4);
|
// QTime otherDep = pass.get<QTime>(4);
|
||||||
|
|
||||||
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
||||||
|
|
||||||
if(myDir == otherDir)
|
if (myDir == otherDir)
|
||||||
passings.append({otherJobId, otherJobCat});
|
passings.append({otherJobId, otherJobCat});
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(firstCoupRow)
|
if (firstCoupRow)
|
||||||
firstCoupRow = false;
|
firstCoupRow = false;
|
||||||
else
|
else
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
@ -863,12 +860,12 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
q_selectPassings.reset();
|
q_selectPassings.reset();
|
||||||
writeCellListEnd(xml);
|
writeCellListEnd(xml);
|
||||||
|
|
||||||
//Passings
|
// Passings
|
||||||
firstCoupRow = true;
|
firstCoupRow = true;
|
||||||
writeCellListStart(xml, "job_5f_stops.A2", P5_style);
|
writeCellListStart(xml, "job_5f_stops.A2", P5_style);
|
||||||
for(auto entry : passings)
|
for (auto entry : passings)
|
||||||
{
|
{
|
||||||
if(firstCoupRow)
|
if (firstCoupRow)
|
||||||
firstCoupRow = false;
|
firstCoupRow = false;
|
||||||
else
|
else
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
@ -876,107 +873,105 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
||||||
}
|
}
|
||||||
writeCellListEnd(xml);
|
writeCellListEnd(xml);
|
||||||
|
|
||||||
//Description
|
// Description
|
||||||
writeCellListStart(xml, "job_5f_stops.H2", P5_style);
|
writeCellListStart(xml, "job_5f_stops.H2", P5_style);
|
||||||
if(!descr.isEmpty())
|
if (!descr.isEmpty())
|
||||||
{
|
{
|
||||||
//Split in lines
|
// Split in lines
|
||||||
int lastIdx = 0;
|
int lastIdx = 0;
|
||||||
while(true)
|
while (true)
|
||||||
{
|
{
|
||||||
int idx = descr.indexOf('\n', lastIdx);
|
int idx = descr.indexOf('\n', lastIdx);
|
||||||
QString line = descr.mid(lastIdx, idx == -1 ? idx : idx - lastIdx);
|
QString line = descr.mid(lastIdx, idx == -1 ? idx : idx - lastIdx);
|
||||||
xml.writeCharacters(line.simplified());
|
xml.writeCharacters(line.simplified());
|
||||||
if(idx < 0)
|
if (idx < 0)
|
||||||
break; //Last line
|
break; // Last line
|
||||||
lastIdx = idx + 1;
|
lastIdx = idx + 1;
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeCellListEnd(xml);
|
writeCellListEnd(xml);
|
||||||
|
|
||||||
xml.writeEndElement(); //end of row
|
xml.writeEndElement(); // end of row
|
||||||
}
|
}
|
||||||
q_getJobStops.reset();
|
q_getJobStops.reset();
|
||||||
|
|
||||||
xml.writeEndElement(); //table:table END
|
xml.writeEndElement(); // table:table END
|
||||||
|
|
||||||
//text:p as separator
|
// text:p as separator
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "P1");
|
xml.writeAttribute("text:style-name", "P1");
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
|
||||||
//Table 'job_asset'
|
// Table 'job_asset'
|
||||||
xml.writeStartElement("table:table");
|
xml.writeStartElement("table:table");
|
||||||
xml.writeAttribute("table:name", "job_asset");
|
xml.writeAttribute("table:name", "job_asset");
|
||||||
xml.writeAttribute("table:style-name", "job_5f_asset");
|
xml.writeAttribute("table:style-name", "job_5f_asset");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Stazione
|
xml.writeEmptyElement("table:table-column"); // Stazione
|
||||||
xml.writeAttribute("table:style-name", "job_5f_asset.A");
|
xml.writeAttribute("table:style-name", "job_5f_asset.A");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Assetto
|
xml.writeEmptyElement("table:table-column"); // Assetto
|
||||||
xml.writeAttribute("table:style-name", "job_5f_asset.B");
|
xml.writeAttribute("table:style-name", "job_5f_asset.B");
|
||||||
|
|
||||||
//Duplicate second-last asset to last stop because last stop would be always empty
|
// Duplicate second-last asset to last stop because last stop would be always empty
|
||||||
if(stopsRS.size() >= 2)
|
if (stopsRS.size() >= 2)
|
||||||
{
|
{
|
||||||
int i = stopsRS.size() - 2; //Get second-last (IT: penultima fermata)
|
int i = stopsRS.size() - 2; // Get second-last (IT: penultima fermata)
|
||||||
stopsRS[i + 1].second = stopsRS[i].second;
|
stopsRS[i + 1].second = stopsRS[i].second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Error!
|
// Error!
|
||||||
qWarning() << __FUNCTION__ << "At least 2 stops required!";
|
qWarning() << __FUNCTION__ << "At least 2 stops required!";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool firstRow = true;
|
bool firstRow = true;
|
||||||
for(auto &s : qAsConst(stopsRS))
|
for (auto &s : qAsConst(stopsRS))
|
||||||
{
|
{
|
||||||
xml.writeStartElement("table:table-row"); //start new row
|
xml.writeStartElement("table:table-row"); // start new row
|
||||||
|
|
||||||
writeCell(xml, firstRow ? "job_5f_asset.A1" : "job_5f_asset.A2", P5_style, s.first);
|
writeCell(xml, firstRow ? "job_5f_asset.A1" : "job_5f_asset.A2", P5_style, s.first);
|
||||||
|
|
||||||
writeCellListStart(xml, firstRow ? "job_5f_asset.B1" : "job_5f_asset.B2", P5_style);
|
writeCellListStart(xml, firstRow ? "job_5f_asset.B1" : "job_5f_asset.B2", P5_style);
|
||||||
for(int i = 0; i < s.second.size(); i++)
|
for (int i = 0; i < s.second.size(); i++)
|
||||||
{
|
{
|
||||||
q_getRSInfo.reset();
|
q_getRSInfo.reset();
|
||||||
q_getRSInfo.bind(1, s.second.at(i));
|
q_getRSInfo.bind(1, s.second.at(i));
|
||||||
int ret = q_getRSInfo.step();
|
int ret = q_getRSInfo.step();
|
||||||
if(ret != SQLITE_ROW)
|
if (ret != SQLITE_ROW)
|
||||||
{
|
{
|
||||||
//Error: RS does not exist!
|
// Error: RS does not exist!
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_stmt *stmt = q_getRSInfo.stmt();
|
sqlite3_stmt *stmt = q_getRSInfo.stmt();
|
||||||
int number = sqlite3_column_int(stmt, 0);
|
int number = sqlite3_column_int(stmt, 0);
|
||||||
int modelNameLen = sqlite3_column_bytes(stmt, 1);
|
int modelNameLen = sqlite3_column_bytes(stmt, 1);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 1));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 1));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 2);
|
int modelSuffixLen = sqlite3_column_bytes(stmt, 2);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||||
RsType type = RsType(sqlite3_column_int(stmt, 3));
|
RsType type = RsType(sqlite3_column_int(stmt, 3));
|
||||||
|
|
||||||
const QString name = rs_utils::formatNameRef(modelName, modelNameLen,
|
const QString name = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||||
number,
|
modelSuffix, modelSuffixLen, type);
|
||||||
modelSuffix, modelSuffixLen,
|
|
||||||
type);
|
|
||||||
|
|
||||||
xml.writeCharacters(name);
|
xml.writeCharacters(name);
|
||||||
if(i < s.second.size() - 1)
|
if (i < s.second.size() - 1)
|
||||||
xml.writeCharacters(" + ");
|
xml.writeCharacters(" + ");
|
||||||
}
|
}
|
||||||
writeCellListEnd(xml);
|
writeCellListEnd(xml);
|
||||||
|
|
||||||
xml.writeEndElement(); //end of row
|
xml.writeEndElement(); // end of row
|
||||||
|
|
||||||
if(firstRow)
|
if (firstRow)
|
||||||
firstRow = false;
|
firstRow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
|
||||||
//Interruzione pagina TODO: see style 'interruzione'
|
// Interruzione pagina TODO: see style 'interruzione'
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "interruzione");
|
xml.writeAttribute("text:style-name", "interruzione");
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
|
|
@ -30,9 +30,9 @@ class QXmlStreamWriter;
|
||||||
class JobWriter
|
class JobWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
JobWriter(database& db);
|
JobWriter(database &db);
|
||||||
|
|
||||||
static void writeJobAutomaticStyles(QXmlStreamWriter& xml);
|
static void writeJobAutomaticStyles(QXmlStreamWriter &xml);
|
||||||
static void writeJobStyles(QXmlStreamWriter &xml);
|
static void writeJobStyles(QXmlStreamWriter &xml);
|
||||||
|
|
||||||
void writeJob(QXmlStreamWriter &xml, db_id jobId, JobCategory jobCat);
|
void writeJob(QXmlStreamWriter &xml, db_id jobId, JobCategory jobCat);
|
||||||
|
|
|
@ -25,54 +25,58 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "info.h" //Fot App constants
|
#include "info.h" //Fot App constants
|
||||||
#include "app/session.h" //For settings
|
#include "app/session.h" //For settings
|
||||||
#include "db_metadata/metadatamanager.h"
|
#include "db_metadata/metadatamanager.h"
|
||||||
|
|
||||||
#include "odtutils.h"
|
#include "odtutils.h"
|
||||||
|
|
||||||
//content.xml
|
// content.xml
|
||||||
static constexpr char contentFileStr[] = "content.xml";
|
static constexpr char contentFileStr[] = "content.xml";
|
||||||
static constexpr QLatin1String contentFileName = QLatin1String(contentFileStr, sizeof (contentFileStr) - 1);
|
static constexpr QLatin1String contentFileName =
|
||||||
|
QLatin1String(contentFileStr, sizeof(contentFileStr) - 1);
|
||||||
|
|
||||||
//styles.xml
|
// styles.xml
|
||||||
static constexpr char stylesFileStr[] = "styles.xml";
|
static constexpr char stylesFileStr[] = "styles.xml";
|
||||||
static constexpr QLatin1String stylesFileName = QLatin1String(stylesFileStr, sizeof (stylesFileStr) - 1);
|
static constexpr QLatin1String stylesFileName =
|
||||||
|
QLatin1String(stylesFileStr, sizeof(stylesFileStr) - 1);
|
||||||
|
|
||||||
//meta.xml
|
// meta.xml
|
||||||
static constexpr char metaFileStr[] = "meta.xml";
|
static constexpr char metaFileStr[] = "meta.xml";
|
||||||
static constexpr QLatin1String metaFileName = QLatin1String(metaFileStr, sizeof (metaFileStr) - 1);
|
static constexpr QLatin1String metaFileName = QLatin1String(metaFileStr, sizeof(metaFileStr) - 1);
|
||||||
|
|
||||||
//META-INF/manifest.xml
|
// META-INF/manifest.xml
|
||||||
static constexpr char manifestFileNameStr[] = "manifest.xml";
|
static constexpr char manifestFileNameStr[] = "manifest.xml";
|
||||||
static constexpr QLatin1String manifestFileName = QLatin1String(manifestFileNameStr, sizeof (manifestFileNameStr) - 1);
|
static constexpr QLatin1String manifestFileName =
|
||||||
|
QLatin1String(manifestFileNameStr, sizeof(manifestFileNameStr) - 1);
|
||||||
static constexpr char metaInfPathStr[] = "/META-INF";
|
static constexpr char metaInfPathStr[] = "/META-INF";
|
||||||
static constexpr QLatin1String metaInfDirPath = QLatin1String(metaInfPathStr, sizeof (metaInfPathStr) - 1);
|
static constexpr QLatin1String metaInfDirPath =
|
||||||
|
QLatin1String(metaInfPathStr, sizeof(metaInfPathStr) - 1);
|
||||||
static constexpr char manifestFilePathStr[] = "META-INF/manifest.xml";
|
static constexpr char manifestFilePathStr[] = "META-INF/manifest.xml";
|
||||||
static constexpr QLatin1String manifestFilePath = QLatin1String(manifestFilePathStr, sizeof (manifestFilePathStr) - 1);
|
static constexpr QLatin1String manifestFilePath =
|
||||||
|
QLatin1String(manifestFilePathStr, sizeof(manifestFilePathStr) - 1);
|
||||||
|
|
||||||
OdtDocument::OdtDocument()
|
OdtDocument::OdtDocument()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OdtDocument::initDocument()
|
bool OdtDocument::initDocument()
|
||||||
{
|
{
|
||||||
if(!dir.isValid())
|
if (!dir.isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
content.setFileName(dir.filePath(contentFileName));
|
content.setFileName(dir.filePath(contentFileName));
|
||||||
if(!content.open(QFile::WriteOnly | QFile::Truncate))
|
if (!content.open(QFile::WriteOnly | QFile::Truncate))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
styles.setFileName(dir.filePath(stylesFileName));
|
styles.setFileName(dir.filePath(stylesFileName));
|
||||||
if(!styles.open(QFile::WriteOnly | QFile::Truncate))
|
if (!styles.open(QFile::WriteOnly | QFile::Truncate))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
contentXml.setDevice(&content);
|
contentXml.setDevice(&content);
|
||||||
stylesXml.setDevice(&styles);
|
stylesXml.setDevice(&styles);
|
||||||
|
|
||||||
//Init content.xml
|
// Init content.xml
|
||||||
writeStartDoc(contentXml);
|
writeStartDoc(contentXml);
|
||||||
contentXml.writeStartElement("office:document-content");
|
contentXml.writeStartElement("office:document-content");
|
||||||
contentXml.writeNamespace("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "office");
|
contentXml.writeNamespace("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "office");
|
||||||
|
@ -85,7 +89,7 @@ bool OdtDocument::initDocument()
|
||||||
contentXml.writeNamespace("http://www.w3.org/1999/xlink", "xlink");
|
contentXml.writeNamespace("http://www.w3.org/1999/xlink", "xlink");
|
||||||
contentXml.writeAttribute("office:version", "1.2");
|
contentXml.writeAttribute("office:version", "1.2");
|
||||||
|
|
||||||
//Init styles.xml
|
// Init styles.xml
|
||||||
writeStartDoc(stylesXml);
|
writeStartDoc(stylesXml);
|
||||||
stylesXml.writeStartElement("office:document-styles");
|
stylesXml.writeStartElement("office:document-styles");
|
||||||
stylesXml.writeNamespace("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "office");
|
stylesXml.writeNamespace("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "office");
|
||||||
|
@ -100,31 +104,32 @@ bool OdtDocument::initDocument()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OdtDocument::startBody() //TODO: start body manually, remove this function
|
void OdtDocument::startBody() // TODO: start body manually, remove this function
|
||||||
{
|
{
|
||||||
contentXml.writeEndElement(); //office:automatic-styles
|
contentXml.writeEndElement(); // office:automatic-styles
|
||||||
|
|
||||||
contentXml.writeStartElement("office:body");
|
contentXml.writeStartElement("office:body");
|
||||||
contentXml.writeStartElement("office:text");
|
contentXml.writeStartElement("office:text");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OdtDocument::saveTo(const QString& fileName)
|
bool OdtDocument::saveTo(const QString &fileName)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
zip_t *zipper = zip_open(fileName.toUtf8(), ZIP_CREATE | ZIP_TRUNCATE, &err);
|
zip_t *zipper = zip_open(fileName.toUtf8(), ZIP_CREATE | ZIP_TRUNCATE, &err);
|
||||||
|
|
||||||
if (zipper == nullptr)
|
if (zipper == nullptr)
|
||||||
{
|
{
|
||||||
zip_error_t ziperror;
|
zip_error_t ziperror;
|
||||||
zip_error_init_with_code(&ziperror, err);
|
zip_error_init_with_code(&ziperror, err);
|
||||||
qDebug() << "Failed to open output file" << fileName << "Err:" << zip_error_strerror(&ziperror);
|
qDebug() << "Failed to open output file" << fileName
|
||||||
|
<< "Err:" << zip_error_strerror(&ziperror);
|
||||||
zip_error_fini(&ziperror);
|
zip_error_fini(&ziperror);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add mimetype file NOTE: must be the first file in archive
|
// Add mimetype file NOTE: must be the first file in archive
|
||||||
const char mimetype[] = "application/vnd.oasis.opendocument.text";
|
const char mimetype[] = "application/vnd.oasis.opendocument.text";
|
||||||
zip_source_t *source = zip_source_buffer(zipper, mimetype, sizeof (mimetype) - 1, 0);
|
zip_source_t *source = zip_source_buffer(zipper, mimetype, sizeof(mimetype) - 1, 0);
|
||||||
if (source == nullptr)
|
if (source == nullptr)
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
|
@ -136,10 +141,10 @@ bool OdtDocument::saveTo(const QString& fileName)
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add META-INF/manifest.xml
|
// Add META-INF/manifest.xml
|
||||||
QString fileToCompress = dir.filePath(manifestFilePath);
|
QString fileToCompress = dir.filePath(manifestFilePath);
|
||||||
|
|
||||||
source = zip_source_file(zipper, fileToCompress.toUtf8(), 0, 0);
|
source = zip_source_file(zipper, fileToCompress.toUtf8(), 0, 0);
|
||||||
if (source == nullptr)
|
if (source == nullptr)
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
|
@ -151,10 +156,10 @@ bool OdtDocument::saveTo(const QString& fileName)
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add styles.xml
|
// Add styles.xml
|
||||||
fileToCompress = dir.filePath(stylesFileName);
|
fileToCompress = dir.filePath(stylesFileName);
|
||||||
|
|
||||||
source = zip_source_file(zipper, fileToCompress.toUtf8(), 0, 0);
|
source = zip_source_file(zipper, fileToCompress.toUtf8(), 0, 0);
|
||||||
if (source == nullptr)
|
if (source == nullptr)
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
|
@ -166,10 +171,10 @@ bool OdtDocument::saveTo(const QString& fileName)
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add content.xml
|
// Add content.xml
|
||||||
fileToCompress = dir.filePath(contentFileName);
|
fileToCompress = dir.filePath(contentFileName);
|
||||||
|
|
||||||
source = zip_source_file(zipper, fileToCompress.toUtf8(), 0, 0);
|
source = zip_source_file(zipper, fileToCompress.toUtf8(), 0, 0);
|
||||||
if (source == nullptr)
|
if (source == nullptr)
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
|
@ -181,10 +186,10 @@ bool OdtDocument::saveTo(const QString& fileName)
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add meta.xml
|
// Add meta.xml
|
||||||
fileToCompress = dir.filePath(metaFileName);
|
fileToCompress = dir.filePath(metaFileName);
|
||||||
|
|
||||||
source = zip_source_file(zipper, fileToCompress.toUtf8(), 0, 0);
|
source = zip_source_file(zipper, fileToCompress.toUtf8(), 0, 0);
|
||||||
if (source == nullptr)
|
if (source == nullptr)
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
|
@ -196,10 +201,10 @@ bool OdtDocument::saveTo(const QString& fileName)
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add possible images
|
// Add possible images
|
||||||
QString imgBasePath = dir.filePath("Pictures") + QLatin1String("/%1");
|
QString imgBasePath = dir.filePath("Pictures") + QLatin1String("/%1");
|
||||||
QString imgNewBasePath = QLatin1String("Pictures/%1");
|
QString imgNewBasePath = QLatin1String("Pictures/%1");
|
||||||
for(const auto& img : qAsConst(imageList))
|
for (const auto &img : qAsConst(imageList))
|
||||||
{
|
{
|
||||||
source = zip_source_file(zipper, imgBasePath.arg(img.first).toUtf8(), 0, 0);
|
source = zip_source_file(zipper, imgBasePath.arg(img.first).toUtf8(), 0, 0);
|
||||||
if (source == nullptr)
|
if (source == nullptr)
|
||||||
|
@ -207,14 +212,15 @@ bool OdtDocument::saveTo(const QString& fileName)
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zip_file_add(zipper, imgNewBasePath.arg(img.first).toUtf8(), source, ZIP_FL_ENC_UTF_8) < 0)
|
if (zip_file_add(zipper, imgNewBasePath.arg(img.first).toUtf8(), source, ZIP_FL_ENC_UTF_8)
|
||||||
|
< 0)
|
||||||
{
|
{
|
||||||
zip_source_free(source);
|
zip_source_free(source);
|
||||||
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to add file to zip:" << zip_strerror(zipper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(zip_close(zipper) != 0)
|
if (zip_close(zipper) != 0)
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to close zip:" << zip_strerror(zipper);
|
qDebug() << "Failed to close zip:" << zip_strerror(zipper);
|
||||||
}
|
}
|
||||||
|
@ -236,11 +242,11 @@ void OdtDocument::endDocument()
|
||||||
|
|
||||||
QString OdtDocument::addImage(const QString &name, const QString &mediaType)
|
QString OdtDocument::addImage(const QString &name, const QString &mediaType)
|
||||||
{
|
{
|
||||||
if(imageList.isEmpty())
|
if (imageList.isEmpty())
|
||||||
{
|
{
|
||||||
//First image added, create Pictures folder
|
// First image added, create Pictures folder
|
||||||
QDir pictures(dir.path());
|
QDir pictures(dir.path());
|
||||||
if(!pictures.mkdir("Pictures"))
|
if (!pictures.mkdir("Pictures"))
|
||||||
qWarning() << "OdtDocument: cannot create Pictures folder";
|
qWarning() << "OdtDocument: cannot create Pictures folder";
|
||||||
}
|
}
|
||||||
imageList.append({name, mediaType});
|
imageList.append({name, mediaType});
|
||||||
|
@ -251,12 +257,12 @@ void OdtDocument::writeStartDoc(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
xml.setAutoFormatting(true);
|
xml.setAutoFormatting(true);
|
||||||
xml.setAutoFormattingIndent(-1);
|
xml.setAutoFormattingIndent(-1);
|
||||||
//xml.writeStartDocument(QStringLiteral("1.0"), true);
|
// xml.writeStartDocument(QStringLiteral("1.0"), true);
|
||||||
xml.writeStartDocument(QStringLiteral("1.0"));
|
xml.writeStartDocument(QStringLiteral("1.0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OdtDocument::writeFileEntry(QXmlStreamWriter& xml,
|
void OdtDocument::writeFileEntry(QXmlStreamWriter &xml, const QString &fullPath,
|
||||||
const QString& fullPath, const QString& mediaType)
|
const QString &mediaType)
|
||||||
{
|
{
|
||||||
xml.writeStartElement("manifest:file-entry");
|
xml.writeStartElement("manifest:file-entry");
|
||||||
xml.writeAttribute("manifest:full-path", fullPath);
|
xml.writeAttribute("manifest:full-path", fullPath);
|
||||||
|
@ -264,12 +270,12 @@ void OdtDocument::writeFileEntry(QXmlStreamWriter& xml,
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OdtDocument::saveManifest(const QString& path)
|
void OdtDocument::saveManifest(const QString &path)
|
||||||
{
|
{
|
||||||
const QString xmlMime = QLatin1String("text/xml");
|
const QString xmlMime = QLatin1String("text/xml");
|
||||||
|
|
||||||
QDir manifestDir(path + metaInfDirPath);
|
QDir manifestDir(path + metaInfDirPath);
|
||||||
if(!manifestDir.exists())
|
if (!manifestDir.exists())
|
||||||
manifestDir.mkpath(".");
|
manifestDir.mkpath(".");
|
||||||
|
|
||||||
QFile manifest(manifestDir.filePath(manifestFileName));
|
QFile manifest(manifestDir.filePath(manifestFileName));
|
||||||
|
@ -281,30 +287,30 @@ void OdtDocument::saveManifest(const QString& path)
|
||||||
xml.writeNamespace("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", "manifest");
|
xml.writeNamespace("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", "manifest");
|
||||||
xml.writeAttribute("manifest:version", "1.2");
|
xml.writeAttribute("manifest:version", "1.2");
|
||||||
|
|
||||||
//Root
|
// Root
|
||||||
writeFileEntry(xml, "/", "application/vnd.oasis.opendocument.text");
|
writeFileEntry(xml, "/", "application/vnd.oasis.opendocument.text");
|
||||||
|
|
||||||
//styles.xml
|
// styles.xml
|
||||||
writeFileEntry(xml, stylesFileName, xmlMime);
|
writeFileEntry(xml, stylesFileName, xmlMime);
|
||||||
|
|
||||||
//content.xml
|
// content.xml
|
||||||
writeFileEntry(xml, contentFileName, xmlMime);
|
writeFileEntry(xml, contentFileName, xmlMime);
|
||||||
|
|
||||||
//meta.xml
|
// meta.xml
|
||||||
writeFileEntry(xml, metaFileName, xmlMime);
|
writeFileEntry(xml, metaFileName, xmlMime);
|
||||||
|
|
||||||
//Add possible images
|
// Add possible images
|
||||||
for(const auto& img : qAsConst(imageList))
|
for (const auto &img : qAsConst(imageList))
|
||||||
{
|
{
|
||||||
writeFileEntry(xml, "Pictures/" + img.first, img.second);
|
writeFileEntry(xml, "Pictures/" + img.first, img.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeEndElement(); //manifest:manifest
|
xml.writeEndElement(); // manifest:manifest
|
||||||
|
|
||||||
xml.writeEndDocument();
|
xml.writeEndDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OdtDocument::saveMeta(const QString& path)
|
void OdtDocument::saveMeta(const QString &path)
|
||||||
{
|
{
|
||||||
QDir metaDir(path);
|
QDir metaDir(path);
|
||||||
|
|
||||||
|
@ -323,122 +329,122 @@ void OdtDocument::saveMeta(const QString& path)
|
||||||
|
|
||||||
xml.writeStartElement("office:meta");
|
xml.writeStartElement("office:meta");
|
||||||
|
|
||||||
MetaDataManager *meta = Session->getMetaDataManager();
|
MetaDataManager *meta = Session->getMetaDataManager();
|
||||||
const bool storeLocationAndDate = AppSettings.getSheetStoreLocationDateInMeta();
|
const bool storeLocationAndDate = AppSettings.getSheetStoreLocationDateInMeta();
|
||||||
|
|
||||||
//Title
|
// Title
|
||||||
if(!documentTitle.isEmpty())
|
if (!documentTitle.isEmpty())
|
||||||
{
|
{
|
||||||
xml.writeStartElement("dc:title");
|
xml.writeStartElement("dc:title");
|
||||||
xml.writeCharacters(documentTitle);
|
xml.writeCharacters(documentTitle);
|
||||||
xml.writeEndElement(); //dc:title
|
xml.writeEndElement(); // dc:title
|
||||||
}
|
}
|
||||||
|
|
||||||
//Subject
|
// Subject
|
||||||
xml.writeStartElement("dc:subject");
|
xml.writeStartElement("dc:subject");
|
||||||
xml.writeCharacters(AppDisplayName);
|
xml.writeCharacters(AppDisplayName);
|
||||||
xml.writeCharacters(" Session Meeting"); //Do not translate, so it's standard for everyone
|
xml.writeCharacters(" Session Meeting"); // Do not translate, so it's standard for everyone
|
||||||
xml.writeEndElement(); //dc:subject
|
xml.writeEndElement(); // dc:subject
|
||||||
|
|
||||||
//Description
|
// Description
|
||||||
QString meetingLocation;
|
QString meetingLocation;
|
||||||
if(storeLocationAndDate)
|
if (storeLocationAndDate)
|
||||||
{
|
{
|
||||||
meta->getString(meetingLocation, MetaDataKey::MeetingLocation);
|
meta->getString(meetingLocation, MetaDataKey::MeetingLocation);
|
||||||
|
|
||||||
QDate start, end;
|
QDate start, end;
|
||||||
qint64 tmp = 0;
|
qint64 tmp = 0;
|
||||||
if(meta->getInt64(tmp, MetaDataKey::MeetingStartDate) == MetaDataKey::ValueFound)
|
if (meta->getInt64(tmp, MetaDataKey::MeetingStartDate) == MetaDataKey::ValueFound)
|
||||||
start = QDate::fromJulianDay(tmp);
|
start = QDate::fromJulianDay(tmp);
|
||||||
if(meta->getInt64(tmp, MetaDataKey::MeetingEndDate) == MetaDataKey::ValueFound)
|
if (meta->getInt64(tmp, MetaDataKey::MeetingEndDate) == MetaDataKey::ValueFound)
|
||||||
end = QDate::fromJulianDay(tmp);
|
end = QDate::fromJulianDay(tmp);
|
||||||
if(!end.isValid() || end < start)
|
if (!end.isValid() || end < start)
|
||||||
end = start;
|
end = start;
|
||||||
|
|
||||||
if(!meetingLocation.isEmpty() && start.isValid())
|
if (!meetingLocation.isEmpty() && start.isValid())
|
||||||
{
|
{
|
||||||
//Store description only if metadata is valid
|
// Store description only if metadata is valid
|
||||||
//Example: Meeting in CORNUDA from 07/11/2020 to 09/11/2020
|
// Example: Meeting in CORNUDA from 07/11/2020 to 09/11/2020
|
||||||
|
|
||||||
QString description;
|
QString description;
|
||||||
if(start != end)
|
if (start != end)
|
||||||
{
|
{
|
||||||
description = Odt::text(Odt::meetingFromTo)
|
description =
|
||||||
.arg(meetingLocation,
|
Odt::text(Odt::meetingFromTo)
|
||||||
start.toString("dd/MM/yyyy"),
|
.arg(meetingLocation, start.toString("dd/MM/yyyy"), end.toString("dd/MM/yyyy"));
|
||||||
end.toString("dd/MM/yyyy"));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
description = Odt::text(Odt::meetingOnDate)
|
description =
|
||||||
.arg(meetingLocation,
|
Odt::text(Odt::meetingOnDate).arg(meetingLocation, start.toString("dd/MM/yyyy"));
|
||||||
start.toString("dd/MM/yyyy"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeStartElement("dc:description");
|
xml.writeStartElement("dc:description");
|
||||||
xml.writeCharacters(description);
|
xml.writeCharacters(description);
|
||||||
xml.writeEndElement(); //dc:description
|
xml.writeEndElement(); // dc:description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Language
|
// Language
|
||||||
xml.writeStartElement("dc:language");
|
xml.writeStartElement("dc:language");
|
||||||
xml.writeCharacters(Session->getSheetExportLocale().bcp47Name());
|
xml.writeCharacters(Session->getSheetExportLocale().bcp47Name());
|
||||||
xml.writeEndElement(); //dc:language
|
xml.writeEndElement(); // dc:language
|
||||||
|
|
||||||
//Generator
|
// Generator
|
||||||
xml.writeStartElement("meta:generator");
|
xml.writeStartElement("meta:generator");
|
||||||
xml.writeCharacters(AppProduct);
|
xml.writeCharacters(AppProduct);
|
||||||
xml.writeCharacters("/");
|
xml.writeCharacters("/");
|
||||||
xml.writeCharacters(AppVersion);
|
xml.writeCharacters(AppVersion);
|
||||||
xml.writeCharacters("-");
|
xml.writeCharacters("-");
|
||||||
xml.writeCharacters(AppBuildDate);
|
xml.writeCharacters(AppBuildDate);
|
||||||
xml.writeEndElement(); //meta:generator
|
xml.writeEndElement(); // meta:generator
|
||||||
|
|
||||||
//Initial creator
|
// Initial creator
|
||||||
xml.writeStartElement("meta:initial-creator");
|
xml.writeStartElement("meta:initial-creator");
|
||||||
xml.writeCharacters(AppDisplayName);
|
xml.writeCharacters(AppDisplayName);
|
||||||
xml.writeEndElement(); //meta:initial-creator
|
xml.writeEndElement(); // meta:initial-creator
|
||||||
|
|
||||||
//Creation date
|
// Creation date
|
||||||
xml.writeStartElement("meta:creation-date");
|
xml.writeStartElement("meta:creation-date");
|
||||||
//NOTE: date must be in ISO 8601 format but without time zone offset (LibreOffice doesn't recognize it)
|
// NOTE: date must be in ISO 8601 format but without time zone offset (LibreOffice doesn't
|
||||||
// so do not use Qt::ISODate otherwise there is the risk of adding time zone offset to string
|
// recognize it)
|
||||||
|
// so do not use Qt::ISODate otherwise there is the risk of adding time zone offset to
|
||||||
|
// string
|
||||||
xml.writeCharacters(QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss"));
|
xml.writeCharacters(QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss"));
|
||||||
xml.writeEndElement(); //meta:creation-date
|
xml.writeEndElement(); // meta:creation-date
|
||||||
|
|
||||||
//Keywords
|
// Keywords
|
||||||
xml.writeStartElement("meta:keyword");
|
xml.writeStartElement("meta:keyword");
|
||||||
xml.writeCharacters(AppDisplayName);
|
xml.writeCharacters(AppDisplayName);
|
||||||
xml.writeEndElement(); //meta:keyword
|
xml.writeEndElement(); // meta:keyword
|
||||||
|
|
||||||
xml.writeStartElement("meta:keyword");
|
xml.writeStartElement("meta:keyword");
|
||||||
xml.writeCharacters(AppProduct);
|
xml.writeCharacters(AppProduct);
|
||||||
xml.writeEndElement(); //meta:keyword
|
xml.writeEndElement(); // meta:keyword
|
||||||
|
|
||||||
xml.writeStartElement("meta:keyword");
|
xml.writeStartElement("meta:keyword");
|
||||||
xml.writeCharacters(AppCompany);
|
xml.writeCharacters(AppCompany);
|
||||||
xml.writeEndElement(); //meta:keyword
|
xml.writeEndElement(); // meta:keyword
|
||||||
|
|
||||||
xml.writeStartElement("meta:keyword");
|
xml.writeStartElement("meta:keyword");
|
||||||
xml.writeCharacters(Odt::text(Odt::meeting));
|
xml.writeCharacters(Odt::text(Odt::meeting));
|
||||||
xml.writeEndElement(); //meta:keyword
|
xml.writeEndElement(); // meta:keyword
|
||||||
|
|
||||||
//Untranslated version
|
// Untranslated version
|
||||||
xml.writeStartElement("meta:keyword");
|
xml.writeStartElement("meta:keyword");
|
||||||
xml.writeCharacters(QString::fromUtf8(Odt::meeting.sourceText));
|
xml.writeCharacters(QString::fromUtf8(Odt::meeting.sourceText));
|
||||||
xml.writeEndElement(); //meta:keyword
|
xml.writeEndElement(); // meta:keyword
|
||||||
|
|
||||||
if(storeLocationAndDate && !meetingLocation.isEmpty())
|
if (storeLocationAndDate && !meetingLocation.isEmpty())
|
||||||
{
|
{
|
||||||
xml.writeStartElement("meta:keyword");
|
xml.writeStartElement("meta:keyword");
|
||||||
xml.writeCharacters(meetingLocation);
|
xml.writeCharacters(meetingLocation);
|
||||||
xml.writeEndElement(); //meta:keyword
|
xml.writeEndElement(); // meta:keyword
|
||||||
}
|
}
|
||||||
|
|
||||||
//End
|
// End
|
||||||
xml.writeEndElement(); //office:meta
|
xml.writeEndElement(); // office:meta
|
||||||
xml.writeEndElement(); //office:document-meta
|
xml.writeEndElement(); // office:document-meta
|
||||||
|
|
||||||
xml.writeEndDocument();
|
xml.writeEndDocument();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,13 @@ public:
|
||||||
void startBody();
|
void startBody();
|
||||||
void endDocument();
|
void endDocument();
|
||||||
|
|
||||||
//Returns a 'path + file name' where you must save the image
|
// Returns a 'path + file name' where you must save the image
|
||||||
QString addImage(const QString& name, const QString& mediaType);
|
QString addImage(const QString &name, const QString &mediaType);
|
||||||
|
|
||||||
inline void setTitle(const QString& title) { documentTitle = title; }
|
inline void setTitle(const QString &title)
|
||||||
|
{
|
||||||
|
documentTitle = title;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QTemporaryDir dir;
|
QTemporaryDir dir;
|
||||||
|
@ -57,7 +60,7 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString documentTitle;
|
QString documentTitle;
|
||||||
//pair: fileName, mediaType
|
// pair: fileName, mediaType
|
||||||
QList<QPair<QString, QString>> imageList;
|
QList<QPair<QString, QString>> imageList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,29 +34,31 @@ void writeColumnStyle(QXmlStreamWriter &xml, const QString &name, const QString
|
||||||
|
|
||||||
xml.writeStartElement("style:table-column-properties");
|
xml.writeStartElement("style:table-column-properties");
|
||||||
xml.writeAttribute("style:column-width", width);
|
xml.writeAttribute("style:column-width", width);
|
||||||
xml.writeEndElement(); //style:table-column-properties
|
xml.writeEndElement(); // style:table-column-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
}
|
}
|
||||||
|
|
||||||
/* writeCell
|
/* writeCell
|
||||||
*
|
*
|
||||||
* Helper function to write table cell
|
* Helper function to write table cell
|
||||||
* Sets up the cell style and paragraph style, writes single line text and closes xml opened elements
|
* Sets up the cell style and paragraph style, writes single line text and closes xml opened
|
||||||
|
* elements
|
||||||
*/
|
*/
|
||||||
void writeCell(QXmlStreamWriter &xml, const QString &cellStyle, const QString ¶graphStyle, const QString &text)
|
void writeCell(QXmlStreamWriter &xml, const QString &cellStyle, const QString ¶graphStyle,
|
||||||
|
const QString &text)
|
||||||
{
|
{
|
||||||
//Cell
|
// Cell
|
||||||
xml.writeStartElement("table:table-cell");
|
xml.writeStartElement("table:table-cell");
|
||||||
xml.writeAttribute("office:value-type", "string");
|
xml.writeAttribute("office:value-type", "string");
|
||||||
xml.writeAttribute("table:style-name", cellStyle);
|
xml.writeAttribute("table:style-name", cellStyle);
|
||||||
|
|
||||||
//text:p
|
// text:p
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", paragraphStyle);
|
xml.writeAttribute("text:style-name", paragraphStyle);
|
||||||
xml.writeCharacters(text);
|
xml.writeCharacters(text);
|
||||||
xml.writeEndElement(); //text:p
|
xml.writeEndElement(); // text:p
|
||||||
|
|
||||||
xml.writeEndElement(); //table-cell
|
xml.writeEndElement(); // table-cell
|
||||||
}
|
}
|
||||||
|
|
||||||
/* writeCellListStart
|
/* writeCellListStart
|
||||||
|
@ -66,14 +68,15 @@ void writeCell(QXmlStreamWriter &xml, const QString &cellStyle, const QString &p
|
||||||
* Then you have full control on cell contents
|
* Then you have full control on cell contents
|
||||||
* Then call writeCellListEnd
|
* Then call writeCellListEnd
|
||||||
*/
|
*/
|
||||||
void writeCellListStart(QXmlStreamWriter &xml, const QString &cellStyle, const QString ¶graphStyle)
|
void writeCellListStart(QXmlStreamWriter &xml, const QString &cellStyle,
|
||||||
|
const QString ¶graphStyle)
|
||||||
{
|
{
|
||||||
//Cell
|
// Cell
|
||||||
xml.writeStartElement("table:table-cell");
|
xml.writeStartElement("table:table-cell");
|
||||||
xml.writeAttribute("office:value-type", "string");
|
xml.writeAttribute("office:value-type", "string");
|
||||||
xml.writeAttribute("table:style-name", cellStyle);
|
xml.writeAttribute("table:style-name", cellStyle);
|
||||||
|
|
||||||
//text:p
|
// text:p
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", paragraphStyle);
|
xml.writeAttribute("text:style-name", paragraphStyle);
|
||||||
}
|
}
|
||||||
|
@ -84,8 +87,8 @@ void writeCellListStart(QXmlStreamWriter &xml, const QString &cellStyle, const Q
|
||||||
*/
|
*/
|
||||||
void writeCellListEnd(QXmlStreamWriter &xml)
|
void writeCellListEnd(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
xml.writeEndElement(); //text:p
|
xml.writeEndElement(); // text:p
|
||||||
xml.writeEndElement(); //table-cell
|
xml.writeEndElement(); // table-cell
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeStandardStyle(QXmlStreamWriter &xml)
|
void writeStandardStyle(QXmlStreamWriter &xml)
|
||||||
|
@ -96,7 +99,7 @@ void writeStandardStyle(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("style:family", "paragraph");
|
xml.writeAttribute("style:family", "paragraph");
|
||||||
xml.writeAttribute("style:class", "text");
|
xml.writeAttribute("style:class", "text");
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeGraphicsStyle(QXmlStreamWriter &xml)
|
void writeGraphicsStyle(QXmlStreamWriter &xml)
|
||||||
|
@ -113,9 +116,9 @@ void writeGraphicsStyle(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("style:vertical-rel", "paragraph");
|
xml.writeAttribute("style:vertical-rel", "paragraph");
|
||||||
xml.writeAttribute("style:horizontal-pos", "center");
|
xml.writeAttribute("style:horizontal-pos", "center");
|
||||||
xml.writeAttribute("style:horizontal-rel", "paragraph");
|
xml.writeAttribute("style:horizontal-rel", "paragraph");
|
||||||
xml.writeEndElement(); //style:graphic-properties
|
xml.writeEndElement(); // style:graphic-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeCommonStyles(QXmlStreamWriter &xml)
|
void writeCommonStyles(QXmlStreamWriter &xml)
|
||||||
|
@ -154,14 +157,14 @@ void writeCommonStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "center");
|
xml.writeAttribute("fo:text-align", "center");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "18pt");
|
xml.writeAttribute("fo:font-size", "18pt");
|
||||||
xml.writeAttribute("fo:font-weight", "bold");
|
xml.writeAttribute("fo:font-weight", "bold");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
/* Style P4
|
/* Style P4
|
||||||
* type: paragraph style
|
* type: paragraph style
|
||||||
|
@ -199,14 +202,14 @@ void writeCommonStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "center");
|
xml.writeAttribute("fo:text-align", "center");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "12pt");
|
xml.writeAttribute("fo:font-size", "12pt");
|
||||||
xml.writeAttribute("fo:font-weight", "bold");
|
xml.writeAttribute("fo:font-weight", "bold");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
/* Style T1
|
/* Style T1
|
||||||
* type: text style
|
* type: text style
|
||||||
|
@ -225,14 +228,14 @@ void writeCommonStyles(QXmlStreamWriter &xml)
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-weight", "bold");
|
xml.writeAttribute("fo:font-weight", "bold");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeFooterStyle(QXmlStreamWriter &xml)
|
void writeFooterStyle(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
//Base style for MP1 style used in header/footer
|
// Base style for MP1 style used in header/footer
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
|
|
||||||
xml.writeAttribute("style:family", "paragraph");
|
xml.writeAttribute("style:family", "paragraph");
|
||||||
|
@ -250,33 +253,33 @@ void writeFooterStyle(QXmlStreamWriter &xml)
|
||||||
xml.writeStartElement("style:tab-stop");
|
xml.writeStartElement("style:tab-stop");
|
||||||
xml.writeAttribute("style:position", "8.5cm");
|
xml.writeAttribute("style:position", "8.5cm");
|
||||||
xml.writeAttribute("style:type", "center");
|
xml.writeAttribute("style:type", "center");
|
||||||
xml.writeEndElement(); //style:tab-stop
|
xml.writeEndElement(); // style:tab-stop
|
||||||
|
|
||||||
xml.writeStartElement("style:tab-stop");
|
xml.writeStartElement("style:tab-stop");
|
||||||
xml.writeAttribute("style:position", "17cm");
|
xml.writeAttribute("style:position", "17cm");
|
||||||
xml.writeAttribute("style:type", "right");
|
xml.writeAttribute("style:type", "right");
|
||||||
xml.writeEndElement(); //style:tab-stop
|
xml.writeEndElement(); // style:tab-stop
|
||||||
|
|
||||||
xml.writeEndElement(); //style:tab-stops
|
xml.writeEndElement(); // style:tab-stops
|
||||||
|
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
}
|
}
|
||||||
|
|
||||||
void writePageLayout(QXmlStreamWriter &xml)
|
void writePageLayout(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
//Footer style
|
// Footer style
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:name", "MP1");
|
xml.writeAttribute("style:name", "MP1");
|
||||||
xml.writeAttribute("style:family", "paragraph");
|
xml.writeAttribute("style:family", "paragraph");
|
||||||
xml.writeAttribute("style:parent-style-name", "Footer");
|
xml.writeAttribute("style:parent-style-name", "Footer");
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("style:font-name", "Liberation Sans");
|
xml.writeAttribute("style:font-name", "Liberation Sans");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
//Page Layout
|
// Page Layout
|
||||||
xml.writeStartElement("style:page-layout");
|
xml.writeStartElement("style:page-layout");
|
||||||
|
|
||||||
xml.writeAttribute("style:name", "Mpm1");
|
xml.writeAttribute("style:name", "Mpm1");
|
||||||
|
@ -286,25 +289,25 @@ void writePageLayout(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:margin-bottom", "2cm");
|
xml.writeAttribute("fo:margin-bottom", "2cm");
|
||||||
xml.writeAttribute("fo:margin-left", "2cm");
|
xml.writeAttribute("fo:margin-left", "2cm");
|
||||||
xml.writeAttribute("fo:margin-right", "2cm");
|
xml.writeAttribute("fo:margin-right", "2cm");
|
||||||
xml.writeEndElement(); //style:page-layout-properties
|
xml.writeEndElement(); // style:page-layout-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:header-style");
|
xml.writeStartElement("style:header-style");
|
||||||
xml.writeEndElement(); //style:header-style
|
xml.writeEndElement(); // style:header-style
|
||||||
|
|
||||||
xml.writeStartElement("style:footer-style");
|
xml.writeStartElement("style:footer-style");
|
||||||
xml.writeEndElement(); //style:footer-style
|
xml.writeEndElement(); // style:footer-style
|
||||||
|
|
||||||
xml.writeEndElement(); //style:page-layout
|
xml.writeEndElement(); // style:page-layout
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeHeaderFooter(QXmlStreamWriter &xml, const QString& headerText, const QString& footerText)
|
void writeHeaderFooter(QXmlStreamWriter &xml, const QString &headerText, const QString &footerText)
|
||||||
{
|
{
|
||||||
xml.writeStartElement("style:master-page");
|
xml.writeStartElement("style:master-page");
|
||||||
|
|
||||||
xml.writeAttribute("style:name", "Standard");
|
xml.writeAttribute("style:name", "Standard");
|
||||||
xml.writeAttribute("style:page-layout-name", "Mpm1"); //TODO
|
xml.writeAttribute("style:page-layout-name", "Mpm1"); // TODO
|
||||||
|
|
||||||
//Header
|
// Header
|
||||||
xml.writeStartElement("style:header");
|
xml.writeStartElement("style:header");
|
||||||
|
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
|
@ -313,10 +316,10 @@ void writeHeaderFooter(QXmlStreamWriter &xml, const QString& headerText, const Q
|
||||||
xml.writeCharacters(headerText);
|
xml.writeCharacters(headerText);
|
||||||
|
|
||||||
xml.writeStartElement("text:tab");
|
xml.writeStartElement("text:tab");
|
||||||
xml.writeEndElement(); //text:tab
|
xml.writeEndElement(); // text:tab
|
||||||
|
|
||||||
xml.writeStartElement("text:tab");
|
xml.writeStartElement("text:tab");
|
||||||
xml.writeEndElement(); //text:tab
|
xml.writeEndElement(); // text:tab
|
||||||
|
|
||||||
const QString pageStr = Odt::text(Odt::headerPage);
|
const QString pageStr = Odt::text(Odt::headerPage);
|
||||||
|
|
||||||
|
@ -324,13 +327,13 @@ void writeHeaderFooter(QXmlStreamWriter &xml, const QString& headerText, const Q
|
||||||
|
|
||||||
xml.writeStartElement("text:page-number");
|
xml.writeStartElement("text:page-number");
|
||||||
xml.writeAttribute("text:select-page", "current");
|
xml.writeAttribute("text:select-page", "current");
|
||||||
xml.writeEndElement(); //text:page-number
|
xml.writeEndElement(); // text:page-number
|
||||||
|
|
||||||
xml.writeEndElement(); //text:p
|
xml.writeEndElement(); // text:p
|
||||||
|
|
||||||
xml.writeEndElement(); //style:header
|
xml.writeEndElement(); // style:header
|
||||||
|
|
||||||
//Header for left pages (mirrored)
|
// Header for left pages (mirrored)
|
||||||
xml.writeStartElement("style:header-left");
|
xml.writeStartElement("style:header-left");
|
||||||
|
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
|
@ -340,21 +343,21 @@ void writeHeaderFooter(QXmlStreamWriter &xml, const QString& headerText, const Q
|
||||||
|
|
||||||
xml.writeStartElement("text:page-number");
|
xml.writeStartElement("text:page-number");
|
||||||
xml.writeAttribute("text:select-page", "current");
|
xml.writeAttribute("text:select-page", "current");
|
||||||
xml.writeEndElement(); //text:page-number
|
xml.writeEndElement(); // text:page-number
|
||||||
|
|
||||||
xml.writeStartElement("text:tab");
|
xml.writeStartElement("text:tab");
|
||||||
xml.writeEndElement(); //text:tab
|
xml.writeEndElement(); // text:tab
|
||||||
|
|
||||||
xml.writeStartElement("text:tab");
|
xml.writeStartElement("text:tab");
|
||||||
xml.writeEndElement(); //text:tab
|
xml.writeEndElement(); // text:tab
|
||||||
|
|
||||||
xml.writeCharacters(headerText);
|
xml.writeCharacters(headerText);
|
||||||
|
|
||||||
xml.writeEndElement(); //text:p
|
xml.writeEndElement(); // text:p
|
||||||
|
|
||||||
xml.writeEndElement(); //style:header-left
|
xml.writeEndElement(); // style:header-left
|
||||||
|
|
||||||
//Footer
|
// Footer
|
||||||
xml.writeStartElement("style:footer");
|
xml.writeStartElement("style:footer");
|
||||||
|
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
|
@ -362,19 +365,19 @@ void writeHeaderFooter(QXmlStreamWriter &xml, const QString& headerText, const Q
|
||||||
|
|
||||||
xml.writeCharacters(footerText);
|
xml.writeCharacters(footerText);
|
||||||
|
|
||||||
xml.writeEndElement(); //text:p
|
xml.writeEndElement(); // text:p
|
||||||
|
|
||||||
xml.writeEndElement(); //style:footer
|
xml.writeEndElement(); // style:footer
|
||||||
|
|
||||||
xml.writeEndElement(); //style:master-page
|
xml.writeEndElement(); // style:master-page
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeLiberationFontFaces(QXmlStreamWriter &xml)
|
void writeLiberationFontFaces(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
const QString variablePitch = QStringLiteral("variable");
|
const QString variablePitch = QStringLiteral("variable");
|
||||||
const QString liberationSerif = QStringLiteral("Liberation Serif");
|
const QString liberationSerif = QStringLiteral("Liberation Serif");
|
||||||
const QString liberationSans = QStringLiteral("Liberation Sans");
|
const QString liberationSans = QStringLiteral("Liberation Sans");
|
||||||
const QString liberationMono = QStringLiteral("Liberation Mono");
|
const QString liberationMono = QStringLiteral("Liberation Mono");
|
||||||
|
|
||||||
writeFontFace(xml, liberationSerif, liberationSerif, "roman", variablePitch);
|
writeFontFace(xml, liberationSerif, liberationSerif, "roman", variablePitch);
|
||||||
writeFontFace(xml, liberationSans, liberationSans, "swiss", variablePitch);
|
writeFontFace(xml, liberationSans, liberationSans, "swiss", variablePitch);
|
||||||
|
@ -386,18 +389,18 @@ QString Odt::text(const Text &t)
|
||||||
QTranslator *translator = Session->getSheetExportTranslator();
|
QTranslator *translator = Session->getSheetExportTranslator();
|
||||||
|
|
||||||
QString result;
|
QString result;
|
||||||
if(translator)
|
if (translator)
|
||||||
{
|
{
|
||||||
//Prefer selected language
|
// Prefer selected language
|
||||||
result = translator->translate("Odt", t.sourceText, t.disambiguation);
|
result = translator->translate("Odt", t.sourceText, t.disambiguation);
|
||||||
}
|
}
|
||||||
else if(Session->getSheetExportLocale() == MeetingSession::embeddedLocale)
|
else if (Session->getSheetExportLocale() == MeetingSession::embeddedLocale)
|
||||||
{
|
{
|
||||||
//Bypass any translation and use hardcoded string literals
|
// Bypass any translation and use hardcoded string literals
|
||||||
return QString::fromUtf8(t.sourceText);
|
return QString::fromUtf8(t.sourceText);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result.isNull()) //Fallback to application language
|
if (result.isNull()) // Fallback to application language
|
||||||
result = tr(t.sourceText, t.disambiguation);
|
result = tr(t.sourceText, t.disambiguation);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,16 +24,14 @@
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
//small util
|
// small util
|
||||||
void writeColumnStyle(QXmlStreamWriter& xml, const QString& name, const QString& width);
|
void writeColumnStyle(QXmlStreamWriter &xml, const QString &name, const QString &width);
|
||||||
|
|
||||||
void writeCell(QXmlStreamWriter &xml,
|
void writeCell(QXmlStreamWriter &xml, const QString &cellStyle, const QString ¶graphStyle,
|
||||||
const QString& cellStyle,
|
const QString &text);
|
||||||
const QString& paragraphStyle,
|
|
||||||
const QString& text);
|
|
||||||
|
|
||||||
|
void writeCellListStart(QXmlStreamWriter &xml, const QString &cellStyle,
|
||||||
void writeCellListStart(QXmlStreamWriter &xml, const QString &cellStyle, const QString ¶graphStyle);
|
const QString ¶graphStyle);
|
||||||
void writeCellListEnd(QXmlStreamWriter &xml);
|
void writeCellListEnd(QXmlStreamWriter &xml);
|
||||||
|
|
||||||
void writeStandardStyle(QXmlStreamWriter &xml);
|
void writeStandardStyle(QXmlStreamWriter &xml);
|
||||||
|
@ -46,37 +44,34 @@ void writeFooterStyle(QXmlStreamWriter &xml);
|
||||||
|
|
||||||
void writePageLayout(QXmlStreamWriter &xml);
|
void writePageLayout(QXmlStreamWriter &xml);
|
||||||
|
|
||||||
void writeHeaderFooter(QXmlStreamWriter &xml,
|
void writeHeaderFooter(QXmlStreamWriter &xml, const QString &headerText, const QString &footerText);
|
||||||
const QString& headerText,
|
|
||||||
const QString& footerText);
|
|
||||||
|
|
||||||
inline void writeFontFace(QXmlStreamWriter &xml,
|
inline void writeFontFace(QXmlStreamWriter &xml, const QString &name, const QString &family,
|
||||||
const QString& name, const QString& family,
|
const QString &genericFamily, const QString &pitch)
|
||||||
const QString& genericFamily, const QString& pitch)
|
|
||||||
{
|
{
|
||||||
xml.writeStartElement("style:font-face");
|
xml.writeStartElement("style:font-face");
|
||||||
xml.writeAttribute("style:name", name);
|
xml.writeAttribute("style:name", name);
|
||||||
if(!family.isEmpty())
|
if (!family.isEmpty())
|
||||||
{
|
{
|
||||||
QString familyQuoted;
|
QString familyQuoted;
|
||||||
familyQuoted.reserve(family.size() + 2);
|
familyQuoted.reserve(family.size() + 2);
|
||||||
bool needsQuotes = family.contains(' '); //If family name contains blanks
|
bool needsQuotes = family.contains(' '); // If family name contains blanks
|
||||||
if(needsQuotes) //Enclose in single quotes
|
if (needsQuotes) // Enclose in single quotes
|
||||||
familyQuoted.append('\'');
|
familyQuoted.append('\'');
|
||||||
familyQuoted.append(family);
|
familyQuoted.append(family);
|
||||||
if(needsQuotes)
|
if (needsQuotes)
|
||||||
familyQuoted.append('\'');
|
familyQuoted.append('\'');
|
||||||
xml.writeAttribute("svg:font-family", familyQuoted);
|
xml.writeAttribute("svg:font-family", familyQuoted);
|
||||||
}
|
}
|
||||||
if(!genericFamily.isEmpty())
|
if (!genericFamily.isEmpty())
|
||||||
{
|
{
|
||||||
xml.writeAttribute("svg:font-family-generic", genericFamily);
|
xml.writeAttribute("svg:font-family-generic", genericFamily);
|
||||||
}
|
}
|
||||||
if(!pitch.isEmpty())
|
if (!pitch.isEmpty())
|
||||||
{
|
{
|
||||||
xml.writeAttribute("svg:font-pitch", pitch);
|
xml.writeAttribute("svg:font-pitch", pitch);
|
||||||
}
|
}
|
||||||
xml.writeEndElement(); //style:font-face
|
xml.writeEndElement(); // style:font-face
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeLiberationFontFaces(QXmlStreamWriter &xml);
|
void writeLiberationFontFaces(QXmlStreamWriter &xml);
|
||||||
|
@ -91,72 +86,90 @@ public:
|
||||||
const char *disambiguation;
|
const char *disambiguation;
|
||||||
};
|
};
|
||||||
|
|
||||||
static QString text(const Text& t);
|
static QString text(const Text &t);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//Header/Footer
|
// Header/Footer
|
||||||
static constexpr Text headerPage = QT_TRANSLATE_NOOP3("Odt", "Page ",
|
static constexpr Text headerPage = QT_TRANSLATE_NOOP3(
|
||||||
"Header page, leave space at end, page number will be added");
|
"Odt", "Page ", "Header page, leave space at end, page number will be added");
|
||||||
|
|
||||||
//Meeting
|
// Meeting
|
||||||
static constexpr Text meeting = QT_TRANSLATE_NOOP3("Odt", "Meeting", "Document keywords");
|
static constexpr Text meeting = QT_TRANSLATE_NOOP3("Odt", "Meeting", "Document keywords");
|
||||||
static constexpr Text meetingFromTo = QT_TRANSLATE_NOOP3("Odt", "Meeting in %1 from %2 to %3",
|
static constexpr Text meetingFromTo = QT_TRANSLATE_NOOP3(
|
||||||
"Document description, where, from date, to date");
|
"Odt", "Meeting in %1 from %2 to %3", "Document description, where, from date, to date");
|
||||||
static constexpr Text meetingOnDate = QT_TRANSLATE_NOOP3("Odt", "Meeting in %1 on %2",
|
static constexpr Text meetingOnDate =
|
||||||
"Document description, where, when");
|
QT_TRANSLATE_NOOP3("Odt", "Meeting in %1 on %2", "Document description, where, when");
|
||||||
static constexpr Text meetingFromToShort = QT_TRANSLATE_NOOP3("Odt", "From %1 to %2",
|
static constexpr Text meetingFromToShort =
|
||||||
"Shift cover, meeting from date, to date");
|
QT_TRANSLATE_NOOP3("Odt", "From %1 to %2", "Shift cover, meeting from date, to date");
|
||||||
|
|
||||||
//Rollingstock
|
// Rollingstock
|
||||||
static constexpr Text CoupledAbbr = QT_TRANSLATE_NOOP3("Odt", "Cp:", "Job stop coupled RS");
|
static constexpr Text CoupledAbbr = QT_TRANSLATE_NOOP3("Odt", "Cp:", "Job stop coupled RS");
|
||||||
static constexpr Text UncoupledAbbr = QT_TRANSLATE_NOOP3("Odt", "Unc:", "Job stop uncoupled RS");
|
static constexpr Text UncoupledAbbr =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "Unc:", "Job stop uncoupled RS");
|
||||||
static constexpr Text genericRSOwner = QT_TRANSLATE_NOOP3("Odt", "Owner", "Rollingstock Owner");
|
static constexpr Text genericRSOwner = QT_TRANSLATE_NOOP3("Odt", "Owner", "Rollingstock Owner");
|
||||||
|
|
||||||
static constexpr Text rsSessionTitle = QT_TRANSLATE_NOOP3("Odt", "Rollingstock by %1 at %2 of session",
|
static constexpr Text rsSessionTitle =
|
||||||
"Rollingstock Session title, 1 is Owner/Station and 2 is start/end");
|
QT_TRANSLATE_NOOP3("Odt", "Rollingstock by %1 at %2 of session",
|
||||||
static constexpr Text rsSessionStart = QT_TRANSLATE_NOOP3("Odt", "start", "Rollingstock Session start");
|
"Rollingstock Session title, 1 is Owner/Station and 2 is start/end");
|
||||||
static constexpr Text rsSessionEnd = QT_TRANSLATE_NOOP3("Odt", "end", "Rollingstock Session end");
|
static constexpr Text rsSessionStart =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "start", "Rollingstock Session start");
|
||||||
|
static constexpr Text rsSessionEnd =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "end", "Rollingstock Session end");
|
||||||
|
|
||||||
//Job Summary
|
// Job Summary
|
||||||
static constexpr Text jobSummaryFrom = QT_TRANSLATE_NOOP3("Odt", "From:", "Job summary");
|
static constexpr Text jobSummaryFrom = QT_TRANSLATE_NOOP3("Odt", "From:", "Job summary");
|
||||||
static constexpr Text jobSummaryTo = QT_TRANSLATE_NOOP3("Odt", "To:", "Job summary");
|
static constexpr Text jobSummaryTo = QT_TRANSLATE_NOOP3("Odt", "To:", "Job summary");
|
||||||
static constexpr Text jobSummaryDep = QT_TRANSLATE_NOOP3("Odt", "Departure:", "Job summary");
|
static constexpr Text jobSummaryDep = QT_TRANSLATE_NOOP3("Odt", "Departure:", "Job summary");
|
||||||
static constexpr Text jobSummaryArr = QT_TRANSLATE_NOOP3("Odt", "Arrival:", "Job summary");
|
static constexpr Text jobSummaryArr = QT_TRANSLATE_NOOP3("Odt", "Arrival:", "Job summary");
|
||||||
static constexpr Text jobSummaryAxes = QT_TRANSLATE_NOOP3("Odt", "Axes:", "Job summary");
|
static constexpr Text jobSummaryAxes = QT_TRANSLATE_NOOP3("Odt", "Axes:", "Job summary");
|
||||||
|
|
||||||
//Job Stops Header
|
// Job Stops Header
|
||||||
static constexpr Text station = QT_TRANSLATE_NOOP3("Odt", "Station", "Job stop table");
|
static constexpr Text station = QT_TRANSLATE_NOOP3("Odt", "Station", "Job stop table");
|
||||||
static constexpr Text stationPageTitle = QT_TRANSLATE_NOOP3("Odt", "Station: %1", "Station title in station sheet");
|
static constexpr Text stationPageTitle =
|
||||||
static constexpr Text stationDocTitle = QT_TRANSLATE_NOOP3("Odt", "%1 station", "Station sheet title in document metadata");
|
QT_TRANSLATE_NOOP3("Odt", "Station: %1", "Station title in station sheet");
|
||||||
static constexpr Text rollingstock = QT_TRANSLATE_NOOP3("Odt", "Rollingstock", "Job stop table");
|
static constexpr Text stationDocTitle =
|
||||||
static constexpr Text jobNr = QT_TRANSLATE_NOOP3("Odt", "Job Nr", "Job column");
|
QT_TRANSLATE_NOOP3("Odt", "%1 station", "Station sheet title in document metadata");
|
||||||
|
static constexpr Text rollingstock =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "Rollingstock", "Job stop table");
|
||||||
|
static constexpr Text jobNr = QT_TRANSLATE_NOOP3("Odt", "Job Nr", "Job column");
|
||||||
|
|
||||||
static constexpr Text arrival = QT_TRANSLATE_NOOP3("Odt", "Arrival", "Job stop table");
|
static constexpr Text arrival = QT_TRANSLATE_NOOP3("Odt", "Arrival", "Job stop table");
|
||||||
static constexpr Text departure = QT_TRANSLATE_NOOP3("Odt", "Departure", "Job stop table");
|
static constexpr Text departure = QT_TRANSLATE_NOOP3("Odt", "Departure", "Job stop table");
|
||||||
static constexpr Text arrivalShort = QT_TRANSLATE_NOOP3("Odt", "Arr.", "Arrival abbreviated");
|
static constexpr Text arrivalShort = QT_TRANSLATE_NOOP3("Odt", "Arr.", "Arrival abbreviated");
|
||||||
static constexpr Text departureShort = QT_TRANSLATE_NOOP3("Odt", "Dep.", "Departure abbreviated");
|
static constexpr Text departureShort =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "Dep.", "Departure abbreviated");
|
||||||
|
|
||||||
static constexpr Text stationFromCol = QT_TRANSLATE_NOOP3("Odt", "From", "Station stop table, From previous station column");
|
static constexpr Text stationFromCol =
|
||||||
static constexpr Text stationToCol = QT_TRANSLATE_NOOP3("Odt", "To", "Station stop table, To next station column");
|
QT_TRANSLATE_NOOP3("Odt", "From", "Station stop table, From previous station column");
|
||||||
|
static constexpr Text stationToCol =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "To", "Station stop table, To next station column");
|
||||||
|
|
||||||
static constexpr Text jobStopPlatf = QT_TRANSLATE_NOOP3("Odt", "Platf", "Job stop table, platform abbreviated");
|
static constexpr Text jobStopPlatf =
|
||||||
static constexpr Text jobStopIsTransit = QT_TRANSLATE_NOOP3("Odt", "Transit", "Job stop table, notes column");
|
QT_TRANSLATE_NOOP3("Odt", "Platf", "Job stop table, platform abbreviated");
|
||||||
static constexpr Text jobStopIsFirst = QT_TRANSLATE_NOOP3("Odt", "START",
|
static constexpr Text jobStopIsTransit =
|
||||||
"Station stop table, notes column for first job stop, "
|
QT_TRANSLATE_NOOP3("Odt", "Transit", "Job stop table, notes column");
|
||||||
"keep in English it's the same for every sheet");
|
static constexpr Text jobStopIsFirst =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "START",
|
||||||
|
"Station stop table, notes column for first job stop, "
|
||||||
|
"keep in English it's the same for every sheet");
|
||||||
|
|
||||||
static constexpr Text jobStopCross = QT_TRANSLATE_NOOP3("Odt", "Crossings", "Job stop table");
|
static constexpr Text jobStopCross = QT_TRANSLATE_NOOP3("Odt", "Crossings", "Job stop table");
|
||||||
static constexpr Text jobStopPassings = QT_TRANSLATE_NOOP3("Odt", "Passings", "Job stop table");
|
static constexpr Text jobStopPassings = QT_TRANSLATE_NOOP3("Odt", "Passings", "Job stop table");
|
||||||
static constexpr Text jobStopCrossShort = QT_TRANSLATE_NOOP3("Odt", "Cross", "Job stop crossings abbreviated column");
|
static constexpr Text jobStopCrossShort =
|
||||||
static constexpr Text jobStopPassingsShort = QT_TRANSLATE_NOOP3("Odt", "Passes", "Job stop passings abbreviated column");
|
QT_TRANSLATE_NOOP3("Odt", "Cross", "Job stop crossings abbreviated column");
|
||||||
|
static constexpr Text jobStopPassingsShort =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "Passes", "Job stop passings abbreviated column");
|
||||||
static constexpr Text notes = QT_TRANSLATE_NOOP3("Odt", "Notes", "Job stop table");
|
static constexpr Text notes = QT_TRANSLATE_NOOP3("Odt", "Notes", "Job stop table");
|
||||||
|
|
||||||
//Job stops
|
// Job stops
|
||||||
static constexpr Text jobReverseDirection = QT_TRANSLATE_NOOP3("Odt", "Reverse direction", "Job stop table");
|
static constexpr Text jobReverseDirection =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "Reverse direction", "Job stop table");
|
||||||
|
|
||||||
//Shift
|
// Shift
|
||||||
static constexpr Text shiftCoverTitle = QT_TRANSLATE_NOOP3("Odt", "SHIFT %1", "Shift title in shift sheet cover");
|
static constexpr Text shiftCoverTitle =
|
||||||
static constexpr Text shiftDocTitle = QT_TRANSLATE_NOOP3("Odt", "Shift %1", "Shift sheet document title for metadata");
|
QT_TRANSLATE_NOOP3("Odt", "SHIFT %1", "Shift title in shift sheet cover");
|
||||||
|
static constexpr Text shiftDocTitle =
|
||||||
|
QT_TRANSLATE_NOOP3("Odt", "Shift %1", "Shift sheet document title for metadata");
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ODTUTILS_H
|
#endif // ODTUTILS_H
|
||||||
|
|
|
@ -33,43 +33,39 @@ SessionRSWriter::SessionRSWriter(database &db, SessionRSMode mode, SessionRSOrde
|
||||||
m_mode(mode),
|
m_mode(mode),
|
||||||
m_order(order)
|
m_order(order)
|
||||||
{
|
{
|
||||||
//TODO: fetch departure instead of arrival for start session
|
// TODO: fetch departure instead of arrival for start session
|
||||||
const auto sql = QStringLiteral("SELECT %1,"
|
const auto sql = QStringLiteral(
|
||||||
" %2, %3, %4,"
|
"SELECT %1,"
|
||||||
" rs_list.id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type,"
|
" %2, %3, %4,"
|
||||||
" t1.name,t2.name,"
|
" rs_list.id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type,"
|
||||||
" stops.job_id, jobs.category, coupling.operation"
|
" t1.name,t2.name,"
|
||||||
" FROM rs_list"
|
" stops.job_id, jobs.category, coupling.operation"
|
||||||
" JOIN coupling ON coupling.rs_id=rs_list.id"
|
" FROM rs_list"
|
||||||
" JOIN stops ON stops.id=coupling.stop_id"
|
" JOIN coupling ON coupling.rs_id=rs_list.id"
|
||||||
" JOIN jobs ON jobs.id=stops.job_id"
|
" JOIN stops ON stops.id=coupling.stop_id"
|
||||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
" JOIN jobs ON jobs.id=stops.job_id"
|
||||||
" LEFT JOIN station_gate_connections g1 ON g1.id=stops.in_gate_conn"
|
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||||
" LEFT JOIN station_gate_connections g2 ON g2.id=stops.out_gate_conn"
|
" LEFT JOIN station_gate_connections g1 ON g1.id=stops.in_gate_conn"
|
||||||
" LEFT JOIN station_tracks t1 ON t1.id=g1.track_id"
|
" LEFT JOIN station_gate_connections g2 ON g2.id=stops.out_gate_conn"
|
||||||
" LEFT JOIN station_tracks t2 ON t2.id=g2.track_id"
|
" LEFT JOIN station_tracks t1 ON t1.id=g1.track_id"
|
||||||
" JOIN %5"
|
" LEFT JOIN station_tracks t2 ON t2.id=g2.track_id"
|
||||||
" GROUP BY rs_list.id"
|
" JOIN %5"
|
||||||
" ORDER BY %6, stops.arrival, stops.job_id, rs_list.model_id");
|
" GROUP BY rs_list.id"
|
||||||
|
" ORDER BY %6, stops.arrival, stops.job_id, rs_list.model_id");
|
||||||
|
|
||||||
QString temp = sql.arg(m_mode == SessionRSMode::StartOfSession ? "MIN(stops.arrival)" : "MAX(stops.departure)");
|
QString temp = sql.arg(m_mode == SessionRSMode::StartOfSession ? "MIN(stops.arrival)"
|
||||||
if(m_order == SessionRSOrder::ByStation)
|
: "MAX(stops.departure)");
|
||||||
|
if (m_order == SessionRSOrder::ByStation)
|
||||||
{
|
{
|
||||||
temp = temp.arg("rs_list.owner_id",
|
temp = temp.arg("rs_list.owner_id", "rs_owners.name", "stops.station_id",
|
||||||
"rs_owners.name",
|
"rs_owners ON rs_owners.id=rs_list.owner_id", "stops.station_id");
|
||||||
"stops.station_id",
|
|
||||||
"rs_owners ON rs_owners.id=rs_list.owner_id",
|
|
||||||
"stops.station_id");
|
|
||||||
|
|
||||||
q_getParentName.prepare("SELECT name FROM stations WHERE id=?");
|
q_getParentName.prepare("SELECT name FROM stations WHERE id=?");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
temp = temp.arg("stops.station_id",
|
temp = temp.arg("stops.station_id", "stations.name", "rs_list.owner_id",
|
||||||
"stations.name",
|
"stations ON stations.id=stops.station_id", "rs_list.owner_id");
|
||||||
"rs_list.owner_id",
|
|
||||||
"stations ON stations.id=stops.station_id",
|
|
||||||
"rs_list.owner_id");
|
|
||||||
|
|
||||||
q_getParentName.prepare("SELECT name FROM rs_owners WHERE id=?");
|
q_getParentName.prepare("SELECT name FROM rs_owners WHERE id=?");
|
||||||
}
|
}
|
||||||
|
@ -91,7 +87,8 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
||||||
* Like P4 but not bold, and Sans Serif
|
* Like P4 but not bold, and Sans Serif
|
||||||
*
|
*
|
||||||
* Usages:
|
* Usages:
|
||||||
* - job_stops: stop cell text for normal stops and transit Rollingstock/Crossings/Passings/Description
|
* - job_stops: stop cell text for normal stops and transit
|
||||||
|
* Rollingstock/Crossings/Passings/Description
|
||||||
*/
|
*/
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:family", "paragraph");
|
xml.writeAttribute("style:family", "paragraph");
|
||||||
|
@ -100,27 +97,26 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "center");
|
xml.writeAttribute("fo:text-align", "center");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("style:font-name", "Liberation Sans");
|
xml.writeAttribute("style:font-name", "Liberation Sans");
|
||||||
xml.writeAttribute("fo:font-size", "12pt");
|
xml.writeAttribute("fo:font-size", "12pt");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
|
// rs_table Table
|
||||||
//rs_table Table
|
|
||||||
/* Style: rs_5f_table
|
/* Style: rs_5f_table
|
||||||
*
|
*
|
||||||
* Type: table
|
* Type: table
|
||||||
* Display name: rollingstock
|
* Display name: rollingstock
|
||||||
* Align: left
|
* Align: left
|
||||||
* Width: 16.0cm
|
* Width: 16.0cm
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* - SessionRSWriter: main table for Rollingstock Owners/Stations
|
* - SessionRSWriter: main table for Rollingstock Owners/Stations
|
||||||
*/
|
*/
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:family", "table");
|
xml.writeAttribute("style:family", "table");
|
||||||
xml.writeAttribute("style:name", "rs_5f_table");
|
xml.writeAttribute("style:name", "rs_5f_table");
|
||||||
|
@ -129,15 +125,15 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("style:shadow", "none");
|
xml.writeAttribute("style:shadow", "none");
|
||||||
xml.writeAttribute("table:align", "left");
|
xml.writeAttribute("table:align", "left");
|
||||||
xml.writeAttribute("style:width", "16.0cm");
|
xml.writeAttribute("style:width", "16.0cm");
|
||||||
xml.writeEndElement(); //style:table-properties
|
xml.writeEndElement(); // style:table-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
//rs_table columns
|
// rs_table columns
|
||||||
writeColumnStyle(xml, "rs_5f_table.A", "3.00cm"); //RS Name
|
writeColumnStyle(xml, "rs_5f_table.A", "3.00cm"); // RS Name
|
||||||
writeColumnStyle(xml, "rs_5f_table.B", "4.45cm"); //Job
|
writeColumnStyle(xml, "rs_5f_table.B", "4.45cm"); // Job
|
||||||
writeColumnStyle(xml, "rs_5f_table.C", "2.21cm"); //Platf
|
writeColumnStyle(xml, "rs_5f_table.C", "2.21cm"); // Platf
|
||||||
writeColumnStyle(xml, "rs_5f_table.D", "3.17cm"); //Departure or Arrival
|
writeColumnStyle(xml, "rs_5f_table.D", "3.17cm"); // Departure or Arrival
|
||||||
writeColumnStyle(xml, "rs_5f_table.E", "4.00cm"); //Station or Owner
|
writeColumnStyle(xml, "rs_5f_table.E", "4.00cm"); // Station or Owner
|
||||||
|
|
||||||
/* Style: rs_5f_table.A1
|
/* Style: rs_5f_table.A1
|
||||||
*
|
*
|
||||||
|
@ -158,8 +154,8 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-right", "none");
|
xml.writeAttribute("fo:border-right", "none");
|
||||||
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: rs_5f_table.E1
|
/* Style: rs_5f_table.E1
|
||||||
*
|
*
|
||||||
|
@ -177,8 +173,8 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeStartElement("style:table-cell-properties");
|
xml.writeStartElement("style:table-cell-properties");
|
||||||
xml.writeAttribute("fo:padding", "0.049cm");
|
xml.writeAttribute("fo:padding", "0.049cm");
|
||||||
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: rs_5f_table.A2
|
/* Style: rs_5f_table.A2
|
||||||
*
|
*
|
||||||
|
@ -199,8 +195,8 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-right", "none");
|
xml.writeAttribute("fo:border-right", "none");
|
||||||
xml.writeAttribute("fo:border-top", "none");
|
xml.writeAttribute("fo:border-top", "none");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: rs_5f_table.E2
|
/* Style: rs_5f_table.E2
|
||||||
*
|
*
|
||||||
|
@ -221,90 +217,93 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-right", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-right", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("fo:border-top", "none");
|
xml.writeAttribute("fo:border-top", "none");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
}
|
}
|
||||||
|
|
||||||
db_id SessionRSWriter::writeTable(QXmlStreamWriter &xml, const QString& parentName)
|
db_id SessionRSWriter::writeTable(QXmlStreamWriter &xml, const QString &parentName)
|
||||||
{
|
{
|
||||||
//Table '???_table' where ??? is the station/owner name without spaces
|
// Table '???_table' where ??? is the station/owner name without spaces
|
||||||
|
|
||||||
QString tableName = parentName;
|
QString tableName = parentName;
|
||||||
tableName.replace(' ', '_'); //Replace spaces with underscores
|
tableName.replace(' ', '_'); // Replace spaces with underscores
|
||||||
tableName.append("_table");
|
tableName.append("_table");
|
||||||
|
|
||||||
xml.writeStartElement("table:table");
|
xml.writeStartElement("table:table");
|
||||||
xml.writeAttribute("table:name", tableName);
|
xml.writeAttribute("table:name", tableName);
|
||||||
xml.writeAttribute("table:style-name", "rs_5f_table");
|
xml.writeAttribute("table:style-name", "rs_5f_table");
|
||||||
|
|
||||||
//Columns
|
// Columns
|
||||||
xml.writeEmptyElement("table:table-column"); //A - RS Name
|
xml.writeEmptyElement("table:table-column"); // A - RS Name
|
||||||
xml.writeAttribute("table:style-name", "rs_5f_table.A");
|
xml.writeAttribute("table:style-name", "rs_5f_table.A");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //B - Job
|
xml.writeEmptyElement("table:table-column"); // B - Job
|
||||||
xml.writeAttribute("table:style-name", "rs_5f_table.B");
|
xml.writeAttribute("table:style-name", "rs_5f_table.B");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //C - Platf
|
xml.writeEmptyElement("table:table-column"); // C - Platf
|
||||||
xml.writeAttribute("table:style-name", "rs_5f_table.C");
|
xml.writeAttribute("table:style-name", "rs_5f_table.C");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //D - Departure
|
xml.writeEmptyElement("table:table-column"); // D - Departure
|
||||||
xml.writeAttribute("table:style-name", "rs_5f_table.D");
|
xml.writeAttribute("table:style-name", "rs_5f_table.D");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //E - Station or Owner
|
xml.writeEmptyElement("table:table-column"); // E - Station or Owner
|
||||||
xml.writeAttribute("table:style-name", "rs_5f_table.E");
|
xml.writeAttribute("table:style-name", "rs_5f_table.E");
|
||||||
|
|
||||||
//Row 1 (Heading)
|
// Row 1 (Heading)
|
||||||
xml.writeStartElement("table:table-header-rows");
|
xml.writeStartElement("table:table-header-rows");
|
||||||
xml.writeStartElement("table:table-row");
|
xml.writeStartElement("table:table-row");
|
||||||
|
|
||||||
const QString P4_style = QStringLiteral("P4");
|
const QString P4_style = QStringLiteral("P4");
|
||||||
const QString P5_style = QStringLiteral("P5");
|
const QString P5_style = QStringLiteral("P5");
|
||||||
//Cells (column names, headings)
|
// Cells (column names, headings)
|
||||||
writeCell(xml, "rs_5f_table.A1", P4_style, Odt::text(Odt::rollingstock));
|
writeCell(xml, "rs_5f_table.A1", P4_style, Odt::text(Odt::rollingstock));
|
||||||
writeCell(xml, "rs_5f_table.A1", P4_style, Odt::text(Odt::jobNr));
|
writeCell(xml, "rs_5f_table.A1", P4_style, Odt::text(Odt::jobNr));
|
||||||
writeCell(xml, "rs_5f_table.A1", P4_style, Odt::text(Odt::jobStopPlatf));
|
writeCell(xml, "rs_5f_table.A1", P4_style, Odt::text(Odt::jobStopPlatf));
|
||||||
writeCell(xml, "rs_5f_table.A1", P4_style, Odt::text(m_mode == SessionRSMode::StartOfSession ? Odt::departure : Odt::arrival));
|
writeCell(xml, "rs_5f_table.A1", P4_style,
|
||||||
writeCell(xml, "rs_5f_table.E1", P4_style, Odt::text(m_order == SessionRSOrder::ByStation ? Odt::genericRSOwner : Odt::station));
|
Odt::text(m_mode == SessionRSMode::StartOfSession ? Odt::departure : Odt::arrival));
|
||||||
|
writeCell(xml, "rs_5f_table.E1", P4_style,
|
||||||
|
Odt::text(m_order == SessionRSOrder::ByStation ? Odt::genericRSOwner : Odt::station));
|
||||||
|
|
||||||
xml.writeEndElement(); //end of row
|
xml.writeEndElement(); // end of row
|
||||||
xml.writeEndElement(); //header section
|
xml.writeEndElement(); // header section
|
||||||
|
|
||||||
//Fill the table
|
// Fill the table
|
||||||
for(; it != q_getSessionRS.end(); ++it)
|
for (; it != q_getSessionRS.end(); ++it)
|
||||||
{
|
{
|
||||||
auto rs = *it;
|
auto rs = *it;
|
||||||
QTime time = rs.get<QTime>(0); //Departure or arrival
|
QTime time = rs.get<QTime>(0); // Departure or arrival
|
||||||
|
|
||||||
//db_id stationOrOwnerId = rs.get<db_id>(1);
|
// db_id stationOrOwnerId = rs.get<db_id>(1);
|
||||||
QString name = rs.get<QString>(2); //Name of the station or owner
|
QString name = rs.get<QString>(2); // Name of the station or owner
|
||||||
db_id parentId = rs.get<db_id>(3); //ownerOrStation (opposite of stationOrOwner)
|
db_id parentId = rs.get<db_id>(3); // ownerOrStation (opposite of stationOrOwner)
|
||||||
|
|
||||||
//db_id rsId = rs.get<db_id>(4);
|
// db_id rsId = rs.get<db_id>(4);
|
||||||
int number = rs.get<int>(5);
|
int number = rs.get<int>(5);
|
||||||
sqlite3_stmt *stmt = q_getSessionRS.stmt();
|
sqlite3_stmt *stmt = q_getSessionRS.stmt();
|
||||||
int modelNameLen = sqlite3_column_bytes(stmt, 6);
|
int modelNameLen = sqlite3_column_bytes(stmt, 6);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 6));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 6));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 7);
|
int modelSuffixLen = sqlite3_column_bytes(stmt, 7);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 7));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 7));
|
||||||
RsType type = RsType(rs.get<int>(8));
|
RsType type = RsType(rs.get<int>(8));
|
||||||
|
|
||||||
QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix, modelSuffixLen, type);
|
QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||||
|
modelSuffixLen, type);
|
||||||
|
|
||||||
QString platform = rs.get<QString>(9);
|
QString platform = rs.get<QString>(9);
|
||||||
if(platform.isEmpty())
|
if (platform.isEmpty())
|
||||||
platform = rs.get<QString>(10); //Use out gate to get track name
|
platform = rs.get<QString>(10); // Use out gate to get track name
|
||||||
|
|
||||||
db_id jobId = rs.get<db_id>(11);
|
db_id jobId = rs.get<db_id>(11);
|
||||||
JobCategory jobCat = JobCategory(rs.get<int>(12));
|
JobCategory jobCat = JobCategory(rs.get<int>(12));
|
||||||
|
|
||||||
if(parentId != lastParentId)
|
if (parentId != lastParentId)
|
||||||
{
|
{
|
||||||
xml.writeEndElement(); //table:table
|
xml.writeEndElement(); // table:table
|
||||||
return parentId;
|
return parentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeStartElement("table:table-row"); //start new row
|
xml.writeStartElement("table:table-row"); // start new row
|
||||||
|
|
||||||
writeCell(xml, "rs_5f_table.A2", P5_style, rsName);
|
writeCell(xml, "rs_5f_table.A2", P5_style, rsName);
|
||||||
writeCell(xml, "rs_5f_table.A2", P5_style, JobCategoryName::jobName(jobId, jobCat));
|
writeCell(xml, "rs_5f_table.A2", P5_style, JobCategoryName::jobName(jobId, jobCat));
|
||||||
|
@ -312,18 +311,18 @@ db_id SessionRSWriter::writeTable(QXmlStreamWriter &xml, const QString& parentNa
|
||||||
writeCell(xml, "rs_5f_table.A2", P5_style, time.toString("HH:mm"));
|
writeCell(xml, "rs_5f_table.A2", P5_style, time.toString("HH:mm"));
|
||||||
writeCell(xml, "rs_5f_table.E2", P5_style, name);
|
writeCell(xml, "rs_5f_table.E2", P5_style, name);
|
||||||
|
|
||||||
xml.writeEndElement(); //end of row
|
xml.writeEndElement(); // end of row
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeEndElement(); //table:table
|
xml.writeEndElement(); // table:table
|
||||||
|
|
||||||
return 0; //End of document, no more tables
|
return 0; // End of document, no more tables
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionRSWriter::writeContent(QXmlStreamWriter &xml)
|
void SessionRSWriter::writeContent(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
it = q_getSessionRS.begin();
|
it = q_getSessionRS.begin();
|
||||||
if(it == q_getSessionRS.end())
|
if (it == q_getSessionRS.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lastParentId = (*it).get<db_id>(3);
|
lastParentId = (*it).get<db_id>(3);
|
||||||
|
@ -334,7 +333,7 @@ void SessionRSWriter::writeContent(QXmlStreamWriter &xml)
|
||||||
QString name = q_getParentName.getRows().get<QString>(0);
|
QString name = q_getParentName.getRows().get<QString>(0);
|
||||||
q_getParentName.reset();
|
q_getParentName.reset();
|
||||||
|
|
||||||
//Write Station or Rollingstock Owner name
|
// Write Station or Rollingstock Owner name
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "P1");
|
xml.writeAttribute("text:style-name", "P1");
|
||||||
xml.writeCharacters(name);
|
xml.writeCharacters(name);
|
||||||
|
@ -342,7 +341,7 @@ void SessionRSWriter::writeContent(QXmlStreamWriter &xml)
|
||||||
|
|
||||||
lastParentId = writeTable(xml, name);
|
lastParentId = writeTable(xml, name);
|
||||||
|
|
||||||
//Add some space
|
// Add some space
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "P1");
|
xml.writeAttribute("text:style-name", "P1");
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
@ -351,8 +350,10 @@ void SessionRSWriter::writeContent(QXmlStreamWriter &xml)
|
||||||
|
|
||||||
QString SessionRSWriter::generateTitle() const
|
QString SessionRSWriter::generateTitle() const
|
||||||
{
|
{
|
||||||
QString title = Odt::text(Odt::rsSessionTitle).arg(
|
QString title =
|
||||||
Odt::text(m_order == SessionRSOrder::ByStation ? Odt::genericRSOwner : Odt::station),
|
Odt::text(Odt::rsSessionTitle)
|
||||||
Odt::text(m_mode == SessionRSMode::StartOfSession ? Odt::rsSessionStart : Odt::rsSessionEnd));
|
.arg(Odt::text(m_order == SessionRSOrder::ByStation ? Odt::genericRSOwner : Odt::station),
|
||||||
|
Odt::text(m_mode == SessionRSMode::StartOfSession ? Odt::rsSessionStart
|
||||||
|
: Odt::rsSessionEnd));
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
|
|
||||||
static void writeStyles(QXmlStreamWriter &xml);
|
static void writeStyles(QXmlStreamWriter &xml);
|
||||||
|
|
||||||
db_id writeTable(QXmlStreamWriter& xml, const QString& parentName);
|
db_id writeTable(QXmlStreamWriter &xml, const QString &parentName);
|
||||||
|
|
||||||
void writeContent(QXmlStreamWriter &xml);
|
void writeContent(QXmlStreamWriter &xml);
|
||||||
|
|
||||||
|
|
|
@ -30,46 +30,48 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
//first == true for the first time the stop is writter
|
// first == true for the first time the stop is writter
|
||||||
//the second time it should be false to skip the repetition of Arrival, Crossings, Passings
|
// the second time it should be false to skip the repetition of Arrival, Crossings, Passings
|
||||||
void StationWriter::insertStop(QXmlStreamWriter &xml, const Stop& stop, bool first, bool transit)
|
void StationWriter::insertStop(QXmlStreamWriter &xml, const Stop &stop, bool first, bool transit)
|
||||||
{
|
{
|
||||||
const QString P3_style = "P3";
|
const QString P3_style = "P3";
|
||||||
|
|
||||||
//Row
|
// Row
|
||||||
xml.writeStartElement("table:table-row");
|
xml.writeStartElement("table:table-row");
|
||||||
|
|
||||||
//Cells, hide Arrival the second time
|
// Cells, hide Arrival the second time
|
||||||
if(first)
|
if (first)
|
||||||
{
|
{
|
||||||
//Arrival in bold, if transit bold + italic
|
// Arrival in bold, if transit bold + italic
|
||||||
writeCell(xml, "stationtable.A2", transit ? "P5" : "P4", stop.arrival.toString("HH:mm"));
|
writeCell(xml, "stationtable.A2", transit ? "P5" : "P4", stop.arrival.toString("HH:mm"));
|
||||||
|
|
||||||
//Departure, if transit don't repeat it
|
// Departure, if transit don't repeat it
|
||||||
writeCell(xml, "stationtable.A2", P3_style, transit ? "-/-" : stop.departure.toString("HH:mm"));
|
writeCell(xml, "stationtable.A2", P3_style,
|
||||||
|
transit ? "-/-" : stop.departure.toString("HH:mm"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
writeCell(xml, "stationtable.A2", P3_style, QString()); //Don't repeat Arrival
|
writeCell(xml, "stationtable.A2", P3_style, QString()); // Don't repeat Arrival
|
||||||
writeCell(xml, "stationtable.A2", "P4", stop.departure.toString("HH:mm")); //Departure in bold
|
writeCell(xml, "stationtable.A2", "P4",
|
||||||
|
stop.departure.toString("HH:mm")); // Departure in bold
|
||||||
}
|
}
|
||||||
|
|
||||||
//Job N
|
// Job N
|
||||||
writeCell(xml, "stationtable.A2", P3_style, JobCategoryName::jobName(stop.jobId, stop.jobCat));
|
writeCell(xml, "stationtable.A2", P3_style, JobCategoryName::jobName(stop.jobId, stop.jobCat));
|
||||||
writeCell(xml, "stationtable.A2", P3_style, stop.platform); //Platform
|
writeCell(xml, "stationtable.A2", P3_style, stop.platform); // Platform
|
||||||
|
|
||||||
//From Previous Station, write only first time
|
// From Previous Station, write only first time
|
||||||
writeCell(xml, "stationtable.A2", P3_style, first ? stop.prevSt : QString());
|
writeCell(xml, "stationtable.A2", P3_style, first ? stop.prevSt : QString());
|
||||||
writeCell(xml, "stationtable.A2", P3_style, stop.nextSt);
|
writeCell(xml, "stationtable.A2", P3_style, stop.nextSt);
|
||||||
|
|
||||||
if(!first)
|
if (!first)
|
||||||
{
|
{
|
||||||
//Fill with empty cells, needed to keep the order
|
// Fill with empty cells, needed to keep the order
|
||||||
writeCell(xml, "stationtable.A2", P3_style, QString()); //Rollingstock
|
writeCell(xml, "stationtable.A2", P3_style, QString()); // Rollingstock
|
||||||
writeCell(xml, "stationtable.A2", P3_style, QString()); //Crossings
|
writeCell(xml, "stationtable.A2", P3_style, QString()); // Crossings
|
||||||
writeCell(xml, "stationtable.A2", P3_style, QString()); //Passings
|
writeCell(xml, "stationtable.A2", P3_style, QString()); // Passings
|
||||||
|
|
||||||
//Notes, description, repaeat to user the arrival to better link the 2 rows
|
// Notes, description, repaeat to user the arrival to better link the 2 rows
|
||||||
writeCell(xml, "stationtable.L2", P3_style, stop.arrival.toString("HH:mm"));
|
writeCell(xml, "stationtable.L2", P3_style, stop.arrival.toString("HH:mm"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +99,8 @@ StationWriter::StationWriter(database &db) :
|
||||||
q_selectPassings(mDb, "SELECT stops.id,stops.job_id,jobs.category"
|
q_selectPassings(mDb, "SELECT stops.id,stops.job_id,jobs.category"
|
||||||
" FROM stops"
|
" FROM stops"
|
||||||
" JOIN jobs ON jobs.id=stops.job_id"
|
" JOIN jobs ON jobs.id=stops.job_id"
|
||||||
" WHERE stops.station_id=? AND stops.departure>=? AND stops.arrival<=? AND stops.job_id<>?"),
|
" WHERE stops.station_id=? AND stops.departure>=? AND stops.arrival<=? "
|
||||||
|
"AND stops.job_id<>?"),
|
||||||
q_getStopCouplings(mDb, "SELECT coupling.rs_id,"
|
q_getStopCouplings(mDb, "SELECT coupling.rs_id,"
|
||||||
"rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
"rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
||||||
" FROM coupling"
|
" FROM coupling"
|
||||||
|
@ -105,22 +108,21 @@ StationWriter::StationWriter(database &db) :
|
||||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||||
" WHERE coupling.stop_id=? AND coupling.operation=?")
|
" WHERE coupling.stop_id=? AND coupling.operation=?")
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: common styles with JobWriter should go in common
|
// TODO: common styles with JobWriter should go in common
|
||||||
void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
{
|
{
|
||||||
/* Style: stationtable
|
/* Style: stationtable
|
||||||
*
|
*
|
||||||
* Type: table
|
* Type: table
|
||||||
* Display name: Station Table
|
* Display name: Station Table
|
||||||
* Align: center
|
* Align: center
|
||||||
* Width: 20.0cm
|
* Width: 20.0cm
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* - StationWriter: station sheet main table showing jobs that stop in this station
|
* - StationWriter: station sheet main table showing jobs that stop in this station
|
||||||
*/
|
*/
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:family", "table");
|
xml.writeAttribute("style:family", "table");
|
||||||
xml.writeAttribute("style:name", "stationtable");
|
xml.writeAttribute("style:name", "stationtable");
|
||||||
|
@ -129,20 +131,20 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("style:shadow", "none");
|
xml.writeAttribute("style:shadow", "none");
|
||||||
xml.writeAttribute("table:align", "center");
|
xml.writeAttribute("table:align", "center");
|
||||||
xml.writeAttribute("style:width", "20.0cm");
|
xml.writeAttribute("style:width", "20.0cm");
|
||||||
xml.writeEndElement(); //style:table-properties
|
xml.writeEndElement(); // style:table-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
//stationtable columns
|
// stationtable columns
|
||||||
writeColumnStyle(xml, "stationtable.A", "1.74cm"); //1 Arrival
|
writeColumnStyle(xml, "stationtable.A", "1.74cm"); // 1 Arrival
|
||||||
writeColumnStyle(xml, "stationtable.B", "1.80cm"); //2 Departure
|
writeColumnStyle(xml, "stationtable.B", "1.80cm"); // 2 Departure
|
||||||
writeColumnStyle(xml, "stationtable.C", "1.93cm"); //3 Job N
|
writeColumnStyle(xml, "stationtable.C", "1.93cm"); // 3 Job N
|
||||||
writeColumnStyle(xml, "stationtable.D", "1.00cm"); //4 Platform (Platf)
|
writeColumnStyle(xml, "stationtable.D", "1.00cm"); // 4 Platform (Platf)
|
||||||
writeColumnStyle(xml, "stationtable.E", "3.09cm"); //5 From (Previous Station)
|
writeColumnStyle(xml, "stationtable.E", "3.09cm"); // 5 From (Previous Station)
|
||||||
writeColumnStyle(xml, "stationtable.F", "3.11cm"); //6 To (Next Station)
|
writeColumnStyle(xml, "stationtable.F", "3.11cm"); // 6 To (Next Station)
|
||||||
writeColumnStyle(xml, "stationtable.G", "3.00cm"); //7 Rollingstock
|
writeColumnStyle(xml, "stationtable.G", "3.00cm"); // 7 Rollingstock
|
||||||
writeColumnStyle(xml, "stationtable.H", "2.10cm"); //8 Crossings
|
writeColumnStyle(xml, "stationtable.H", "2.10cm"); // 8 Crossings
|
||||||
writeColumnStyle(xml, "stationtable.I", "2.10cm"); //9 Passings
|
writeColumnStyle(xml, "stationtable.I", "2.10cm"); // 9 Passings
|
||||||
writeColumnStyle(xml, "stationtable.L", "2.21cm"); //10 Description
|
writeColumnStyle(xml, "stationtable.L", "2.21cm"); // 10 Description
|
||||||
|
|
||||||
/* Style: stationtable.A1
|
/* Style: stationtable.A1
|
||||||
*
|
*
|
||||||
|
@ -165,8 +167,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: stationtable.L1
|
/* Style: stationtable.L1
|
||||||
*
|
*
|
||||||
|
@ -186,8 +188,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("fo:padding", "0.097cm");
|
xml.writeAttribute("fo:padding", "0.097cm");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: stationtable.A2
|
/* Style: stationtable.A2
|
||||||
*
|
*
|
||||||
|
@ -210,8 +212,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-top", "none");
|
xml.writeAttribute("fo:border-top", "none");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style: stationtable.L2
|
/* Style: stationtable.L2
|
||||||
*
|
*
|
||||||
|
@ -234,8 +236,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeAttribute("fo:border-top", "none");
|
xml.writeAttribute("fo:border-top", "none");
|
||||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||||
xml.writeAttribute("style:vertical-align", "middle");
|
xml.writeAttribute("style:vertical-align", "middle");
|
||||||
xml.writeEndElement(); //style:table-cell-properties
|
xml.writeEndElement(); // style:table-cell-properties
|
||||||
xml.writeEndElement(); //style
|
xml.writeEndElement(); // style
|
||||||
|
|
||||||
/* Style P2
|
/* Style P2
|
||||||
* type: paragraph
|
* type: paragraph
|
||||||
|
@ -253,14 +255,14 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "center");
|
xml.writeAttribute("fo:text-align", "center");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "13pt");
|
xml.writeAttribute("fo:font-size", "13pt");
|
||||||
xml.writeAttribute("fo:font-weight", "bold");
|
xml.writeAttribute("fo:font-weight", "bold");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
/* Style P3
|
/* Style P3
|
||||||
* type: paragraph
|
* type: paragraph
|
||||||
|
@ -277,15 +279,15 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "center");
|
xml.writeAttribute("fo:text-align", "center");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "10pt");
|
xml.writeAttribute("fo:font-size", "10pt");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
|
|
||||||
//P5 - Bold, Italics, for Transits
|
// P5 - Bold, Italics, for Transits
|
||||||
/* Style P5
|
/* Style P5
|
||||||
* type: paragraph
|
* type: paragraph
|
||||||
* text-align: center
|
* text-align: center
|
||||||
|
@ -294,7 +296,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
* font-style: italic
|
* font-style: italic
|
||||||
*
|
*
|
||||||
* Usages:
|
* Usages:
|
||||||
* - stationtable table: Arrival for transit jobs (Normal stops have bold Arrival, transits have Bold + Italic)
|
* - stationtable table: Arrival for transit jobs (Normal stops have bold Arrival, transits have
|
||||||
|
* Bold + Italic)
|
||||||
*/
|
*/
|
||||||
xml.writeStartElement("style:style");
|
xml.writeStartElement("style:style");
|
||||||
xml.writeAttribute("style:family", "paragraph");
|
xml.writeAttribute("style:family", "paragraph");
|
||||||
|
@ -303,20 +306,20 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
||||||
xml.writeStartElement("style:paragraph-properties");
|
xml.writeStartElement("style:paragraph-properties");
|
||||||
xml.writeAttribute("fo:text-align", "center");
|
xml.writeAttribute("fo:text-align", "center");
|
||||||
xml.writeAttribute("style:justify-single-word", "false");
|
xml.writeAttribute("style:justify-single-word", "false");
|
||||||
xml.writeEndElement(); //style:paragraph-properties
|
xml.writeEndElement(); // style:paragraph-properties
|
||||||
|
|
||||||
xml.writeStartElement("style:text-properties");
|
xml.writeStartElement("style:text-properties");
|
||||||
xml.writeAttribute("fo:font-size", "12pt");
|
xml.writeAttribute("fo:font-size", "12pt");
|
||||||
xml.writeAttribute("fo:font-weight", "bold");
|
xml.writeAttribute("fo:font-weight", "bold");
|
||||||
xml.writeAttribute("fo:font-style", "italic");
|
xml.writeAttribute("fo:font-style", "italic");
|
||||||
xml.writeEndElement(); //style:text-properties
|
xml.writeEndElement(); // style:text-properties
|
||||||
|
|
||||||
xml.writeEndElement(); //style:style
|
xml.writeEndElement(); // style:style
|
||||||
}
|
}
|
||||||
|
|
||||||
void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString *stNameOut)
|
void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString *stNameOut)
|
||||||
{
|
{
|
||||||
QMap<QTime, Stop> stops; //Order by Departure ASC
|
QMap<QTime, Stop> stops; // Order by Departure ASC
|
||||||
|
|
||||||
query q_getStName(mDb, "SELECT name,short_name FROM stations WHERE id=?");
|
query q_getStName(mDb, "SELECT name,short_name FROM stations WHERE id=?");
|
||||||
|
|
||||||
|
@ -328,71 +331,71 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
QString stationName;
|
QString stationName;
|
||||||
QString shortName;
|
QString shortName;
|
||||||
q_getStName.bind(1, stationId);
|
q_getStName.bind(1, stationId);
|
||||||
if(q_getStName.step() == SQLITE_ROW)
|
if (q_getStName.step() == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
auto r = q_getStName.getRows();
|
auto r = q_getStName.getRows();
|
||||||
stationName = r.get<QString>(0);
|
stationName = r.get<QString>(0);
|
||||||
shortName = r.get<QString>(1);
|
shortName = r.get<QString>(1);
|
||||||
}
|
}
|
||||||
q_getStName.reset();
|
q_getStName.reset();
|
||||||
if(stNameOut)
|
if (stNameOut)
|
||||||
*stNameOut = stationName;
|
*stNameOut = stationName;
|
||||||
|
|
||||||
QString stationNameStr = stationName;
|
QString stationNameStr = stationName;
|
||||||
if(!shortName.isEmpty())
|
if (!shortName.isEmpty())
|
||||||
{
|
{
|
||||||
stationNameStr.append(QLatin1String(" ("));
|
stationNameStr.append(QLatin1String(" ("));
|
||||||
stationNameStr.append(shortName);
|
stationNameStr.append(shortName);
|
||||||
stationNameStr.append(')');
|
stationNameStr.append(')');
|
||||||
}
|
}
|
||||||
|
|
||||||
//Title
|
// Title
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "P1");
|
xml.writeAttribute("text:style-name", "P1");
|
||||||
xml.writeCharacters(Odt::text(Odt::stationPageTitle).arg(stationNameStr));
|
xml.writeCharacters(Odt::text(Odt::stationPageTitle).arg(stationNameStr));
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
|
||||||
//Vertical space
|
// Vertical space
|
||||||
xml.writeStartElement("text:p");
|
xml.writeStartElement("text:p");
|
||||||
xml.writeAttribute("text:style-name", "P1");
|
xml.writeAttribute("text:style-name", "P1");
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
|
|
||||||
//stationtable
|
// stationtable
|
||||||
xml.writeStartElement("table:table");
|
xml.writeStartElement("table:table");
|
||||||
//xml.writeAttribute("table:name", "stationtable");
|
// xml.writeAttribute("table:name", "stationtable");
|
||||||
xml.writeAttribute("table:style-name", "stationtable");
|
xml.writeAttribute("table:style-name", "stationtable");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Arrival
|
xml.writeEmptyElement("table:table-column"); // Arrival
|
||||||
xml.writeAttribute("table:style-name", "stationtable.A");
|
xml.writeAttribute("table:style-name", "stationtable.A");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Departure
|
xml.writeEmptyElement("table:table-column"); // Departure
|
||||||
xml.writeAttribute("table:style-name", "stationtable.B");
|
xml.writeAttribute("table:style-name", "stationtable.B");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Job N
|
xml.writeEmptyElement("table:table-column"); // Job N
|
||||||
xml.writeAttribute("table:style-name", "stationtable.C");
|
xml.writeAttribute("table:style-name", "stationtable.C");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Platform (Bin)
|
xml.writeEmptyElement("table:table-column"); // Platform (Bin)
|
||||||
xml.writeAttribute("table:style-name", "stationtable.D");
|
xml.writeAttribute("table:style-name", "stationtable.D");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Comes From
|
xml.writeEmptyElement("table:table-column"); // Comes From
|
||||||
xml.writeAttribute("table:style-name", "stationtable.E");
|
xml.writeAttribute("table:style-name", "stationtable.E");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Goes To
|
xml.writeEmptyElement("table:table-column"); // Goes To
|
||||||
xml.writeAttribute("table:style-name", "stationtable.F");
|
xml.writeAttribute("table:style-name", "stationtable.F");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Rollingstock
|
xml.writeEmptyElement("table:table-column"); // Rollingstock
|
||||||
xml.writeAttribute("table:style-name", "stationtable.G");
|
xml.writeAttribute("table:style-name", "stationtable.G");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Crossings
|
xml.writeEmptyElement("table:table-column"); // Crossings
|
||||||
xml.writeAttribute("table:style-name", "stationtable.H");
|
xml.writeAttribute("table:style-name", "stationtable.H");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Passings
|
xml.writeEmptyElement("table:table-column"); // Passings
|
||||||
xml.writeAttribute("table:style-name", "stationtable.I");
|
xml.writeAttribute("table:style-name", "stationtable.I");
|
||||||
|
|
||||||
xml.writeEmptyElement("table:table-column"); //Notes
|
xml.writeEmptyElement("table:table-column"); // Notes
|
||||||
xml.writeAttribute("table:style-name", "stationtable.L");
|
xml.writeAttribute("table:style-name", "stationtable.L");
|
||||||
|
|
||||||
//Row 1 (Heading)
|
// Row 1 (Heading)
|
||||||
xml.writeStartElement("table:table-header-rows");
|
xml.writeStartElement("table:table-header-rows");
|
||||||
xml.writeStartElement("table:table-row");
|
xml.writeStartElement("table:table-row");
|
||||||
|
|
||||||
|
@ -405,54 +408,55 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
writeCell(xml, "stationtable.A1", "P2", Odt::text(Odt::rollingstock));
|
writeCell(xml, "stationtable.A1", "P2", Odt::text(Odt::rollingstock));
|
||||||
writeCell(xml, "stationtable.A1", "P2", Odt::text(Odt::jobStopCrossShort));
|
writeCell(xml, "stationtable.A1", "P2", Odt::text(Odt::jobStopCrossShort));
|
||||||
writeCell(xml, "stationtable.A1", "P2", Odt::text(Odt::jobStopPassingsShort));
|
writeCell(xml, "stationtable.A1", "P2", Odt::text(Odt::jobStopPassingsShort));
|
||||||
writeCell(xml, "stationtable.L1", "P2", Odt::text(Odt::notes)); //Description
|
writeCell(xml, "stationtable.L1", "P2", Odt::text(Odt::notes)); // Description
|
||||||
|
|
||||||
xml.writeEndElement(); //end of row
|
xml.writeEndElement(); // end of row
|
||||||
xml.writeEndElement(); //header section
|
xml.writeEndElement(); // header section
|
||||||
|
|
||||||
//Stops
|
// Stops
|
||||||
q_getJobsByStation.bind(1, stationId);
|
q_getJobsByStation.bind(1, stationId);
|
||||||
for(auto r : q_getJobsByStation)
|
for (auto r : q_getJobsByStation)
|
||||||
{
|
{
|
||||||
db_id stopId = r.get<db_id>(0);
|
db_id stopId = r.get<db_id>(0);
|
||||||
Stop stop;
|
Stop stop;
|
||||||
stop.jobId = r.get<db_id>(1);
|
stop.jobId = r.get<db_id>(1);
|
||||||
stop.jobCat = JobCategory(r.get<int>(2));
|
stop.jobCat = JobCategory(r.get<int>(2));
|
||||||
stop.arrival = r.get<QTime>(3);
|
stop.arrival = r.get<QTime>(3);
|
||||||
stop.departure = r.get<QTime>(4);
|
stop.departure = r.get<QTime>(4);
|
||||||
const int stopType = r.get<int>(5);
|
const int stopType = r.get<int>(5);
|
||||||
stop.description = r.get<QString>(6);
|
stop.description = r.get<QString>(6);
|
||||||
|
|
||||||
stop.platform = r.get<QString>(7);
|
stop.platform = r.get<QString>(7);
|
||||||
if(stop.platform.isEmpty())
|
if (stop.platform.isEmpty())
|
||||||
stop.platform = r.get<QString>(8); //Use out gate to get track name
|
stop.platform = r.get<QString>(8); // Use out gate to get track name
|
||||||
|
|
||||||
utils::Side entranceSide = utils::Side(r.get<int>(9));
|
utils::Side entranceSide = utils::Side(r.get<int>(9));
|
||||||
utils::Side exitSide = utils::Side(r.get<int>(10));
|
utils::Side exitSide = utils::Side(r.get<int>(10));
|
||||||
|
|
||||||
if(entranceSide == exitSide && r.column_type(9) != SQLITE_NULL && r.column_type(10) != SQLITE_NULL)
|
if (entranceSide == exitSide && r.column_type(9) != SQLITE_NULL
|
||||||
|
&& r.column_type(10) != SQLITE_NULL)
|
||||||
{
|
{
|
||||||
//Train enters and leaves from same track side, add reversal to description
|
// Train enters and leaves from same track side, add reversal to description
|
||||||
QString descr2 = Odt::text(Odt::jobReverseDirection);
|
QString descr2 = Odt::text(Odt::jobReverseDirection);
|
||||||
if(!stop.description.isEmpty())
|
if (!stop.description.isEmpty())
|
||||||
descr2.append('\n'); //Separate from manually set description
|
descr2.append('\n'); // Separate from manually set description
|
||||||
descr2.append(stop.description);
|
descr2.append(stop.description);
|
||||||
stop.description = descr2;
|
stop.description = descr2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool isTransit = stopType == 1;
|
const bool isTransit = stopType == 1;
|
||||||
|
|
||||||
//BIG TODO: if this is First or Last stop of this job
|
// BIG TODO: if this is First or Last stop of this job
|
||||||
//then it shouldn't be duplicated in 2 rows
|
// then it shouldn't be duplicated in 2 rows
|
||||||
|
|
||||||
//Comes from station
|
// Comes from station
|
||||||
q_getPrevStop.bind(1, stop.jobId);
|
q_getPrevStop.bind(1, stop.jobId);
|
||||||
q_getPrevStop.bind(2, stop.arrival);
|
q_getPrevStop.bind(2, stop.arrival);
|
||||||
if(q_getPrevStop.step() == SQLITE_ROW)
|
if (q_getPrevStop.step() == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
db_id prevStId = q_getPrevStop.getRows().get<db_id>(1);
|
db_id prevStId = q_getPrevStop.getRows().get<db_id>(1);
|
||||||
q_getStName.bind(1, prevStId);
|
q_getStName.bind(1, prevStId);
|
||||||
if(q_getStName.step() == SQLITE_ROW)
|
if (q_getStName.step() == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
stop.prevSt = q_getStName.getRows().get<QString>(0);
|
stop.prevSt = q_getStName.getRows().get<QString>(0);
|
||||||
}
|
}
|
||||||
|
@ -460,14 +464,14 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
}
|
}
|
||||||
q_getPrevStop.reset();
|
q_getPrevStop.reset();
|
||||||
|
|
||||||
//Goes to station
|
// Goes to station
|
||||||
q_getNextStop.bind(1, stop.jobId);
|
q_getNextStop.bind(1, stop.jobId);
|
||||||
q_getNextStop.bind(2, stop.arrival);
|
q_getNextStop.bind(2, stop.arrival);
|
||||||
if(q_getNextStop.step() == SQLITE_ROW)
|
if (q_getNextStop.step() == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
db_id nextStId = q_getNextStop.getRows().get<db_id>(1);
|
db_id nextStId = q_getNextStop.getRows().get<db_id>(1);
|
||||||
q_getStName.bind(1, nextStId);
|
q_getStName.bind(1, nextStId);
|
||||||
if(q_getStName.step() == SQLITE_ROW)
|
if (q_getStName.step() == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
stop.nextSt = q_getStName.getRows().get<QString>(0);
|
stop.nextSt = q_getStName.getRows().get<QString>(0);
|
||||||
}
|
}
|
||||||
|
@ -475,62 +479,60 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
}
|
}
|
||||||
q_getNextStop.reset();
|
q_getNextStop.reset();
|
||||||
|
|
||||||
for(auto s = stops.begin(); s != stops.end(); /*nothing because of erase*/)
|
for (auto s = stops.begin(); s != stops.end(); /*nothing because of erase*/)
|
||||||
{
|
{
|
||||||
//If 's' departs after 'stop' arrives then skip 's' for now
|
// If 's' departs after 'stop' arrives then skip 's' for now
|
||||||
if(s->departure >= stop.arrival)
|
if (s->departure >= stop.arrival)
|
||||||
{
|
{
|
||||||
++s;
|
++s;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//'s' departs before 'stop' arrives so we
|
//'s' departs before 'stop' arrives so we
|
||||||
//insert it again to remind station master (IT: capostazione)
|
// insert it again to remind station master (IT: capostazione)
|
||||||
insertStop(xml, s.value(), false, false);
|
insertStop(xml, s.value(), false, false);
|
||||||
xml.writeEndElement(); //table-row
|
xml.writeEndElement(); // table-row
|
||||||
|
|
||||||
//Then remove from the list otherwise it gets inserted infinite times
|
// Then remove from the list otherwise it gets inserted infinite times
|
||||||
s = stops.erase(s);
|
s = stops.erase(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fill with basic data
|
// Fill with basic data
|
||||||
insertStop(xml, stop, true, isTransit);
|
insertStop(xml, stop, true, isTransit);
|
||||||
|
|
||||||
//First time this stop is written, fill with other data
|
// First time this stop is written, fill with other data
|
||||||
|
|
||||||
//Rollingstock
|
// Rollingstock
|
||||||
sqlite3_stmt *stmt = q_getStopCouplings.stmt();
|
sqlite3_stmt *stmt = q_getStopCouplings.stmt();
|
||||||
writeCellListStart(xml, "stationtable.A2", "P3");
|
writeCellListStart(xml, "stationtable.A2", "P3");
|
||||||
|
|
||||||
//Coupled rollingstock
|
// Coupled rollingstock
|
||||||
bool firstCoupRow = true;
|
bool firstCoupRow = true;
|
||||||
q_getStopCouplings.bind(1, stopId);
|
q_getStopCouplings.bind(1, stopId);
|
||||||
q_getStopCouplings.bind(2, int(RsOp::Coupled));
|
q_getStopCouplings.bind(2, int(RsOp::Coupled));
|
||||||
for(auto coup : q_getStopCouplings)
|
for (auto coup : q_getStopCouplings)
|
||||||
{
|
{
|
||||||
//db_id rsId = coup.get<db_id>(0);
|
// db_id rsId = coup.get<db_id>(0);
|
||||||
|
|
||||||
int number = coup.get<int>(1);
|
int number = coup.get<int>(1);
|
||||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 3));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 3));
|
||||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||||
|
|
||||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||||
number,
|
modelSuffix, modelSuffixLen, type);
|
||||||
modelSuffix, modelSuffixLen,
|
|
||||||
type);
|
|
||||||
|
|
||||||
if(firstCoupRow)
|
if (firstCoupRow)
|
||||||
{
|
{
|
||||||
firstCoupRow = false;
|
firstCoupRow = false;
|
||||||
//Use bold font
|
// Use bold font
|
||||||
xml.writeStartElement("text:span");
|
xml.writeStartElement("text:span");
|
||||||
xml.writeAttribute("text:style-name", "T1");
|
xml.writeAttribute("text:style-name", "T1");
|
||||||
xml.writeCharacters(Odt::text(Odt::CoupledAbbr));
|
xml.writeCharacters(Odt::text(Odt::CoupledAbbr));
|
||||||
xml.writeEndElement(); //test:span
|
xml.writeEndElement(); // test:span
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
@ -538,38 +540,36 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
}
|
}
|
||||||
q_getStopCouplings.reset();
|
q_getStopCouplings.reset();
|
||||||
|
|
||||||
//Unoupled rollingstock
|
// Unoupled rollingstock
|
||||||
bool firstUncoupRow = true;
|
bool firstUncoupRow = true;
|
||||||
q_getStopCouplings.bind(1, stopId);
|
q_getStopCouplings.bind(1, stopId);
|
||||||
q_getStopCouplings.bind(2, int(RsOp::Uncoupled));
|
q_getStopCouplings.bind(2, int(RsOp::Uncoupled));
|
||||||
for(auto coup : q_getStopCouplings)
|
for (auto coup : q_getStopCouplings)
|
||||||
{
|
{
|
||||||
//db_id rsId = coup.get<db_id>(0);
|
// db_id rsId = coup.get<db_id>(0);
|
||||||
|
|
||||||
int number = coup.get<int>(1);
|
int number = coup.get<int>(1);
|
||||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||||
|
|
||||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 3));
|
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 3));
|
||||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||||
|
|
||||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||||
number,
|
modelSuffix, modelSuffixLen, type);
|
||||||
modelSuffix, modelSuffixLen,
|
|
||||||
type);
|
|
||||||
|
|
||||||
if(firstUncoupRow)
|
if (firstUncoupRow)
|
||||||
{
|
{
|
||||||
if(!firstCoupRow) //Not first row, there were coupled rs
|
if (!firstCoupRow) // Not first row, there were coupled rs
|
||||||
xml.writeEmptyElement("text:line-break"); //Separate from coupled
|
xml.writeEmptyElement("text:line-break"); // Separate from coupled
|
||||||
firstUncoupRow = false;
|
firstUncoupRow = false;
|
||||||
|
|
||||||
//Use bold font
|
// Use bold font
|
||||||
xml.writeStartElement("text:span");
|
xml.writeStartElement("text:span");
|
||||||
xml.writeAttribute("text:style-name", "T1");
|
xml.writeAttribute("text:style-name", "T1");
|
||||||
xml.writeCharacters(Odt::text(Odt::UncoupledAbbr));
|
xml.writeCharacters(Odt::text(Odt::UncoupledAbbr));
|
||||||
xml.writeEndElement(); //test:span
|
xml.writeEndElement(); // test:span
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
@ -578,7 +578,7 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
q_getStopCouplings.reset();
|
q_getStopCouplings.reset();
|
||||||
writeCellListEnd(xml);
|
writeCellListEnd(xml);
|
||||||
|
|
||||||
//Crossings, Passings
|
// Crossings, Passings
|
||||||
QVector<JobEntry> passings;
|
QVector<JobEntry> passings;
|
||||||
JobStopDirectionHelper dirHelper(mDb);
|
JobStopDirectionHelper dirHelper(mDb);
|
||||||
utils::Side myDirection = dirHelper.getStopOutSide(stopId);
|
utils::Side myDirection = dirHelper.getStopOutSide(stopId);
|
||||||
|
@ -589,24 +589,24 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
q_selectPassings.bind(4, stop.jobId);
|
q_selectPassings.bind(4, stop.jobId);
|
||||||
firstCoupRow = true;
|
firstCoupRow = true;
|
||||||
|
|
||||||
//Incroci
|
// Incroci
|
||||||
writeCellListStart(xml, "stationtable.A2", "P3");
|
writeCellListStart(xml, "stationtable.A2", "P3");
|
||||||
for(auto pass : q_selectPassings)
|
for (auto pass : q_selectPassings)
|
||||||
{
|
{
|
||||||
db_id otherStopId = pass.get<db_id>(0);
|
db_id otherStopId = pass.get<db_id>(0);
|
||||||
db_id otherJobId = pass.get<db_id>(1);
|
db_id otherJobId = pass.get<db_id>(1);
|
||||||
JobCategory otherJobCat = JobCategory(pass.get<int>(2));
|
JobCategory otherJobCat = JobCategory(pass.get<int>(2));
|
||||||
|
|
||||||
//QTime otherArr = pass.get<QTime>(3);
|
// QTime otherArr = pass.get<QTime>(3);
|
||||||
//QTime otherDep = pass.get<QTime>(4);
|
// QTime otherDep = pass.get<QTime>(4);
|
||||||
|
|
||||||
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
||||||
|
|
||||||
if(myDirection == otherDir)
|
if (myDirection == otherDir)
|
||||||
passings.append({otherJobId, otherJobCat});
|
passings.append({otherJobId, otherJobCat});
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(firstCoupRow)
|
if (firstCoupRow)
|
||||||
firstCoupRow = false;
|
firstCoupRow = false;
|
||||||
else
|
else
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
@ -616,12 +616,12 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
q_selectPassings.reset();
|
q_selectPassings.reset();
|
||||||
writeCellListEnd(xml);
|
writeCellListEnd(xml);
|
||||||
|
|
||||||
//Passings
|
// Passings
|
||||||
firstCoupRow = true;
|
firstCoupRow = true;
|
||||||
writeCellListStart(xml, "stationtable.A2", "P3");
|
writeCellListStart(xml, "stationtable.A2", "P3");
|
||||||
for(auto entry : passings)
|
for (auto entry : passings)
|
||||||
{
|
{
|
||||||
if(firstCoupRow)
|
if (firstCoupRow)
|
||||||
firstCoupRow = false;
|
firstCoupRow = false;
|
||||||
else
|
else
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
@ -629,66 +629,66 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
||||||
}
|
}
|
||||||
writeCellListEnd(xml);
|
writeCellListEnd(xml);
|
||||||
|
|
||||||
//Description, Notes
|
// Description, Notes
|
||||||
writeCellListStart(xml, "stationtable.L2", "P3");
|
writeCellListStart(xml, "stationtable.L2", "P3");
|
||||||
bool needsLineBreak = false;
|
bool needsLineBreak = false;
|
||||||
if(isTransit)
|
if (isTransit)
|
||||||
{
|
{
|
||||||
xml.writeCharacters(Odt::text(Odt::jobStopIsTransit));
|
xml.writeCharacters(Odt::text(Odt::jobStopIsTransit));
|
||||||
needsLineBreak = true;
|
needsLineBreak = true;
|
||||||
}
|
}
|
||||||
if(stop.prevSt.isEmpty())
|
if (stop.prevSt.isEmpty())
|
||||||
{
|
{
|
||||||
if(needsLineBreak)
|
if (needsLineBreak)
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
|
||||||
//This is Origin (First stop), use Bold font
|
// This is Origin (First stop), use Bold font
|
||||||
xml.writeStartElement("text:span");
|
xml.writeStartElement("text:span");
|
||||||
xml.writeAttribute("text:style-name", "T1");
|
xml.writeAttribute("text:style-name", "T1");
|
||||||
xml.writeCharacters(Odt::text(Odt::jobStopIsFirst));
|
xml.writeCharacters(Odt::text(Odt::jobStopIsFirst));
|
||||||
xml.writeEndElement(); //test:span
|
xml.writeEndElement(); // test:span
|
||||||
needsLineBreak = true;
|
needsLineBreak = true;
|
||||||
}
|
}
|
||||||
if(!stop.description.isEmpty())
|
if (!stop.description.isEmpty())
|
||||||
{
|
{
|
||||||
if(needsLineBreak) //go to new line after 'Transit' word
|
if (needsLineBreak) // go to new line after 'Transit' word
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
|
|
||||||
//Split in lines
|
// Split in lines
|
||||||
int lastIdx = 0;
|
int lastIdx = 0;
|
||||||
while(true)
|
while (true)
|
||||||
{
|
{
|
||||||
int idx = stop.description.indexOf('\n', lastIdx);
|
int idx = stop.description.indexOf('\n', lastIdx);
|
||||||
QString line = stop.description.mid(lastIdx, idx == -1 ? idx : idx - lastIdx);
|
QString line = stop.description.mid(lastIdx, idx == -1 ? idx : idx - lastIdx);
|
||||||
xml.writeCharacters(line.simplified());
|
xml.writeCharacters(line.simplified());
|
||||||
if(idx < 0)
|
if (idx < 0)
|
||||||
break; //Last line
|
break; // Last line
|
||||||
lastIdx = idx + 1;
|
lastIdx = idx + 1;
|
||||||
xml.writeEmptyElement("text:line-break");
|
xml.writeEmptyElement("text:line-break");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeCellListEnd(xml);
|
writeCellListEnd(xml);
|
||||||
|
|
||||||
xml.writeEndElement(); //table-row
|
xml.writeEndElement(); // table-row
|
||||||
|
|
||||||
if(!isTransit && !stop.prevSt.isEmpty() && !stop.nextSt.isEmpty())
|
if (!isTransit && !stop.prevSt.isEmpty() && !stop.nextSt.isEmpty())
|
||||||
{
|
{
|
||||||
//If it is a normal stop (not a transit and not first stop or last stop)
|
// If it is a normal stop (not a transit and not first stop or last stop)
|
||||||
//insert two rows: one for arrival and another
|
// insert two rows: one for arrival and another
|
||||||
//that reminds the station master (capostazione)
|
// that reminds the station master (capostazione)
|
||||||
//the departure of that train
|
// the departure of that train
|
||||||
//In order to achieve this we put the stop in a list
|
// In order to achieve this we put the stop in a list
|
||||||
//and write it again before another arrival (see above)
|
// and write it again before another arrival (see above)
|
||||||
stops.insert(stop.departure, stop);
|
stops.insert(stop.departure, stop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q_getJobsByStation.reset();
|
q_getJobsByStation.reset();
|
||||||
|
|
||||||
for(const Stop& s : stops)
|
for (const Stop &s : stops)
|
||||||
{
|
{
|
||||||
insertStop(xml, s, false, false);
|
insertStop(xml, s, false, false);
|
||||||
xml.writeEndElement(); //table-row
|
xml.writeEndElement(); // table-row
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.writeEndElement(); //stationtable end
|
xml.writeEndElement(); // stationtable end
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,9 @@ class QXmlStreamWriter;
|
||||||
class StationWriter
|
class StationWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StationWriter(database& db);
|
StationWriter(database &db);
|
||||||
|
|
||||||
static void writeStationAutomaticStyles(QXmlStreamWriter& xml);
|
static void writeStationAutomaticStyles(QXmlStreamWriter &xml);
|
||||||
|
|
||||||
void writeStation(QXmlStreamWriter &xml, db_id stationId, QString *stNameOut = nullptr);
|
void writeStation(QXmlStreamWriter &xml, db_id stationId, QString *stNameOut = nullptr);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ private:
|
||||||
JobCategory jobCat;
|
JobCategory jobCat;
|
||||||
};
|
};
|
||||||
|
|
||||||
void insertStop(QXmlStreamWriter &xml, const Stop& stop, bool first, bool transit);
|
void insertStop(QXmlStreamWriter &xml, const Stop &stop, bool first, bool transit);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
database &mDb;
|
database &mDb;
|
||||||
|
|
|
@ -30,7 +30,6 @@ JobSheetExport::JobSheetExport(db_id jobId, JobCategory cat) :
|
||||||
m_jobId(jobId),
|
m_jobId(jobId),
|
||||||
m_jobCat(cat)
|
m_jobCat(cat)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JobSheetExport::write()
|
void JobSheetExport::write()
|
||||||
|
@ -38,27 +37,27 @@ void JobSheetExport::write()
|
||||||
qDebug() << "TEMP:" << odt.dir.path();
|
qDebug() << "TEMP:" << odt.dir.path();
|
||||||
odt.initDocument();
|
odt.initDocument();
|
||||||
|
|
||||||
//styles.xml font declarations
|
// styles.xml font declarations
|
||||||
odt.stylesXml.writeStartElement("office:font-face-decls");
|
odt.stylesXml.writeStartElement("office:font-face-decls");
|
||||||
writeLiberationFontFaces(odt.stylesXml);
|
writeLiberationFontFaces(odt.stylesXml);
|
||||||
odt.stylesXml.writeEndElement(); //office:font-face-decls
|
odt.stylesXml.writeEndElement(); // office:font-face-decls
|
||||||
|
|
||||||
//Content font declarations
|
// Content font declarations
|
||||||
odt.contentXml.writeStartElement("office:font-face-decls");
|
odt.contentXml.writeStartElement("office:font-face-decls");
|
||||||
writeLiberationFontFaces(odt.contentXml);
|
writeLiberationFontFaces(odt.contentXml);
|
||||||
odt.contentXml.writeEndElement(); //office:font-face-decls
|
odt.contentXml.writeEndElement(); // office:font-face-decls
|
||||||
|
|
||||||
//Content Automatic styles
|
// Content Automatic styles
|
||||||
odt.contentXml.writeStartElement("office:automatic-styles");
|
odt.contentXml.writeStartElement("office:automatic-styles");
|
||||||
JobWriter::writeJobAutomaticStyles(odt.contentXml);
|
JobWriter::writeJobAutomaticStyles(odt.contentXml);
|
||||||
|
|
||||||
//Styles
|
// Styles
|
||||||
odt.stylesXml.writeStartElement("office:styles");
|
odt.stylesXml.writeStartElement("office:styles");
|
||||||
writeCommonStyles(odt.stylesXml);
|
writeCommonStyles(odt.stylesXml);
|
||||||
JobWriter::writeJobStyles(odt.stylesXml);
|
JobWriter::writeJobStyles(odt.stylesXml);
|
||||||
odt.stylesXml.writeEndElement();
|
odt.stylesXml.writeEndElement();
|
||||||
|
|
||||||
//Body
|
// Body
|
||||||
odt.startBody();
|
odt.startBody();
|
||||||
|
|
||||||
JobWriter w(Session->m_Db);
|
JobWriter w(Session->m_Db);
|
||||||
|
|
|
@ -24,14 +24,13 @@
|
||||||
|
|
||||||
#include "utils/types.h"
|
#include "utils/types.h"
|
||||||
|
|
||||||
|
|
||||||
class JobSheetExport
|
class JobSheetExport
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
JobSheetExport(db_id jobId, JobCategory cat);
|
JobSheetExport(db_id jobId, JobCategory cat);
|
||||||
|
|
||||||
void write();
|
void write();
|
||||||
void save(const QString& fileName);
|
void save(const QString &fileName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OdtDocument odt;
|
OdtDocument odt;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue