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);
|
||||
|
||||
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");
|
||||
switch (type) {
|
||||
switch (type)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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());
|
||||
|
@ -73,114 +79,124 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
|
|||
|
||||
void setupLogger()
|
||||
{
|
||||
//const QString path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
// const QString path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
QString path = MeetingSession::appDataPath;
|
||||
if(qApp->arguments().contains("--test"))
|
||||
path = qApp->applicationDirPath(); //If testing use exe folder instead of AppData: see MeetingSession
|
||||
if (qApp->arguments().contains("--test"))
|
||||
path = qApp->applicationDirPath(); // If testing use exe folder instead of AppData:
|
||||
// see MeetingSession
|
||||
|
||||
QFile *logFile = gLogFile();
|
||||
|
||||
logFile->setFileName(path + QStringLiteral("/logs/mrtp_log.log"));
|
||||
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);
|
||||
dir.mkdir("logs");
|
||||
logFile->open(QFile::WriteOnly | QFile::Append | QFile::Text);
|
||||
}
|
||||
if(logFile->isOpen())
|
||||
if (logFile->isOpen())
|
||||
{
|
||||
defaultHandler = qInstallMessageHandler(myMessageOutput);
|
||||
}
|
||||
else {
|
||||
qDebug() << "Cannot open Log file:" << logFile->fileName() << "Error:" << logFile->errorString();
|
||||
else
|
||||
{
|
||||
qDebug() << "Cannot open Log file:" << logFile->fileName()
|
||||
<< "Error:" << logFile->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef GLOBAL_TRY_CATCH
|
||||
try{
|
||||
try
|
||||
{
|
||||
#endif
|
||||
|
||||
QApplication app(argc, argv);
|
||||
QApplication::setOrganizationName(AppCompany);
|
||||
//QApplication::setApplicationName(AppProduct);
|
||||
QApplication::setApplicationDisplayName(AppDisplayName);
|
||||
QApplication::setApplicationVersion(AppVersion);
|
||||
QApplication app(argc, argv);
|
||||
QApplication::setOrganizationName(AppCompany);
|
||||
// QApplication::setApplicationName(AppProduct);
|
||||
QApplication::setApplicationDisplayName(AppDisplayName);
|
||||
QApplication::setApplicationVersion(AppVersion);
|
||||
|
||||
MeetingSession::locateAppdata();
|
||||
MeetingSession::locateAppdata();
|
||||
|
||||
setupLogger();
|
||||
setupLogger();
|
||||
|
||||
qDebug() << QApplication::applicationDisplayName()
|
||||
<< "Version:" << QApplication::applicationVersion()
|
||||
<< "Built:" << AppBuildDate
|
||||
<< "Website: " << AppProjectWebSite;
|
||||
qDebug() << "Qt:" << QT_VERSION_STR;
|
||||
qDebug() << "Sqlite:" << sqlite3_libversion() << " DB Format: V" << FormatVersion;
|
||||
qDebug() << QDateTime::currentDateTime().toString("dd/MM/yyyy HH:mm");
|
||||
qDebug() << QApplication::applicationDisplayName()
|
||||
<< "Version:" << QApplication::applicationVersion() << "Built:" << AppBuildDate
|
||||
<< "Website: " << AppProjectWebSite;
|
||||
qDebug() << "Qt:" << QT_VERSION_STR;
|
||||
qDebug() << "Sqlite:" << sqlite3_libversion() << " DB Format: V" << FormatVersion;
|
||||
qDebug() << QDateTime::currentDateTime().toString("dd/MM/yyyy HH:mm");
|
||||
|
||||
//Check SQLite thread safety
|
||||
int val = sqlite3_threadsafe();
|
||||
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())
|
||||
// Check SQLite thread safety
|
||||
int val = sqlite3_threadsafe();
|
||||
if (val != 1)
|
||||
{
|
||||
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();
|
||||
QThreadPool::globalInstance()->waitForDone(1000);
|
||||
DB_Error err = Session->closeDB();
|
||||
MainWindow w;
|
||||
w.showNormal();
|
||||
w.resize(800, 600);
|
||||
w.showMaximized();
|
||||
|
||||
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();
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}catch(const char* str)
|
||||
}
|
||||
catch (const char *str)
|
||||
{
|
||||
qDebug() << "Exception:" << str;
|
||||
throw;
|
||||
}catch(const std::string& str)
|
||||
}
|
||||
catch (const std::string &str)
|
||||
{
|
||||
qDebug() << "Exception:" << str.c_str();
|
||||
throw;
|
||||
}catch(sqlite3pp::database_error& e)
|
||||
}
|
||||
catch (sqlite3pp::database_error &e)
|
||||
{
|
||||
qDebug() << "Exception:" << e.what();
|
||||
throw;
|
||||
}catch(std::exception& e)
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
qDebug() << "Exception:" << e.what();
|
||||
throw;
|
||||
}catch(...)
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qDebug() << "Caught generic exception";
|
||||
throw;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
#include "viewmanager/viewmanager.h"
|
||||
|
||||
|
||||
#include "jobs/jobeditor/jobpatheditor.h"
|
||||
#include <QDockWidget>
|
||||
|
||||
|
@ -52,7 +51,7 @@
|
|||
#include "printing/wizard/printwizard.h"
|
||||
|
||||
#ifdef ENABLE_USER_QUERY
|
||||
#include "sqlconsole/sqlconsole.h"
|
||||
# include "sqlconsole/sqlconsole.h"
|
||||
#endif
|
||||
|
||||
#include <QActionGroup>
|
||||
|
@ -61,10 +60,10 @@
|
|||
#include "searchbox/searchresultmodel.h"
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
#include "backgroundmanager/backgroundmanager.h"
|
||||
#include "backgroundmanager/backgroundresultpanel.h"
|
||||
#include "jobs/jobs_checker/crossing/jobcrossingchecker.h"
|
||||
#include "rollingstock/rs_checker/rscheckermanager.h"
|
||||
# include "backgroundmanager/backgroundmanager.h"
|
||||
# include "backgroundmanager/backgroundresultpanel.h"
|
||||
# include "jobs/jobs_checker/crossing/jobcrossingchecker.h"
|
||||
# include "rollingstock/rs_checker/rscheckermanager.h"
|
||||
#endif // ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include "propertiesdialog.h"
|
||||
|
@ -100,47 +99,47 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
ui->setupUi(this);
|
||||
ui->actionAbout->setText(tr("About %1").arg(qApp->applicationDisplayName()));
|
||||
|
||||
auto viewMgr = Session->getViewManager();
|
||||
auto viewMgr = Session->getViewManager();
|
||||
viewMgr->m_mainWidget = this;
|
||||
|
||||
auto graphMgr = viewMgr->getLineGraphMgr();
|
||||
auto graphMgr = viewMgr->getLineGraphMgr();
|
||||
connect(graphMgr, &LineGraphManager::jobSelected, this, &MainWindow::onJobSelected);
|
||||
|
||||
//view = graphMgr->getView();
|
||||
// view = graphMgr->getView();
|
||||
view = new LineGraphWidget(this);
|
||||
|
||||
//Welcome label
|
||||
// Welcome label
|
||||
welcomeLabel = new QLabel(this);
|
||||
welcomeLabel->setTextFormat(Qt::RichText);
|
||||
welcomeLabel->setAlignment(Qt::AlignCenter);
|
||||
welcomeLabel->setFont(QFont("Arial", 15));
|
||||
welcomeLabel->setObjectName("WelcomeLabel");
|
||||
|
||||
//JobPathEditor dock
|
||||
jobEditor = new JobPathEditor(this);
|
||||
// JobPathEditor dock
|
||||
jobEditor = new JobPathEditor(this);
|
||||
viewMgr->jobEditor = jobEditor;
|
||||
jobDock = new QDockWidget(tr("Job Editor"), this);
|
||||
jobDock = new QDockWidget(tr("Job Editor"), this);
|
||||
jobDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||
jobDock->setWidget(jobEditor);
|
||||
jobDock->installEventFilter(this); //NOTE: see MainWindow::eventFilter() below
|
||||
jobDock->installEventFilter(this); // NOTE: see MainWindow::eventFilter() below
|
||||
|
||||
addDockWidget(Qt::RightDockWidgetArea, jobDock);
|
||||
ui->menuView->addAction(jobDock->toggleViewAction());
|
||||
connect(jobDock->toggleViewAction(), &QAction::triggered, jobEditor, &JobPathEditor::show);
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
//Background Errors dock
|
||||
// Background Errors dock
|
||||
BackgroundResultPanel *resPanel = new BackgroundResultPanel(this);
|
||||
resPanelDock = new QDockWidget(tr("Errors"), this);
|
||||
resPanelDock = new QDockWidget(tr("Errors"), this);
|
||||
resPanelDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
|
||||
resPanelDock->setWidget(resPanel);
|
||||
resPanelDock->installEventFilter(this); //NOTE: see eventFilter() below
|
||||
resPanelDock->installEventFilter(this); // NOTE: see eventFilter() below
|
||||
|
||||
addDockWidget(Qt::BottomDockWidgetArea, resPanelDock);
|
||||
ui->menuView->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);
|
||||
Session->getBackgroundManager()->addChecker(jobCrossingChecker);
|
||||
|
||||
|
@ -148,22 +147,24 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
Session->getBackgroundManager()->addChecker(rsChecker);
|
||||
#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::BottomLeftCorner, Qt::LeftDockWidgetArea);
|
||||
|
||||
//Search Box
|
||||
// Search Box
|
||||
SearchResultModel *searchModel = new SearchResultModel(Session->m_Db, this);
|
||||
searchEdit = new CustomCompletionLineEdit(searchModel, this);
|
||||
searchEdit = new CustomCompletionLineEdit(searchModel, this);
|
||||
searchEdit->setMinimumWidth(300);
|
||||
searchEdit->setMinimumHeight(25);
|
||||
searchEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
searchEdit->setPlaceholderText(tr("Find"));
|
||||
searchEdit->setClearButtonEnabled(true);
|
||||
connect(searchEdit, &CustomCompletionLineEdit::completionDone, this, &MainWindow::onJobSearchItemSelected);
|
||||
connect(searchModel, &SearchResultModel::resultsReady, this, &MainWindow::onJobSearchResultsReady);
|
||||
connect(searchEdit, &CustomCompletionLineEdit::completionDone, this,
|
||||
&MainWindow::onJobSearchItemSelected);
|
||||
connect(searchModel, &SearchResultModel::resultsReady, this,
|
||||
&MainWindow::onJobSearchResultsReady);
|
||||
|
||||
QWidget* spacer = new QWidget();
|
||||
QWidget *spacer = new QWidget();
|
||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
ui->mainToolBar->addWidget(spacer);
|
||||
ui->mainToolBar->addWidget(searchEdit);
|
||||
|
@ -172,12 +173,11 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
setCentralWidgetMode(CentralWidgetMode::StartPageMode);
|
||||
|
||||
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]->setVisible(false);
|
||||
connect(recentFileActs[i], &QAction::triggered,
|
||||
this, &MainWindow::onOpenRecent);
|
||||
connect(recentFileActs[i], &QAction::triggered, this, &MainWindow::onOpenRecent);
|
||||
|
||||
recentFilesMenu->addAction(recentFileActs[i]);
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
|
||||
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::segmentRemoved, 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->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->action_JobsMgr, &QAction::triggered, this, &MainWindow::onJobsManager);
|
||||
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->actionRemoveJob, &QAction::triggered, this, &MainWindow::onRemoveJob);
|
||||
|
@ -263,16 +265,22 @@ void MainWindow::setup_actions()
|
|||
|
||||
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->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, []()
|
||||
ui->actionNext_Job_Segment->setToolTip(
|
||||
tr("Hold shift and click to go to <b>last</b> job stop."));
|
||||
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);
|
||||
});
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
@ -284,15 +292,14 @@ void MainWindow::about()
|
|||
msgBox->setWindowTitle(tr("About %1").arg(qApp->applicationDisplayName()));
|
||||
|
||||
const QString translatedText =
|
||||
tr(
|
||||
"<h3>%1</h3>"
|
||||
"<p>This program makes it easier to deal with timetables and trains.</p>"
|
||||
"<p>Version: <b>%2</b></p>"
|
||||
"<p>Built: %3</p>"
|
||||
"<p>Website: <a href='%4'>%4</a></p>")
|
||||
.arg(qApp->applicationDisplayName(), qApp->applicationVersion(),
|
||||
QDate::fromString(AppBuildDate, QLatin1String("MMM dd yyyy")).toString("dd/MM/yyyy"),
|
||||
AppProjectWebSite);
|
||||
tr("<h3>%1</h3>"
|
||||
"<p>This program makes it easier to deal with timetables and trains.</p>"
|
||||
"<p>Version: <b>%2</b></p>"
|
||||
"<p>Built: %3</p>"
|
||||
"<p>Website: <a href='%4'>%4</a></p>")
|
||||
.arg(qApp->applicationDisplayName(), qApp->applicationVersion(),
|
||||
QDate::fromString(AppBuildDate, QLatin1String("MMM dd yyyy")).toString("dd/MM/yyyy"),
|
||||
AppProjectWebSite);
|
||||
|
||||
msgBox->setTextFormat(Qt::RichText);
|
||||
msgBox->setText(translatedText);
|
||||
|
@ -309,15 +316,14 @@ void MainWindow::onOpen()
|
|||
#endif
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
if(Session->getBackgroundManager()->isRunning())
|
||||
if (Session->getBackgroundManager()->isRunning())
|
||||
{
|
||||
int ret = QMessageBox::warning(this,
|
||||
tr("Backgroung Task"),
|
||||
tr("Background task for checking rollingstock errors is still running.\n"
|
||||
"Do you want to cancel it?"),
|
||||
QMessageBox::Yes, QMessageBox::No,
|
||||
QMessageBox::Yes);
|
||||
if(ret == QMessageBox::Yes)
|
||||
int ret = QMessageBox::warning(
|
||||
this, tr("Backgroung Task"),
|
||||
tr("Background task for checking rollingstock errors is still running.\n"
|
||||
"Do you want to cancel it?"),
|
||||
QMessageBox::Yes, QMessageBox::No, QMessageBox::Yes);
|
||||
if (ret == QMessageBox::Yes)
|
||||
Session->getBackgroundManager()->abortAllTasks();
|
||||
else
|
||||
return;
|
||||
|
@ -335,22 +341,21 @@ void MainWindow::onOpen()
|
|||
filters << FileFormats::tr(FileFormats::allFiles);
|
||||
dlg->setNameFilters(filters);
|
||||
|
||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
||||
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||
return;
|
||||
|
||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||
|
||||
if(fileName.isEmpty())
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
RecentDirStore::setPath(directory_key::session, fileName);
|
||||
|
||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
|
||||
if(!QThreadPool::globalInstance()->waitForDone(2000))
|
||||
if (!QThreadPool::globalInstance()->waitForDone(2000))
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Background Tasks"),
|
||||
QMessageBox::warning(this, tr("Background Tasks"),
|
||||
tr("Some background tasks are still running.\n"
|
||||
"The file was not opened. Try again."));
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
@ -362,10 +367,10 @@ void MainWindow::onOpen()
|
|||
loadFile(fileName);
|
||||
}
|
||||
|
||||
void MainWindow::loadFile(const QString& fileName)
|
||||
void MainWindow::loadFile(const QString &fileName)
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
if(fileName.isEmpty())
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
qDebug() << "Loading:" << fileName;
|
||||
|
@ -376,86 +381,91 @@ void MainWindow::loadFile(const QString& fileName)
|
|||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
if(err == DB_Error::FormatTooOld)
|
||||
if (err == DB_Error::FormatTooOld)
|
||||
{
|
||||
int but = QMessageBox::warning(this, tr("Version is old"),
|
||||
tr("This file was created by an older version of %1.\n"
|
||||
"Opening it without conversion might not work and even crash the application.\n"
|
||||
"Do you want to open it anyway?").arg(qApp->applicationDisplayName()),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if(but == QMessageBox::Yes)
|
||||
int but = QMessageBox::warning(
|
||||
this, tr("Version is old"),
|
||||
tr("This file was created by an older version of %1.\n"
|
||||
"Opening it without conversion might not work and even crash the application.\n"
|
||||
"Do you want to open it anyway?")
|
||||
.arg(qApp->applicationDisplayName()),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (but == QMessageBox::Yes)
|
||||
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"),
|
||||
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"
|
||||
"Do you want to open it anyway?").arg(qApp->applicationDisplayName()),
|
||||
"You should update the application first. Opening "
|
||||
"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);
|
||||
if(but == QMessageBox::Yes)
|
||||
if (but == QMessageBox::Yes)
|
||||
err = Session->openDB(fileName, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(err == DB_Error::DbBusyWhenClosing)
|
||||
if (err == DB_Error::DbBusyWhenClosing)
|
||||
showCloseWarning();
|
||||
|
||||
if(err != DB_Error::NoError)
|
||||
if (err != DB_Error::NoError)
|
||||
return;
|
||||
|
||||
setCurrentFile(fileName);
|
||||
|
||||
//Fake we are coming from Start Page
|
||||
//Otherwise we cannot show the first line
|
||||
// Fake we are coming from Start Page
|
||||
// Otherwise we cannot show the first line
|
||||
m_mode = CentralWidgetMode::StartPageMode;
|
||||
checkLineNumber();
|
||||
|
||||
|
||||
if(!Session->checkImportRSTablesEmpty())
|
||||
if (!Session->checkImportRSTablesEmpty())
|
||||
{
|
||||
//Probably the application crashed before finishing RS importation
|
||||
//Give user choice to resume it or discard
|
||||
// Probably the application crashed before finishing RS importation
|
||||
// Give user choice to resume it or discard
|
||||
|
||||
OwningQPointer<QMessageBox> msgBox = new QMessageBox(
|
||||
QMessageBox::Warning,
|
||||
tr("RS Import"),
|
||||
tr("There is some rollingstock import data left in this file. "
|
||||
"Probably the application has crashed!<br>"
|
||||
"Before deleting it would you like to resume importation?<br>"
|
||||
"<i>(Sorry for the crash, would you like to contact me and share information about it?)</i>"),
|
||||
QMessageBox::NoButton, this);
|
||||
OwningQPointer<QMessageBox> msgBox =
|
||||
new QMessageBox(QMessageBox::Warning, tr("RS Import"),
|
||||
tr("There is some rollingstock import data left in this file. "
|
||||
"Probably the application has crashed!<br>"
|
||||
"Before deleting it would you like to resume importation?<br>"
|
||||
"<i>(Sorry for the crash, would you like to contact me and share "
|
||||
"information about it?)</i>"),
|
||||
QMessageBox::NoButton, this);
|
||||
auto resumeBut = msgBox->addButton(tr("Resume importation"), QMessageBox::YesRole);
|
||||
msgBox->addButton(tr("Just delete it"), QMessageBox::NoRole);
|
||||
msgBox->setDefaultButton(resumeBut);
|
||||
msgBox->setTextFormat(Qt::RichText);
|
||||
|
||||
msgBox->exec();
|
||||
if(!msgBox)
|
||||
if (!msgBox)
|
||||
return;
|
||||
|
||||
if(msgBox->clickedButton() == resumeBut)
|
||||
if (msgBox->clickedButton() == resumeBut)
|
||||
{
|
||||
Session->getViewManager()->resumeRSImportation();
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
Session->clearImportRSTables();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setCurrentFile(const QString& fileName)
|
||||
void MainWindow::setCurrentFile(const QString &fileName)
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
if(fileName.isEmpty())
|
||||
if (fileName.isEmpty())
|
||||
{
|
||||
setWindowFilePath(QString()); //Reset title bar
|
||||
setWindowFilePath(QString()); // Reset title bar
|
||||
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);
|
||||
|
||||
QStringList files = AppSettings.getRecentFiles();
|
||||
|
@ -472,22 +482,23 @@ void MainWindow::setCurrentFile(const QString& fileName)
|
|||
QString MainWindow::strippedName(const QString &fullFileName, bool *ok)
|
||||
{
|
||||
QFileInfo fi(fullFileName);
|
||||
if(ok) *ok = fi.exists();
|
||||
if (ok)
|
||||
*ok = fi.exists();
|
||||
return fi.fileName();
|
||||
}
|
||||
|
||||
void MainWindow::updateRecentFileActions()
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
QStringList files = AppSettings.getRecentFiles();
|
||||
QStringList files = AppSettings.getRecentFiles();
|
||||
|
||||
int numRecentFiles = qMin(files.size(), int(MaxRecentFiles));
|
||||
|
||||
for (int i = 0; i < numRecentFiles; i++)
|
||||
{
|
||||
bool ok = true;
|
||||
bool ok = true;
|
||||
QString name = strippedName(files[i], &ok);
|
||||
if(name.isEmpty() || !ok)
|
||||
if (name.isEmpty() || !ok)
|
||||
{
|
||||
files.removeAt(i);
|
||||
i--;
|
||||
|
@ -511,8 +522,8 @@ void MainWindow::updateRecentFileActions()
|
|||
void MainWindow::onOpenRecent()
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
QAction *act = qobject_cast<QAction*>(sender());
|
||||
if(!act)
|
||||
QAction *act = qobject_cast<QAction *>(sender());
|
||||
if (!act)
|
||||
return;
|
||||
|
||||
loadFile(act->data().toString());
|
||||
|
@ -527,15 +538,14 @@ void MainWindow::onNew()
|
|||
#endif
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
if(Session->getBackgroundManager()->isRunning())
|
||||
if (Session->getBackgroundManager()->isRunning())
|
||||
{
|
||||
int ret = QMessageBox::warning(this,
|
||||
tr("Backgroung Task"),
|
||||
tr("Background task for checking rollingstock errors is still running.\n"
|
||||
"Do you want to cancel it?"),
|
||||
QMessageBox::Yes, QMessageBox::No,
|
||||
QMessageBox::Yes);
|
||||
if(ret == QMessageBox::Yes)
|
||||
int ret = QMessageBox::warning(
|
||||
this, tr("Backgroung Task"),
|
||||
tr("Background task for checking rollingstock errors is still running.\n"
|
||||
"Do you want to cancel it?"),
|
||||
QMessageBox::Yes, QMessageBox::No, QMessageBox::Yes);
|
||||
if (ret == QMessageBox::Yes)
|
||||
Session->getBackgroundManager()->abortAllTasks();
|
||||
else
|
||||
return;
|
||||
|
@ -553,22 +563,21 @@ void MainWindow::onNew()
|
|||
filters << FileFormats::tr(FileFormats::allFiles);
|
||||
dlg->setNameFilters(filters);
|
||||
|
||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
||||
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||
return;
|
||||
|
||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||
|
||||
if(fileName.isEmpty())
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
RecentDirStore::setPath(directory_key::session, fileName);
|
||||
|
||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
|
||||
if(!QThreadPool::globalInstance()->waitForDone(2000))
|
||||
if (!QThreadPool::globalInstance()->waitForDone(2000))
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Background Tasks"),
|
||||
QMessageBox::warning(this, tr("Background Tasks"),
|
||||
tr("Some background tasks are still running.\n"
|
||||
"The new file was not created. Try again."));
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
@ -576,17 +585,17 @@ void MainWindow::onNew()
|
|||
}
|
||||
|
||||
QFile f(fileName);
|
||||
if(f.exists())
|
||||
if (f.exists())
|
||||
f.remove();
|
||||
|
||||
DB_Error err = Session->createNewDB(fileName);
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
if(err == DB_Error::DbBusyWhenClosing)
|
||||
if (err == DB_Error::DbBusyWhenClosing)
|
||||
showCloseWarning();
|
||||
|
||||
if(err != DB_Error::NoError)
|
||||
if (err != DB_Error::NoError)
|
||||
return;
|
||||
|
||||
setCurrentFile(fileName);
|
||||
|
@ -595,7 +604,7 @@ void MainWindow::onNew()
|
|||
|
||||
void MainWindow::onSave()
|
||||
{
|
||||
if(!Session->getViewManager()->closeEditors())
|
||||
if (!Session->getViewManager()->closeEditors())
|
||||
return;
|
||||
|
||||
Session->releaseAllSavepoints();
|
||||
|
@ -605,7 +614,7 @@ void MainWindow::onSaveCopyAs()
|
|||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
if(!Session->getViewManager()->closeEditors())
|
||||
if (!Session->getViewManager()->closeEditors())
|
||||
return;
|
||||
|
||||
OwningQPointer<QFileDialog> dlg = new QFileDialog(this, tr("Save Session Copy"));
|
||||
|
@ -619,29 +628,30 @@ void MainWindow::onSaveCopyAs()
|
|||
filters << FileFormats::tr(FileFormats::allFiles);
|
||||
dlg->setNameFilters(filters);
|
||||
|
||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
||||
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||
return;
|
||||
|
||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||
|
||||
if(fileName.isEmpty())
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
RecentDirStore::setPath(directory_key::session, fileName);
|
||||
|
||||
QFile f(fileName);
|
||||
if(f.exists())
|
||||
if (f.exists())
|
||||
f.remove();
|
||||
|
||||
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)
|
||||
qDebug() << pageCount << "/" << remaining;
|
||||
});
|
||||
|
||||
if(rc != SQLITE_OK && rc != SQLITE_DONE)
|
||||
if (rc != SQLITE_OK && rc != SQLITE_DONE)
|
||||
{
|
||||
QString errMsg = Session->m_Db.error_msg();
|
||||
qDebug() << Session->m_Db.error_code() << errMsg;
|
||||
|
@ -651,7 +661,7 @@ void MainWindow::onSaveCopyAs()
|
|||
|
||||
void MainWindow::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
if(closeSession())
|
||||
if (closeSession())
|
||||
e->accept();
|
||||
else
|
||||
e->ignore();
|
||||
|
@ -659,15 +669,14 @@ void MainWindow::closeEvent(QCloseEvent *e)
|
|||
|
||||
void MainWindow::showCloseWarning()
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Error while Closing"),
|
||||
QMessageBox::warning(this, tr("Error while Closing"),
|
||||
tr("There was an error while closing the database.\n"
|
||||
"Make sure there aren't any background tasks running and try again."));
|
||||
}
|
||||
|
||||
void MainWindow::stopCloseTimer()
|
||||
{
|
||||
if(closeTimerId)
|
||||
if (closeTimerId)
|
||||
{
|
||||
killTimer(closeTimerId);
|
||||
closeTimerId = 0;
|
||||
|
@ -701,36 +710,36 @@ void MainWindow::setCentralWidgetMode(MainWindow::CentralWidgetMode mode)
|
|||
#endif // ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
welcomeLabel->setText(
|
||||
tr("<p><b>There are no lines in this session</b></p>"
|
||||
"<p>"
|
||||
"<table align=\"center\">"
|
||||
"<tr>"
|
||||
"<td>Start by creating the railway layout for this session:</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td>"
|
||||
"<table>"
|
||||
"<tr>"
|
||||
"<td>1.</td>"
|
||||
"<td>Create stations (<b>Edit</b> > <b>Stations</b>)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td>2.</td>"
|
||||
"<td>Create railway lines (<b>Edit</b> > <b>Stations</b> > <b>Lines Tab</b>)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td>3.</td>"
|
||||
"<td>Add stations to railway lines</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td>(<b>Edit</b> > <b>Stations</b> > <b>Lines Tab</b> > <b>Edit Line</b>)</td>"
|
||||
"</tr>"
|
||||
"</table>"
|
||||
"</td>"
|
||||
"</tr>"
|
||||
"</table>"
|
||||
"</p>"));
|
||||
tr("<p><b>There are no lines in this session</b></p>"
|
||||
"<p>"
|
||||
"<table align=\"center\">"
|
||||
"<tr>"
|
||||
"<td>Start by creating the railway layout for this session:</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td>"
|
||||
"<table>"
|
||||
"<tr>"
|
||||
"<td>1.</td>"
|
||||
"<td>Create stations (<b>Edit</b> > <b>Stations</b>)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td>2.</td>"
|
||||
"<td>Create railway lines (<b>Edit</b> > <b>Stations</b> > <b>Lines Tab</b>)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td>3.</td>"
|
||||
"<td>Add stations to railway lines</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td>(<b>Edit</b> > <b>Stations</b> > <b>Lines Tab</b> > <b>Edit Line</b>)</td>"
|
||||
"</tr>"
|
||||
"</table>"
|
||||
"</td>"
|
||||
"</tr>"
|
||||
"</table>"
|
||||
"</p>"));
|
||||
break;
|
||||
}
|
||||
case CentralWidgetMode::ViewSessionMode:
|
||||
|
@ -748,37 +757,39 @@ void MainWindow::setCentralWidgetMode(MainWindow::CentralWidgetMode mode)
|
|||
|
||||
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);
|
||||
view->show();
|
||||
welcomeLabel->hide();
|
||||
}
|
||||
|
||||
//Enable Job Creation
|
||||
// Enable Job Creation
|
||||
ui->actionAddJob->setEnabled(true);
|
||||
ui->actionAddJob->setToolTip(tr("Add train job"));
|
||||
|
||||
//Update actions based on Job selection
|
||||
JobStopEntry selectedJob = Session->getViewManager()->getLineGraphMgr()->getCurrentSelectedJob();
|
||||
// Update actions based on Job selection
|
||||
JobStopEntry selectedJob =
|
||||
Session->getViewManager()->getLineGraphMgr()->getCurrentSelectedJob();
|
||||
onJobSelected(selectedJob.jobId);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(centralWidget() != welcomeLabel)
|
||||
if (centralWidget() != welcomeLabel)
|
||||
{
|
||||
takeCentralWidget(); //Remove ownership from LineGraphWidget
|
||||
takeCentralWidget(); // Remove ownership from LineGraphWidget
|
||||
setCentralWidget(welcomeLabel);
|
||||
view->hide();
|
||||
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->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);
|
||||
}
|
||||
|
||||
|
@ -799,8 +810,8 @@ void MainWindow::onProperties()
|
|||
void MainWindow::onMeetingInformation()
|
||||
{
|
||||
OwningQPointer<MeetingInformationDialog> dlg = new MeetingInformationDialog(this);
|
||||
int ret = dlg->exec();
|
||||
if(dlg && ret == QDialog::Accepted)
|
||||
int ret = dlg->exec();
|
||||
if (dlg && ret == QDialog::Accepted)
|
||||
dlg->saveData();
|
||||
}
|
||||
|
||||
|
@ -808,11 +819,11 @@ bool MainWindow::closeSession()
|
|||
{
|
||||
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();
|
||||
|
||||
|
@ -820,19 +831,19 @@ bool MainWindow::closeSession()
|
|||
return false;
|
||||
}
|
||||
|
||||
//Start a timer to try again
|
||||
// Start a timer to try again
|
||||
closeTimerId = startTimer(1500);
|
||||
return false;
|
||||
}
|
||||
|
||||
stopCloseTimer();
|
||||
|
||||
if(err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||
if (err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||
return false;
|
||||
|
||||
setCentralWidgetMode(CentralWidgetMode::StartPageMode);
|
||||
|
||||
//Reset filePath to refresh title
|
||||
// Reset filePath to refresh title
|
||||
setCurrentFile(QString());
|
||||
|
||||
return true;
|
||||
|
@ -842,7 +853,7 @@ void MainWindow::enableDBActions(bool enable)
|
|||
{
|
||||
databaseActionGroup->setEnabled(enable);
|
||||
searchEdit->setEnabled(enable);
|
||||
if(!enable)
|
||||
if (!enable)
|
||||
jobEditor->setEnabled(false);
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
@ -924,30 +935,30 @@ void MainWindow::checkLineNumber()
|
|||
{
|
||||
RailwaySegmentHelper helper(Session->m_Db);
|
||||
|
||||
bool isLine = false;
|
||||
bool isLine = false;
|
||||
db_id graphObjId = 0;
|
||||
|
||||
if(!helper.findFirstLineOrSegment(graphObjId, isLine))
|
||||
if (!helper.findFirstLineOrSegment(graphObjId, isLine))
|
||||
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);
|
||||
|
||||
//Load first line or segment
|
||||
// Load first line or segment
|
||||
view->tryLoadGraph(graphObjId,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if(e->timerId() == closeTimerId)
|
||||
if (e->timerId() == closeTimerId)
|
||||
{
|
||||
closeSession();
|
||||
return;
|
||||
|
@ -964,38 +975,32 @@ void MainWindow::onJobSelected(db_id jobId)
|
|||
ui->actionRemoveJob->setEnabled(selected);
|
||||
|
||||
QString removeJobTooltip;
|
||||
if(selected)
|
||||
if (selected)
|
||||
removeJobTooltip = tr("Remove selected Job");
|
||||
else
|
||||
removeJobTooltip = tr("First select a Job by double click on graph or type in search box");
|
||||
ui->actionRemoveJob->setToolTip(removeJobTooltip);
|
||||
}
|
||||
|
||||
//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
|
||||
//NOTE: calling directly 'QDockWidget::setFloating(false)' from inside 'eventFinter()' causes CRASH
|
||||
// so queue it. Cannot use 'QMetaObject::invokeMethod()' because it's not a slot.
|
||||
// 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
|
||||
// NOTE: calling directly 'QDockWidget::setFloating(false)' from inside 'eventFinter()' causes CRASH
|
||||
// so queue it. Cannot use 'QMetaObject::invokeMethod()' because it's not a slot.
|
||||
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]()
|
||||
{
|
||||
jobDock->setFloating(false);
|
||||
});
|
||||
QTimer::singleShot(0, jobDock, [this]() { jobDock->setFloating(false); });
|
||||
}
|
||||
}
|
||||
#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]()
|
||||
{
|
||||
resPanelDock->setFloating(false);
|
||||
});
|
||||
QTimer::singleShot(0, resPanelDock, [this]() { resPanelDock->setFloating(false); });
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_BACKGROUND_MANAGER
|
||||
|
@ -1012,10 +1017,10 @@ void MainWindow::onJobSearchItemSelected()
|
|||
{
|
||||
db_id jobId = 0;
|
||||
QString tmp;
|
||||
if(!searchEdit->getData(jobId, tmp))
|
||||
if (!searchEdit->getData(jobId, tmp))
|
||||
return;
|
||||
|
||||
searchEdit->clear(); //Clear text
|
||||
searchEdit->clear(); // Clear text
|
||||
Session->getViewManager()->requestJobSelection(jobId, true, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
void loadFile(const QString &fileName);
|
||||
|
||||
bool closeSession();
|
||||
|
||||
|
||||
private slots:
|
||||
void onStationManager();
|
||||
|
||||
|
@ -140,8 +140,11 @@ private:
|
|||
|
||||
QActionGroup *databaseActionGroup;
|
||||
|
||||
enum { MaxRecentFiles = 5 };
|
||||
QAction* recentFileActs[MaxRecentFiles];
|
||||
enum
|
||||
{
|
||||
MaxRecentFiles = 5
|
||||
};
|
||||
QAction *recentFileActs[MaxRecentFiles];
|
||||
|
||||
CentralWidgetMode m_mode;
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ PropertiesDialog::PropertiesDialog(QWidget *parent) :
|
|||
pathReadOnlyEdit->setPlaceholderText(tr("No opened file"));
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -28,19 +28,20 @@ Scope::Scope(const char *fn, const char *s, const char *e) :
|
|||
start(s),
|
||||
end(e)
|
||||
{
|
||||
qDebug().nospace().noquote()
|
||||
<< start << QByteArray(" ").repeated(stackLevel) << ">>> " << func << end;
|
||||
qDebug().nospace().noquote() << start << QByteArray(" ").repeated(stackLevel) << ">>> " << func
|
||||
<< end;
|
||||
stackLevel++;
|
||||
}
|
||||
|
||||
Scope::~Scope()
|
||||
{
|
||||
stackLevel--;
|
||||
qDebug().nospace().noquote()
|
||||
<< start << QByteArray(" ").repeated(stackLevel) << "<<< " << func << end;
|
||||
qDebug().nospace().noquote() << start << QByteArray(" ").repeated(stackLevel) << "<<< " << func
|
||||
<< 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();
|
||||
}
|
||||
|
|
|
@ -20,57 +20,52 @@
|
|||
#ifndef 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_YELLOW "\033[033m"
|
||||
#define SHELL_BLUE "\033[034m"
|
||||
|
||||
#define SHELL_RED "\033[031m"
|
||||
#define SHELL_GREEN "\033[032m"
|
||||
#define SHELL_YELLOW "\033[033m"
|
||||
#define SHELL_BLUE "\033[034m"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
//#define NO_DEBUG_CALL_TRACE
|
||||
// #define NO_DEBUG_CALL_TRACE
|
||||
|
||||
#ifndef NO_DEBUG_CALL_TRACE
|
||||
|
||||
class Scope
|
||||
{
|
||||
public:
|
||||
Scope(const char *fn, const char *s="", const char* e="");
|
||||
Scope(const char *fn, const char *s = "", const char *e = "");
|
||||
~Scope();
|
||||
|
||||
const char *func, *start, *end;
|
||||
};
|
||||
|
||||
|
||||
class ScopeTimer : Scope
|
||||
{
|
||||
public:
|
||||
ScopeTimer(const char *fn, const char *s="", const char* e="");
|
||||
ScopeTimer(const char *fn, const char *s = "", const char *e = "");
|
||||
~ScopeTimer();
|
||||
|
||||
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_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_TIME_ENTRY ScopeTimer DBG(__PRETTY_FUNCTION__)
|
||||
|
||||
#else
|
||||
# define DEBUG_ENTRY_NAME(name)
|
||||
# define DEBUG_ENTRY
|
||||
# define DEBUG_COLOR_ENTRY(color)
|
||||
# define DEBUG_IMPORTANT_ENTRY
|
||||
# define DEBUG_TIME_ENTRY
|
||||
# define DEBUG_ENTRY_NAME(name)
|
||||
# define DEBUG_ENTRY
|
||||
# define DEBUG_COLOR_ENTRY(color)
|
||||
# define DEBUG_IMPORTANT_ENTRY
|
||||
# define DEBUG_TIME_ENTRY
|
||||
#endif // NO_DEBUG_CALLTRACE
|
||||
|
||||
#endif // SCOPEDEBUG_H
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "db_metadata/metadatamanager.h"
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
#include "backgroundmanager/backgroundmanager.h"
|
||||
# include "backgroundmanager/backgroundmanager.h"
|
||||
#endif // ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include <QStandardPaths>
|
||||
|
@ -37,7 +37,7 @@
|
|||
|
||||
#include <QTranslator>
|
||||
|
||||
MeetingSession* MeetingSession::session;
|
||||
MeetingSession *MeetingSession::session;
|
||||
QString MeetingSession::appDataPath;
|
||||
const QLocale MeetingSession::embeddedLocale = QLocale(QLocale::English, QLocale::UnitedStates);
|
||||
|
||||
|
@ -54,13 +54,14 @@ MeetingSession::MeetingSession() :
|
|||
m_Db(nullptr),
|
||||
sheetExportTranslator(nullptr)
|
||||
{
|
||||
session = this; //Global singleton pointer
|
||||
session = this; // Global singleton pointer
|
||||
|
||||
QString settings_file;
|
||||
if(qApp->arguments().contains("test"))
|
||||
if (qApp->arguments().contains("test"))
|
||||
{
|
||||
//If testing use exe folder instead of AppData
|
||||
settings_file = QCoreApplication::applicationDirPath() + QStringLiteral("/mrtp_settings.ini");
|
||||
// If testing use exe folder instead of AppData
|
||||
settings_file =
|
||||
QCoreApplication::applicationDirPath() + QStringLiteral("/mrtp_settings.ini");
|
||||
}
|
||||
|
||||
loadSettings(settings_file);
|
||||
|
@ -76,7 +77,7 @@ MeetingSession::MeetingSession() :
|
|||
|
||||
MeetingSession::~MeetingSession()
|
||||
{
|
||||
//Delete sheet export translator
|
||||
// Delete sheet export translator
|
||||
setSheetExportTranslator(nullptr, sheetExportLocale);
|
||||
}
|
||||
|
||||
|
@ -90,29 +91,29 @@ DB_Error MeetingSession::openDB(const QString &str, bool ignoreVersion)
|
|||
DEBUG_ENTRY;
|
||||
|
||||
DB_Error err = closeDB();
|
||||
if(err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||
if (err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
//try{
|
||||
if(m_Db.connect(str.toUtf8(), SQLITE_OPEN_READWRITE) != SQLITE_OK)
|
||||
// try{
|
||||
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();
|
||||
return DB_Error::GenericError;
|
||||
}
|
||||
|
||||
if(!ignoreVersion)
|
||||
if (!ignoreVersion)
|
||||
{
|
||||
qint64 version = 0;
|
||||
switch (metaDataMgr->getInt64(version, MetaDataKey::FormatVersionKey))
|
||||
{
|
||||
case MetaDataKey::Result::ValueFound:
|
||||
{
|
||||
if(version < FormatVersion)
|
||||
if (version < FormatVersion)
|
||||
return DB_Error::FormatTooOld;
|
||||
else if(version > FormatVersion)
|
||||
else if (version > FormatVersion)
|
||||
return DB_Error::FormatTooNew;
|
||||
break;
|
||||
}
|
||||
|
@ -123,38 +124,38 @@ DB_Error MeetingSession::openDB(const QString &str, bool ignoreVersion)
|
|||
|
||||
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_extended_result_codes(true);
|
||||
|
||||
// }catch(const char *msg)
|
||||
// {
|
||||
// QMessageBox::warning(nullptr,
|
||||
// QObject::tr("Error"),
|
||||
// QObject::tr("Error while opening file:\n%1\n'%2'")
|
||||
// .arg(str)
|
||||
// .arg(msg));
|
||||
// throw;
|
||||
// return false;
|
||||
// }
|
||||
// catch(std::exception& e)
|
||||
// {
|
||||
// QMessageBox::warning(nullptr,
|
||||
// QObject::tr("Error"),
|
||||
// QObject::tr("Error while opening file:\n%1\n'%2'")
|
||||
// .arg(str)
|
||||
// .arg(e.what()));
|
||||
// throw;
|
||||
// return false;
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// QMessageBox::warning(nullptr,
|
||||
// QObject::tr("Error"),
|
||||
// QObject::tr("Unknown error while opening file:\n%1").arg(str));
|
||||
// throw;
|
||||
// return false;
|
||||
// }
|
||||
// }catch(const char *msg)
|
||||
// {
|
||||
// QMessageBox::warning(nullptr,
|
||||
// QObject::tr("Error"),
|
||||
// QObject::tr("Error while opening file:\n%1\n'%2'")
|
||||
// .arg(str)
|
||||
// .arg(msg));
|
||||
// throw;
|
||||
// return false;
|
||||
// }
|
||||
// catch(std::exception& e)
|
||||
// {
|
||||
// QMessageBox::warning(nullptr,
|
||||
// QObject::tr("Error"),
|
||||
// QObject::tr("Error while opening file:\n%1\n'%2'")
|
||||
// .arg(str)
|
||||
// .arg(e.what()));
|
||||
// throw;
|
||||
// return false;
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// QMessageBox::warning(nullptr,
|
||||
// QObject::tr("Error"),
|
||||
// QObject::tr("Unknown error while opening file:\n%1").arg(str));
|
||||
// throw;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
backgroundManager->handleSessionLoaded();
|
||||
|
@ -167,7 +168,7 @@ DB_Error MeetingSession::closeDB()
|
|||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
if(!m_Db.db())
|
||||
if (!m_Db.db())
|
||||
return DB_Error::DbNotOpen;
|
||||
|
||||
#ifdef SEARCHBOX_MODE_ASYNC
|
||||
|
@ -178,27 +179,27 @@ DB_Error MeetingSession::closeDB()
|
|||
backgroundManager->abortAllTasks();
|
||||
#endif
|
||||
|
||||
if(!viewManager->closeEditors())
|
||||
return DB_Error::EditorsStillOpened; //User wants to continue editing
|
||||
if (!viewManager->closeEditors())
|
||||
return DB_Error::EditorsStillOpened; // User wants to continue editing
|
||||
|
||||
//Close all graphs
|
||||
// Close all graphs
|
||||
viewManager->clearAllLineGraphs();
|
||||
|
||||
releaseAllSavepoints();
|
||||
|
||||
//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)
|
||||
//we abort closing and return. It's like nevere having closed, database is 100% working
|
||||
// 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)
|
||||
// we abort closing and return. It's like nevere having closed, database is 100% working
|
||||
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();
|
||||
|
||||
if(rc == SQLITE_BUSY)
|
||||
if (rc == SQLITE_BUSY)
|
||||
{
|
||||
return DB_Error::DbBusyWhenClosing;
|
||||
}
|
||||
//return false;
|
||||
// return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
@ -210,22 +211,24 @@ DB_Error MeetingSession::closeDB()
|
|||
return DB_Error::NoError;
|
||||
}
|
||||
|
||||
DB_Error MeetingSession::createNewDB(const QString& file)
|
||||
DB_Error MeetingSession::createNewDB(const QString &file)
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
DB_Error err = closeDB();
|
||||
if(err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||
if (err != DB_Error::NoError && err != DB_Error::DbNotOpen)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
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);
|
||||
CHECK(result);
|
||||
|
||||
//See 'openDB()'
|
||||
// See 'openDB()'
|
||||
m_Db.enable_foreign_keys(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.
|
||||
*/
|
||||
|
||||
//Tables
|
||||
// Tables
|
||||
result = m_Db.execute("CREATE TABLE rs_models ("
|
||||
"id INTEGER,"
|
||||
"name TEXT,"
|
||||
|
@ -278,81 +281,87 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
"CHECK(length(name)>0) )");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE station_tracks ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"station_id INTEGER NOT NULL,"
|
||||
"pos INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"track_length_cm INTEGER NOT NULL,"
|
||||
"platf_length_cm INTEGET NOT NULL,"
|
||||
"freight_length_cm INTEGER NOT NULL,"
|
||||
"max_axes INTEGER NOT NULL,"
|
||||
"color_rgb INTEGER,"
|
||||
"name TEXT NOT NULL,"
|
||||
"CHECK("
|
||||
" length(name)>0 AND max_axes>=2 AND track_length_cm>0"
|
||||
" 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),"
|
||||
"FOREIGN KEY (station_id) REFERENCES stations(id) ON UPDATE CASCADE ON DELETE CASCADE )");
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE station_tracks ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"station_id INTEGER NOT NULL,"
|
||||
"pos INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"track_length_cm INTEGER NOT NULL,"
|
||||
"platf_length_cm INTEGET NOT NULL,"
|
||||
"freight_length_cm INTEGER NOT NULL,"
|
||||
"max_axes INTEGER NOT NULL,"
|
||||
"color_rgb INTEGER,"
|
||||
"name TEXT NOT NULL,"
|
||||
"CHECK("
|
||||
" length(name)>0 AND max_axes>=2 AND track_length_cm>0"
|
||||
" 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),"
|
||||
"FOREIGN KEY (station_id) REFERENCES stations(id) ON UPDATE CASCADE ON DELETE CASCADE )");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE station_gates ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"station_id INTEGER NOT NULL,"
|
||||
"out_track_count INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"def_in_platf_id INTEGER,"
|
||||
"name TEXT NOT NULL,"
|
||||
"side INTEGER NOT NULL,"
|
||||
"CHECK("
|
||||
" out_track_count>0 AND (type&(1<<0) OR type&(1<<1))"
|
||||
" AND (length(name)=1 AND name BETWEEN 'A' AND 'Z')"
|
||||
")," //NOTE: see utils::GateType
|
||||
"FOREIGN KEY (station_id) REFERENCES stations(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"FOREIGN KEY(def_in_platf_id) REFERENCES station_tracks(id) ON UPDATE CASCADE ON DELETE SET NULL,"
|
||||
"UNIQUE(station_id,name) )");
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE station_gates ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"station_id INTEGER NOT NULL,"
|
||||
"out_track_count INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"def_in_platf_id INTEGER,"
|
||||
"name TEXT NOT NULL,"
|
||||
"side INTEGER NOT NULL,"
|
||||
"CHECK("
|
||||
" out_track_count>0 AND (type&(1<<0) OR type&(1<<1))"
|
||||
" AND (length(name)=1 AND name BETWEEN 'A' AND 'Z')"
|
||||
")," // NOTE: see utils::GateType
|
||||
"FOREIGN KEY (station_id) REFERENCES stations(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"FOREIGN KEY(def_in_platf_id) REFERENCES station_tracks(id) ON UPDATE CASCADE ON DELETE SET "
|
||||
"NULL,"
|
||||
"UNIQUE(station_id,name) )");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE station_gate_connections ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"track_id INTEGER NOT NULL,"
|
||||
"track_side INTEGER NOT NULL,"
|
||||
"gate_id INTEGER NOT NULL,"
|
||||
"gate_track INTEGER NOT NULL,"
|
||||
"UNIQUE(gate_id,track_id,track_side,gate_track),"
|
||||
"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 )");
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE station_gate_connections ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"track_id INTEGER NOT NULL,"
|
||||
"track_side INTEGER NOT NULL,"
|
||||
"gate_id INTEGER NOT NULL,"
|
||||
"gate_track INTEGER NOT NULL,"
|
||||
"UNIQUE(gate_id,track_id,track_side,gate_track),"
|
||||
"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);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE railway_segments ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"in_gate_id INTEGER NOT NULL,"
|
||||
"out_gate_id INTEGER NOT NULL,"
|
||||
"name TEXT,"
|
||||
"max_speed_kmh INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"distance_meters INTEGER NOT NULL,"
|
||||
"UNIQUE(in_gate_id),"
|
||||
"UNIQUE(out_gate_id),"
|
||||
"FOREIGN KEY(in_gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"FOREIGN KEY(out_gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"CHECK(in_gate_id<>out_gate_id AND"
|
||||
" max_speed_kmh>=10 AND"
|
||||
" distance_meters>=100 AND"
|
||||
" length(name)>0) )");
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE railway_segments ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"in_gate_id INTEGER NOT NULL,"
|
||||
"out_gate_id INTEGER NOT NULL,"
|
||||
"name TEXT,"
|
||||
"max_speed_kmh INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"distance_meters INTEGER NOT NULL,"
|
||||
"UNIQUE(in_gate_id),"
|
||||
"UNIQUE(out_gate_id),"
|
||||
"FOREIGN KEY(in_gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"FOREIGN KEY(out_gate_id) REFERENCES station_gates(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"CHECK(in_gate_id<>out_gate_id AND"
|
||||
" max_speed_kmh>=10 AND"
|
||||
" distance_meters>=100 AND"
|
||||
" length(name)>0) )");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE railway_connections ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"seg_id INTEGER NOT NULL,"
|
||||
"in_track INTEGER NOT NULL,"
|
||||
"out_track INTEGER NOT NULL,"
|
||||
"UNIQUE(seg_id,in_track),"
|
||||
"UNIQUE(seg_id,out_track),"
|
||||
"FOREIGN KEY(seg_id) REFERENCES railway_segments(id) ON UPDATE CASCADE ON DELETE RESTRICT )");
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE railway_connections ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"seg_id INTEGER NOT NULL,"
|
||||
"in_track INTEGER NOT NULL,"
|
||||
"out_track INTEGER NOT NULL,"
|
||||
"UNIQUE(seg_id,in_track),"
|
||||
"UNIQUE(seg_id,out_track),"
|
||||
"FOREIGN KEY(seg_id) REFERENCES railway_segments(id) ON UPDATE CASCADE ON DELETE RESTRICT )");
|
||||
CHECK(result);
|
||||
|
||||
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 )");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE line_segments ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"line_id INTEGER NOT NULL,"
|
||||
"seg_id INTEGER NOT NULL,"
|
||||
"direction INTEGER NOT NULL,"
|
||||
"pos INTEGER NOT NULL,"
|
||||
"FOREIGN KEY(line_id) REFERENCES lines(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"FOREIGN KEY(seg_id) REFERENCES railway_segments(id) ON UPDATE CASCADE ON DELETE RESTRICT,"
|
||||
"UNIQUE(line_id, seg_id)"
|
||||
"UNIQUE(line_id, pos)"
|
||||
"CHECK(pos<100) )"); //Allow up to 100 segments for each line
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE line_segments ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"line_id INTEGER NOT NULL,"
|
||||
"seg_id INTEGER NOT NULL,"
|
||||
"direction INTEGER NOT NULL,"
|
||||
"pos INTEGER NOT NULL,"
|
||||
"FOREIGN KEY(line_id) REFERENCES lines(id) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"FOREIGN KEY(seg_id) REFERENCES railway_segments(id) ON UPDATE CASCADE ON DELETE RESTRICT,"
|
||||
"UNIQUE(line_id, seg_id)"
|
||||
"UNIQUE(line_id, pos)"
|
||||
"CHECK(pos<100) )"); // Allow up to 100 segments for each line
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE jobshifts ("
|
||||
|
@ -379,34 +389,39 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
"name TEXT UNIQUE NOT NULL)");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE jobs ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"category INTEGER NOT NULL DEFAULT 0,"
|
||||
"shift_id INTEGER,"
|
||||
"FOREIGN KEY(shift_id) REFERENCES jobshifts(id) ON UPDATE CASCADE ON DELETE RESTRICT)");
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE jobs ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"category INTEGER NOT NULL DEFAULT 0,"
|
||||
"shift_id INTEGER,"
|
||||
"FOREIGN KEY(shift_id) REFERENCES jobshifts(id) ON UPDATE CASCADE ON DELETE RESTRICT)");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE stops ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"job_id INTEGER NOT NULL,"
|
||||
"station_id INTEGER,"
|
||||
"arrival INTEGER NOT NULL,"
|
||||
"departure INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"description TEXT,"
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE stops ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"job_id INTEGER NOT NULL,"
|
||||
"station_id INTEGER,"
|
||||
"arrival INTEGER NOT NULL,"
|
||||
"departure INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"description TEXT,"
|
||||
|
||||
"in_gate_conn INTEGER,"
|
||||
"out_gate_conn INTEGER,"
|
||||
"next_segment_conn_id INTEGER,"
|
||||
"in_gate_conn INTEGER,"
|
||||
"out_gate_conn INTEGER,"
|
||||
"next_segment_conn_id INTEGER,"
|
||||
|
||||
"CHECK(arrival<=departure),"
|
||||
"UNIQUE(job_id,arrival),"
|
||||
"UNIQUE(job_id,departure),"
|
||||
"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(in_gate_conn) REFERENCES station_gate_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(arrival<=departure),"
|
||||
"UNIQUE(job_id,arrival),"
|
||||
"UNIQUE(job_id,departure),"
|
||||
"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(in_gate_conn) REFERENCES station_gate_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);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE coupling ("
|
||||
|
@ -420,41 +435,47 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
"UNIQUE(stop_id,rs_id))");
|
||||
CHECK(result);
|
||||
|
||||
//Create also backup tables to save old stops and couplings before editing a job and restore 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
|
||||
// Create also backup tables to save old stops and couplings before editing a job and restore
|
||||
// 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 ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"job_id INTEGER NOT NULL,"
|
||||
"station_id INTEGER,"
|
||||
"arrival INTEGER NOT NULL,"
|
||||
"departure INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"description TEXT,"
|
||||
result = m_Db.execute(
|
||||
"CREATE TABLE old_stops ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"job_id INTEGER NOT NULL,"
|
||||
"station_id INTEGER,"
|
||||
"arrival INTEGER NOT NULL,"
|
||||
"departure INTEGER NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"description TEXT,"
|
||||
|
||||
"in_gate_conn INTEGER,"
|
||||
"out_gate_conn INTEGER,"
|
||||
"next_segment_conn_id INTEGER,"
|
||||
"in_gate_conn INTEGER,"
|
||||
"out_gate_conn INTEGER,"
|
||||
"next_segment_conn_id INTEGER,"
|
||||
|
||||
"CHECK(arrival<=departure),"
|
||||
"UNIQUE(job_id,arrival),"
|
||||
"UNIQUE(job_id,departure),"
|
||||
"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(in_gate_conn) REFERENCES station_gate_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(arrival<=departure),"
|
||||
"UNIQUE(job_id,arrival),"
|
||||
"UNIQUE(job_id,departure),"
|
||||
"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(in_gate_conn) REFERENCES station_gate_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);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE old_coupling ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"stop_id INTEGER,"
|
||||
"rs_id INTEGER,"
|
||||
"operation INTEGER NOT NULL DEFAULT 0,"
|
||||
result =
|
||||
m_Db.execute("CREATE TABLE old_coupling ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"stop_id INTEGER,"
|
||||
"rs_id INTEGER,"
|
||||
"operation INTEGER NOT NULL DEFAULT 0,"
|
||||
|
||||
"FOREIGN KEY(stop_id) REFERENCES old_stops(id) ON DELETE CASCADE," //Old stops
|
||||
"FOREIGN KEY(rs_id) REFERENCES rs_list(id) ON DELETE RESTRICT,"
|
||||
"UNIQUE(stop_id,rs_id))");
|
||||
"FOREIGN KEY(stop_id) REFERENCES old_stops(id) ON DELETE CASCADE," // Old stops
|
||||
"FOREIGN KEY(rs_id) REFERENCES rs_list(id) ON DELETE RESTRICT,"
|
||||
"UNIQUE(stop_id,rs_id))");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE imported_rs_owners ("
|
||||
|
@ -465,7 +486,8 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
"match_existing_id INTEGER,"
|
||||
"sheet_idx INTEGER,"
|
||||
"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);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE imported_rs_models ("
|
||||
|
@ -480,7 +502,8 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
"type INTEGER,"
|
||||
"sub_type INTEGER,"
|
||||
"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);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE imported_rs_list ("
|
||||
|
@ -491,8 +514,10 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
"number INTEGER,"
|
||||
"new_number INTEGER,"
|
||||
"PRIMARY KEY(id),"
|
||||
"FOREIGN KEY(model_id) REFERENCES imported_rs_models(id) ON UPDATE RESTRICT ON DELETE RESTRICT,"
|
||||
"FOREIGN KEY(owner_id) REFERENCES imported_rs_owners(id) ON UPDATE RESTRICT ON DELETE RESTRICT)");
|
||||
"FOREIGN KEY(model_id) REFERENCES imported_rs_models(id) ON UPDATE "
|
||||
"RESTRICT ON DELETE RESTRICT,"
|
||||
"FOREIGN KEY(owner_id) REFERENCES imported_rs_owners(id) ON UPDATE "
|
||||
"RESTRICT ON DELETE RESTRICT)");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TABLE metadata ("
|
||||
|
@ -500,50 +525,56 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
"val BLOB)");
|
||||
CHECK(result);
|
||||
|
||||
//Triggers
|
||||
// Triggers
|
||||
|
||||
//Prevent multiple segments on same station gate
|
||||
result = m_Db.execute("CREATE TRIGGER multiple_gate_segments\n"
|
||||
"BEFORE INSERT ON railway_segments\n"
|
||||
"BEGIN\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;"
|
||||
"END");
|
||||
// Prevent multiple segments on same station gate
|
||||
result =
|
||||
m_Db.execute("CREATE TRIGGER multiple_gate_segments\n"
|
||||
"BEFORE INSERT ON railway_segments\n"
|
||||
"BEGIN\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;"
|
||||
"END");
|
||||
CHECK(result);
|
||||
result = m_Db.execute("CREATE TRIGGER multiple_gate_segments_update_in\n"
|
||||
"BEFORE UPDATE OF in_gate_id ON railway_segments\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");
|
||||
CHECK(result);
|
||||
result = m_Db.execute("CREATE TRIGGER multiple_gate_segments_update_out\n"
|
||||
"BEFORE UPDATE OF out_gate_id ON railway_segments\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");
|
||||
CHECK(result);
|
||||
|
||||
//Prevent connecting a track to a gate of a different station
|
||||
result = m_Db.execute("CREATE TRIGGER gate_conn_different_station\n"
|
||||
"BEFORE INSERT ON station_gate_connections\n"
|
||||
"BEGIN\n"
|
||||
"SELECT RAISE(ABORT, 'Cannot connect platform of a different station') FROM station_tracks t"
|
||||
" JOIN station_gates g ON g.id=NEW.gate_id"
|
||||
" WHERE t.id=NEW.track_id AND t.station_id<>g.station_id;"
|
||||
"END");
|
||||
// Prevent connecting a track to a gate of a different station
|
||||
result = m_Db.execute(
|
||||
"CREATE TRIGGER gate_conn_different_station\n"
|
||||
"BEFORE INSERT ON station_gate_connections\n"
|
||||
"BEGIN\n"
|
||||
"SELECT RAISE(ABORT, 'Cannot connect platform of a different station') FROM station_tracks t"
|
||||
" JOIN station_gates g ON g.id=NEW.gate_id"
|
||||
" WHERE t.id=NEW.track_id AND t.station_id<>g.station_id;"
|
||||
"END");
|
||||
CHECK(result);
|
||||
|
||||
result = m_Db.execute("CREATE TRIGGER gate_conn_different_station_update\n"
|
||||
"BEFORE UPDATE OF track_id,gate_id ON station_gate_connections\n"
|
||||
"BEGIN\n"
|
||||
"SELECT RAISE(ABORT, 'Cannot connect platform of a different station') FROM station_tracks t"
|
||||
" JOIN station_gates g ON g.id=NEW.gate_id"
|
||||
" WHERE t.id=NEW.track_id AND t.station_id<>g.station_id;"
|
||||
"END");
|
||||
result = m_Db.execute(
|
||||
"CREATE TRIGGER gate_conn_different_station_update\n"
|
||||
"BEFORE UPDATE OF track_id,gate_id ON station_gate_connections\n"
|
||||
"BEGIN\n"
|
||||
"SELECT RAISE(ABORT, 'Cannot connect platform of a different station') FROM station_tracks t"
|
||||
" JOIN station_gates g ON g.id=NEW.gate_id"
|
||||
" WHERE t.id=NEW.track_id AND t.station_id<>g.station_id;"
|
||||
"END");
|
||||
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"
|
||||
"BEFORE INSERT ON station_gate_connections\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"
|
||||
"BEFORE UPDATE OF out_track_count ON station_gates\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;"
|
||||
"END");
|
||||
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"
|
||||
"BEFORE INSERT ON station_gates\n"
|
||||
"BEGIN\n"
|
||||
"SELECT RAISE(ABORT, 'Platform not connected to this gate') WHERE"
|
||||
" 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");
|
||||
CHECK(result);
|
||||
|
@ -584,13 +617,13 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
"BEGIN\n"
|
||||
"SELECT RAISE(ABORT, 'Platform not connected to this gate') WHERE"
|
||||
" 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");
|
||||
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
|
||||
|
||||
|
@ -605,25 +638,25 @@ DB_Error MeetingSession::createNewDB(const QString& file)
|
|||
* Theese tables are used during RS importation and are cleared when the process
|
||||
* completes or gets canceled by the user
|
||||
* If they are not empty it might be because the application crashed before clearing theese tables
|
||||
*/
|
||||
*/
|
||||
bool MeetingSession::checkImportRSTablesEmpty()
|
||||
{
|
||||
query q(m_Db, "SELECT COUNT(1) FROM imported_rs_list");
|
||||
q.step();
|
||||
int count = q.getRows().get<int>(0);
|
||||
if(count)
|
||||
if (count)
|
||||
return false;
|
||||
|
||||
q.prepare("SELECT COUNT(1) FROM imported_rs_models");
|
||||
q.step();
|
||||
count = q.getRows().get<int>(0);
|
||||
if(count)
|
||||
if (count)
|
||||
return false;
|
||||
|
||||
q.prepare("SELECT COUNT(1) FROM imported_rs_owners");
|
||||
q.step();
|
||||
count = q.getRows().get<int>(0);
|
||||
if(count)
|
||||
if (count)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -631,15 +664,15 @@ bool MeetingSession::checkImportRSTablesEmpty()
|
|||
bool MeetingSession::clearImportRSTables()
|
||||
{
|
||||
command cmd(m_Db, "DELETE FROM imported_rs_list");
|
||||
if(cmd.execute() != SQLITE_OK)
|
||||
if (cmd.execute() != SQLITE_OK)
|
||||
return false;
|
||||
|
||||
cmd.prepare("DELETE FROM imported_rs_models");
|
||||
if(cmd.execute() != SQLITE_OK)
|
||||
if (cmd.execute() != SQLITE_OK)
|
||||
return false;
|
||||
|
||||
cmd.prepare("DELETE FROM imported_rs_owners");
|
||||
if(cmd.execute() != SQLITE_OK)
|
||||
if (cmd.execute() != SQLITE_OK)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -647,15 +680,15 @@ bool MeetingSession::clearImportRSTables()
|
|||
|
||||
bool MeetingSession::setSavepoint(const QString &pointname)
|
||||
{
|
||||
if(!m_Db.db())
|
||||
if (!m_Db.db())
|
||||
return false;
|
||||
|
||||
if(savepointList.contains(pointname))
|
||||
if (savepointList.contains(pointname))
|
||||
return true;
|
||||
|
||||
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();
|
||||
return false;
|
||||
|
@ -667,15 +700,15 @@ bool MeetingSession::setSavepoint(const QString &pointname)
|
|||
|
||||
bool MeetingSession::releaseSavepoint(const QString &pointname)
|
||||
{
|
||||
if(!m_Db.db())
|
||||
if (!m_Db.db())
|
||||
return false;
|
||||
|
||||
if(!savepointList.contains(pointname))
|
||||
if (!savepointList.contains(pointname))
|
||||
return true;
|
||||
|
||||
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();
|
||||
return false;
|
||||
|
@ -689,15 +722,15 @@ bool MeetingSession::releaseSavepoint(const QString &pointname)
|
|||
|
||||
bool MeetingSession::revertToSavepoint(const QString &pointname)
|
||||
{
|
||||
if(!m_Db.db())
|
||||
if (!m_Db.db())
|
||||
return false;
|
||||
|
||||
if(!savepointList.contains(pointname))
|
||||
if (!savepointList.contains(pointname))
|
||||
return false;
|
||||
|
||||
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();
|
||||
return false;
|
||||
|
@ -711,17 +744,17 @@ bool MeetingSession::revertToSavepoint(const QString &pointname)
|
|||
|
||||
bool MeetingSession::releaseAllSavepoints()
|
||||
{
|
||||
if(!m_Db.db())
|
||||
if (!m_Db.db())
|
||||
return false;
|
||||
|
||||
for(const QString& point : qAsConst(savepointList))
|
||||
for (const QString &point : qAsConst(savepointList))
|
||||
{
|
||||
if(!releaseSavepoint(point))
|
||||
if (!releaseSavepoint(point))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;");
|
||||
|
||||
return true;
|
||||
|
@ -729,9 +762,9 @@ bool MeetingSession::releaseAllSavepoints()
|
|||
|
||||
bool MeetingSession::revertAll()
|
||||
{
|
||||
for(const QString& point : qAsConst(savepointList))
|
||||
for (const QString &point : qAsConst(savepointList))
|
||||
{
|
||||
if(!revertToSavepoint(point))
|
||||
if (!revertToSavepoint(point))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -739,59 +772,59 @@ bool MeetingSession::revertAll()
|
|||
|
||||
QColor MeetingSession::colorForCat(JobCategory cat)
|
||||
{
|
||||
QColor col = settings.getCategoryColor(int(cat)); //TODO: maybe session-specific
|
||||
if(col.isValid())
|
||||
QColor col = settings.getCategoryColor(int(cat)); // TODO: maybe session-specific
|
||||
if (col.isValid())
|
||||
return col;
|
||||
return QColor(Qt::gray); //Error
|
||||
return QColor(Qt::gray); // Error
|
||||
}
|
||||
|
||||
void MeetingSession::locateAppdata()
|
||||
{
|
||||
appDataPath = QStringLiteral("%1/%2/%3")
|
||||
.arg(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation),
|
||||
AppCompany, AppProductShort);
|
||||
.arg(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation),
|
||||
AppCompany, AppProductShort);
|
||||
appDataPath = QDir::cleanPath(appDataPath);
|
||||
qDebug() << appDataPath;
|
||||
}
|
||||
|
||||
void MeetingSession::setSheetExportTranslator(QTranslator *translator, const QLocale &loc)
|
||||
{
|
||||
//NOTE: if Sheet Language is of Application Language then set a nullptr translator
|
||||
//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 different from English, use default translations
|
||||
// NOTE: if Sheet Language is of Application Language then set a nullptr translator
|
||||
// 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 different from English, use default translations
|
||||
|
||||
if(sheetExportTranslator && sheetExportTranslator != translator)
|
||||
if (sheetExportTranslator && sheetExportTranslator != translator)
|
||||
delete sheetExportTranslator;
|
||||
sheetExportTranslator = translator;
|
||||
sheetExportLocale = loc;
|
||||
sheetExportLocale = loc;
|
||||
}
|
||||
|
||||
void MeetingSession::loadSettings(const QString& settings_file)
|
||||
void MeetingSession::loadSettings(const QString &settings_file)
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
if(settings_file.isEmpty())
|
||||
if (settings_file.isEmpty())
|
||||
settings.loadSettings(appDataPath + QStringLiteral("/mrtp_settings.ini"));
|
||||
else
|
||||
settings.loadSettings(settings_file);
|
||||
|
||||
hourOffset = settings.getHourOffset();
|
||||
stationOffset = settings.getStationOffset();
|
||||
horizOffset = settings.getHorizontalOffset();
|
||||
vertOffset = settings.getVerticalOffset();
|
||||
platformOffset = settings.getPlatformOffset();
|
||||
hourOffset = settings.getHourOffset();
|
||||
stationOffset = settings.getStationOffset();
|
||||
horizOffset = settings.getHorizontalOffset();
|
||||
vertOffset = settings.getVerticalOffset();
|
||||
platformOffset = settings.getPlatformOffset();
|
||||
|
||||
jobLineWidth = settings.getJobLineWidth();
|
||||
jobLineWidth = settings.getJobLineWidth();
|
||||
|
||||
originalAppLocale = settings.getLanguage();
|
||||
|
||||
//Default initialize to same value of application language
|
||||
// Default initialize to same value of application language
|
||||
setSheetExportTranslator(nullptr, originalAppLocale);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
BackgroundManager* MeetingSession::getBackgroundManager() const
|
||||
BackgroundManager *MeetingSession::getBackgroundManager() const
|
||||
{
|
||||
return backgroundManager.get();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ using namespace sqlite3pp;
|
|||
|
||||
#include <settings/appsettings.h>
|
||||
|
||||
|
||||
class ViewManager;
|
||||
class MetaDataManager;
|
||||
|
||||
|
@ -65,53 +64,60 @@ class MeetingSession : public QObject
|
|||
Q_OBJECT
|
||||
|
||||
private:
|
||||
static MeetingSession* session;
|
||||
static MeetingSession *session;
|
||||
|
||||
public:
|
||||
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
|
||||
BackgroundManager *getBackgroundManager() const;
|
||||
#endif
|
||||
|
||||
signals:
|
||||
//Shifts
|
||||
// Shifts
|
||||
void shiftAdded(db_id shiftId);
|
||||
void shiftRemoved(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);
|
||||
|
||||
//Rollingstock
|
||||
// Rollingstock
|
||||
void rollingstockRemoved(db_id rsId);
|
||||
void rollingStockPlanChanged(QSet<db_id> rsIds);
|
||||
void rollingStockModified(db_id rsId);
|
||||
|
||||
//Jobs
|
||||
// Jobs
|
||||
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);
|
||||
|
||||
//Stations
|
||||
// Stations
|
||||
void stationNameChanged(db_id stationId);
|
||||
void stationJobsPlanChanged(const QSet<db_id>& stationIds);
|
||||
void stationTrackPlanChanged(const QSet<db_id>& stationIds);
|
||||
void stationJobsPlanChanged(const QSet<db_id> &stationIds);
|
||||
void stationTrackPlanChanged(const QSet<db_id> &stationIds);
|
||||
void stationRemoved(db_id stationId);
|
||||
|
||||
//Segments
|
||||
// Segments
|
||||
void segmentAdded(db_id segmentId);
|
||||
void segmentNameChanged(db_id segmentId);
|
||||
void segmentStationsChanged(db_id segmentId);
|
||||
void segmentRemoved(db_id segmentId);
|
||||
|
||||
//Lines
|
||||
// Lines
|
||||
void lineAdded(db_id lineId);
|
||||
void lineNameChanged(db_id lineId);
|
||||
void lineSegmentsChanged(db_id lineId);
|
||||
|
@ -126,45 +132,48 @@ private:
|
|||
std::unique_ptr<BackgroundManager> backgroundManager;
|
||||
#endif
|
||||
|
||||
//Settings TODO: remove
|
||||
// Settings TODO: remove
|
||||
public:
|
||||
void loadSettings(const QString &settings_file);
|
||||
|
||||
MRTPSettings settings;
|
||||
|
||||
int hourOffset;
|
||||
int stationOffset;
|
||||
qreal platformOffset;
|
||||
int hourOffset;
|
||||
int stationOffset;
|
||||
qreal platformOffset;
|
||||
|
||||
int horizOffset;
|
||||
int vertOffset;
|
||||
int horizOffset;
|
||||
int vertOffset;
|
||||
|
||||
int jobLineWidth;
|
||||
|
||||
//Database
|
||||
// Database
|
||||
public:
|
||||
database m_Db;
|
||||
|
||||
//Job Categories:
|
||||
// Job Categories:
|
||||
public:
|
||||
QColor colorForCat(JobCategory cat);
|
||||
|
||||
//Savepoints TODO: seem unused
|
||||
// Savepoints TODO: seem unused
|
||||
public:
|
||||
inline bool getDBDirty() { return !savepointList.isEmpty(); }
|
||||
inline bool getDBDirty()
|
||||
{
|
||||
return !savepointList.isEmpty();
|
||||
}
|
||||
|
||||
bool setSavepoint(const QString& pointname = "RESTOREPOINT");
|
||||
bool releaseSavepoint(const QString& pointname = "RESTOREPOINT");
|
||||
bool revertToSavepoint(const QString& pointname = "RESTOREPOINT");
|
||||
bool setSavepoint(const QString &pointname = "RESTOREPOINT");
|
||||
bool releaseSavepoint(const QString &pointname = "RESTOREPOINT");
|
||||
bool revertToSavepoint(const QString &pointname = "RESTOREPOINT");
|
||||
bool releaseAllSavepoints();
|
||||
bool revertAll();
|
||||
|
||||
QStringList savepointList;
|
||||
|
||||
//DB
|
||||
// DB
|
||||
public:
|
||||
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();
|
||||
|
||||
bool checkImportRSTablesEmpty();
|
||||
|
@ -172,7 +181,7 @@ public:
|
|||
|
||||
QString fileName;
|
||||
|
||||
//AppData
|
||||
// AppData
|
||||
public:
|
||||
static void locateAppdata();
|
||||
static QString appDataPath;
|
||||
|
@ -228,14 +237,25 @@ public:
|
|||
*/
|
||||
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 QLocale getSheetExportLocale() const { return sheetExportLocale; }
|
||||
inline QLocale getAppLanguage() const { return originalAppLocale; }
|
||||
inline QTranslator *getSheetExportTranslator() const
|
||||
{
|
||||
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
|
||||
|
||||
|
|
|
@ -20,25 +20,23 @@
|
|||
#include "backgroundmanager.h"
|
||||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
#include "backgroundmanager/ibackgroundchecker.h"
|
||||
# include "backgroundmanager/ibackgroundchecker.h"
|
||||
|
||||
#include <QThreadPool>
|
||||
#include <QSet>
|
||||
# include <QThreadPool>
|
||||
# include <QSet>
|
||||
|
||||
BackgroundManager::BackgroundManager(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BackgroundManager::~BackgroundManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BackgroundManager::handleSessionLoaded()
|
||||
{
|
||||
for(IBackgroundChecker *mgr : qAsConst(checkers))
|
||||
for (IBackgroundChecker *mgr : qAsConst(checkers))
|
||||
mgr->startWorker();
|
||||
}
|
||||
|
||||
|
@ -46,19 +44,19 @@ void BackgroundManager::abortAllTasks()
|
|||
{
|
||||
emit abortTrivialTasks();
|
||||
|
||||
for(IBackgroundChecker *mgr : qAsConst(checkers))
|
||||
for (IBackgroundChecker *mgr : qAsConst(checkers))
|
||||
mgr->abortTasks();
|
||||
}
|
||||
|
||||
bool BackgroundManager::isRunning()
|
||||
{
|
||||
bool running = QThreadPool::globalInstance()->activeThreadCount() > 0;
|
||||
if(running)
|
||||
if (running)
|
||||
return true;
|
||||
|
||||
for(IBackgroundChecker *mgr : qAsConst(checkers))
|
||||
for (IBackgroundChecker *mgr : qAsConst(checkers))
|
||||
{
|
||||
if(mgr->isRunning())
|
||||
if (mgr->isRunning())
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -69,10 +67,8 @@ void BackgroundManager::addChecker(IBackgroundChecker *mgr)
|
|||
{
|
||||
checkers.append(mgr);
|
||||
|
||||
connect(mgr, &IBackgroundChecker::destroyed, this, [this](QObject *self)
|
||||
{
|
||||
removeChecker(static_cast<IBackgroundChecker *>(self));
|
||||
});
|
||||
connect(mgr, &IBackgroundChecker::destroyed, this,
|
||||
[this](QObject *self) { removeChecker(static_cast<IBackgroundChecker *>(self)); });
|
||||
|
||||
emit checkerAdded(mgr);
|
||||
}
|
||||
|
@ -86,7 +82,7 @@ void BackgroundManager::removeChecker(IBackgroundChecker *mgr)
|
|||
|
||||
void BackgroundManager::clearResults()
|
||||
{
|
||||
for(IBackgroundChecker *mgr : qAsConst(checkers))
|
||||
for (IBackgroundChecker *mgr : qAsConst(checkers))
|
||||
{
|
||||
mgr->clearModel();
|
||||
}
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
# include <QObject>
|
||||
# include <QVector>
|
||||
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include "backgroundresultpanel.h"
|
||||
# include "backgroundresultpanel.h"
|
||||
|
||||
#include "backgroundmanager/ibackgroundchecker.h"
|
||||
#include "backgroundresultwidget.h"
|
||||
# include "backgroundmanager/ibackgroundchecker.h"
|
||||
# include "backgroundresultwidget.h"
|
||||
|
||||
#include "app/session.h"
|
||||
#include "backgroundmanager.h"
|
||||
# include "app/session.h"
|
||||
# include "backgroundmanager.h"
|
||||
|
||||
BackgroundResultPanel::BackgroundResultPanel(QWidget *parent) :
|
||||
QTabWidget(parent)
|
||||
|
@ -34,7 +34,7 @@ BackgroundResultPanel::BackgroundResultPanel(QWidget *parent) :
|
|||
connect(bkMgr, &BackgroundManager::checkerAdded, this, &BackgroundResultPanel::addChecker);
|
||||
connect(bkMgr, &BackgroundManager::checkerRemoved, this, &BackgroundResultPanel::removeChecker);
|
||||
|
||||
for(auto mgr : bkMgr->checkers)
|
||||
for (auto mgr : bkMgr->checkers)
|
||||
addChecker(mgr);
|
||||
}
|
||||
|
||||
|
@ -46,10 +46,10 @@ void BackgroundResultPanel::addChecker(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));
|
||||
if(w->mgr == mgr)
|
||||
if (w->mgr == mgr)
|
||||
{
|
||||
removeTab(i);
|
||||
delete w;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include <QTabWidget>
|
||||
# include <QTabWidget>
|
||||
|
||||
class IBackgroundChecker;
|
||||
|
||||
|
|
|
@ -19,21 +19,20 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include "ibackgroundchecker.h"
|
||||
#include "backgroundresultwidget.h"
|
||||
# include "ibackgroundchecker.h"
|
||||
# include "backgroundresultwidget.h"
|
||||
|
||||
#include <QTreeView>
|
||||
#include <QHeaderView>
|
||||
#include <QProgressBar>
|
||||
#include <QPushButton>
|
||||
# include <QTreeView>
|
||||
# include <QHeaderView>
|
||||
# include <QProgressBar>
|
||||
# include <QPushButton>
|
||||
|
||||
#include <QGridLayout>
|
||||
# include <QGridLayout>
|
||||
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
|
||||
#include <QTimerEvent>
|
||||
# include <QMenu>
|
||||
# include <QAction>
|
||||
|
||||
# include <QTimerEvent>
|
||||
|
||||
BackgroundResultWidget::BackgroundResultWidget(IBackgroundChecker *mgr_, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
|
@ -45,8 +44,8 @@ BackgroundResultWidget::BackgroundResultWidget(IBackgroundChecker *mgr_, QWidget
|
|||
view->setSelectionBehavior(QTreeView::SelectRows);
|
||||
|
||||
progressBar = new QProgressBar;
|
||||
startBut = new QPushButton(tr("Start"));
|
||||
stopBut = new QPushButton(tr("Stop"));
|
||||
startBut = new QPushButton(tr("Start"));
|
||||
stopBut = new QPushButton(tr("Stop"));
|
||||
|
||||
startBut->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);
|
||||
|
||||
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(view, &QTreeView::customContextMenuRequested, this, &BackgroundResultWidget::showContextMenu);
|
||||
connect(view, &QTreeView::customContextMenuRequested, this,
|
||||
&BackgroundResultWidget::showContextMenu);
|
||||
|
||||
setWindowTitle(tr("Error Results"));
|
||||
|
||||
|
@ -79,11 +79,11 @@ void BackgroundResultWidget::startTask()
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -105,14 +105,14 @@ void BackgroundResultWidget::taskFinished()
|
|||
{
|
||||
progressBar->setValue(progressBar->maximum());
|
||||
|
||||
if(timerId)
|
||||
if (timerId)
|
||||
killTimer(timerId);
|
||||
timerId = startTimer(1000); //Hide progressBar after 1 second
|
||||
timerId = startTimer(1000); // Hide progressBar after 1 second
|
||||
}
|
||||
|
||||
void BackgroundResultWidget::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if(e->timerId() == timerId)
|
||||
if (e->timerId() == timerId)
|
||||
{
|
||||
killTimer(timerId);
|
||||
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);
|
||||
if(!idx.isValid())
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
mgr->showContextMenu(this, view->viewport()->mapToGlobal(pos), idx);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include <QWidget>
|
||||
# include <QWidget>
|
||||
|
||||
class QTreeView;
|
||||
class QProgressBar;
|
||||
|
|
|
@ -19,25 +19,23 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include "ibackgroundchecker.h"
|
||||
# include "ibackgroundchecker.h"
|
||||
|
||||
#include <QThreadPool>
|
||||
#include "utils/thread/iquittabletask.h"
|
||||
#include "utils/thread/taskprogressevent.h"
|
||||
|
||||
#include "sqlite3pp/sqlite3pp.h"
|
||||
# include <QThreadPool>
|
||||
# include "utils/thread/iquittabletask.h"
|
||||
# include "utils/thread/taskprogressevent.h"
|
||||
|
||||
# include "sqlite3pp/sqlite3pp.h"
|
||||
|
||||
IBackgroundChecker::IBackgroundChecker(sqlite3pp::database &db, QObject *parent) :
|
||||
QObject(parent),
|
||||
mDb(db)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool IBackgroundChecker::event(QEvent *e)
|
||||
{
|
||||
if(e->type() == TaskProgressEvent::_Type)
|
||||
if (e->type() == TaskProgressEvent::_Type)
|
||||
{
|
||||
e->setAccepted(true);
|
||||
|
||||
|
@ -46,14 +44,14 @@ bool IBackgroundChecker::event(QEvent *e)
|
|||
|
||||
return true;
|
||||
}
|
||||
else if(e->type() == eventType)
|
||||
else if (e->type() == eventType)
|
||||
{
|
||||
e->setAccepted(true);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -66,10 +64,10 @@ bool IBackgroundChecker::event(QEvent *e)
|
|||
else
|
||||
{
|
||||
int idx = m_workers.indexOf(ev->task);
|
||||
if(idx != -1)
|
||||
if (idx != -1)
|
||||
{
|
||||
m_workers.removeAt(idx);
|
||||
if(!ev->task->wasStopped())
|
||||
if (!ev->task->wasStopped())
|
||||
setErrors(ev, true);
|
||||
|
||||
delete ev->task;
|
||||
|
@ -84,19 +82,19 @@ bool IBackgroundChecker::event(QEvent *e)
|
|||
|
||||
bool IBackgroundChecker::startWorker()
|
||||
{
|
||||
if(m_mainWorker)
|
||||
if (m_mainWorker)
|
||||
return false;
|
||||
|
||||
if(!mDb.db())
|
||||
if (!mDb.db())
|
||||
return false;
|
||||
|
||||
m_mainWorker = createMainWorker();
|
||||
|
||||
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;
|
||||
m_workers.erase(task);
|
||||
|
@ -113,12 +111,12 @@ bool IBackgroundChecker::startWorker()
|
|||
|
||||
void IBackgroundChecker::abortTasks()
|
||||
{
|
||||
if(m_mainWorker)
|
||||
if (m_mainWorker)
|
||||
{
|
||||
m_mainWorker->stop();
|
||||
}
|
||||
|
||||
for(IQuittableTask *task : qAsConst(m_workers))
|
||||
for (IQuittableTask *task : qAsConst(m_workers))
|
||||
{
|
||||
task->stop();
|
||||
}
|
||||
|
@ -126,7 +124,7 @@ void IBackgroundChecker::abortTasks()
|
|||
|
||||
void IBackgroundChecker::sessionLoadedHandler()
|
||||
{
|
||||
//no-op
|
||||
// no-op
|
||||
}
|
||||
|
||||
void IBackgroundChecker::addSubTask(IQuittableTask *task)
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
# include <QObject>
|
||||
# include <QVector>
|
||||
|
||||
class QAbstractItemModel;
|
||||
class QModelIndex;
|
||||
|
@ -47,13 +47,20 @@ public:
|
|||
bool startWorker();
|
||||
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 void clearModel() = 0;
|
||||
virtual void showContextMenu(QWidget *panel, const QPoint& globalPos, const QModelIndex& idx) const = 0;
|
||||
virtual QString getName() const = 0;
|
||||
virtual void clearModel() = 0;
|
||||
virtual void showContextMenu(QWidget *panel, const QPoint &globalPos,
|
||||
const QModelIndex &idx) const = 0;
|
||||
|
||||
virtual void sessionLoadedHandler();
|
||||
|
||||
|
@ -64,13 +71,13 @@ signals:
|
|||
protected:
|
||||
void addSubTask(IQuittableTask *task);
|
||||
|
||||
virtual IQuittableTask *createMainWorker() = 0;
|
||||
virtual IQuittableTask *createMainWorker() = 0;
|
||||
virtual void setErrors(QEvent *e, bool merge) = 0;
|
||||
|
||||
protected:
|
||||
sqlite3pp::database &mDb;
|
||||
QAbstractItemModel *errorsModel = nullptr;
|
||||
int eventType = 0;
|
||||
int eventType = 0;
|
||||
|
||||
private:
|
||||
IQuittableTask *m_mainWorker = nullptr;
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
namespace ImageMetaData
|
||||
{
|
||||
namespace ImageMetaData {
|
||||
|
||||
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),
|
||||
mBlob(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ImageBlobDevice::~ImageBlobDevice()
|
||||
|
@ -45,40 +43,40 @@ ImageBlobDevice::~ImageBlobDevice()
|
|||
|
||||
void ImageBlobDevice::setBlobInfo(const QByteArray &table, const QByteArray &column, qint64 rowId)
|
||||
{
|
||||
mRowId = rowId;
|
||||
mTable = table;
|
||||
mRowId = rowId;
|
||||
mTable = table;
|
||||
mColumn = column;
|
||||
}
|
||||
|
||||
bool ImageBlobDevice::reserveSizeAndReset(qint64 len)
|
||||
{
|
||||
//NOTE: this will discard any previous content
|
||||
// NOTE: this will discard any previous content
|
||||
|
||||
//Close previous BLOB handle
|
||||
if(mBlob)
|
||||
// Close previous BLOB handle
|
||||
if (mBlob)
|
||||
close();
|
||||
|
||||
//Create SQL statement
|
||||
QByteArray sql = "UPDATE " + mTable + " SET " + mColumn + "=? WHERE rowId=?";
|
||||
// Create SQL statement
|
||||
QByteArray sql = "UPDATE " + mTable + " SET " + mColumn + "=? WHERE rowId=?";
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
int rc = sqlite3_prepare_v2(mDb, sql.constData(), sql.size(), &stmt, nullptr);
|
||||
if(rc != SQLITE_OK)
|
||||
int rc = sqlite3_prepare_v2(mDb, sql.constData(), sql.size(), &stmt, nullptr);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
qWarning() << "ImageBlobDevice::reserveSizeAndReset cannot prepare:" << sqlite3_errmsg(mDb);
|
||||
setErrorString(tr("Cannot query database"));
|
||||
return false;
|
||||
}
|
||||
|
||||
//Reserve BLOB memory
|
||||
// Reserve BLOB memory
|
||||
rc = sqlite3_bind_zeroblob64(stmt, 1, len);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
}
|
||||
rc = sqlite3_bind_int64(stmt, 2, mRowId);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
|
@ -88,30 +86,30 @@ bool ImageBlobDevice::reserveSizeAndReset(qint64 len)
|
|||
|
||||
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);
|
||||
setErrorString(tr("Cannot create BLOB"));
|
||||
return false;
|
||||
}
|
||||
|
||||
//Open new BLOB handle
|
||||
// Open new BLOB handle
|
||||
return open(QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
bool ImageBlobDevice::open(QIODevice::OpenMode mode)
|
||||
{
|
||||
if(isOpen())
|
||||
if (isOpen())
|
||||
{
|
||||
qWarning().nospace() << "ImageBlobDevice::open Device already open "
|
||||
<< '(' << mTable << '.' << mColumn << ')';
|
||||
qWarning().nospace() << "ImageBlobDevice::open Device already open " << '(' << mTable << '.'
|
||||
<< mColumn << ')';
|
||||
return false;
|
||||
}
|
||||
|
||||
mode |= QIODevice::ReadOnly; //Always enable reading
|
||||
int rc = sqlite3_blob_open(mDb, "main", mTable.constData(), mColumn.constData(),
|
||||
mRowId, (mode & QIODevice::WriteOnly) != 0, &mBlob);
|
||||
if(rc != SQLITE_OK || !mBlob)
|
||||
mode |= QIODevice::ReadOnly; // Always enable reading
|
||||
int rc = sqlite3_blob_open(mDb, "main", mTable.constData(), mColumn.constData(), mRowId,
|
||||
(mode & QIODevice::WriteOnly) != 0, &mBlob);
|
||||
if (rc != SQLITE_OK || !mBlob)
|
||||
{
|
||||
mBlob = nullptr;
|
||||
setErrorString(sqlite3_errmsg(mDb));
|
||||
|
@ -127,7 +125,7 @@ bool ImageBlobDevice::open(QIODevice::OpenMode mode)
|
|||
|
||||
void ImageBlobDevice::close()
|
||||
{
|
||||
if(mBlob)
|
||||
if (mBlob)
|
||||
{
|
||||
sqlite3_blob_close(mBlob);
|
||||
mBlob = nullptr;
|
||||
|
@ -144,21 +142,21 @@ qint64 ImageBlobDevice::size() const
|
|||
|
||||
qint64 ImageBlobDevice::writeData(const char *data, qint64 len)
|
||||
{
|
||||
if(!mBlob)
|
||||
if (!mBlob)
|
||||
return -1;
|
||||
|
||||
int offset = int(pos());
|
||||
if(len + offset >= mSize)
|
||||
if (len + offset >= mSize)
|
||||
len = mSize - offset;
|
||||
|
||||
if(!len)
|
||||
if (!len)
|
||||
return -1;
|
||||
|
||||
int rc = sqlite3_blob_write(mBlob, data, int(len), offset);
|
||||
if(rc == SQLITE_OK)
|
||||
if (rc == SQLITE_OK)
|
||||
return len;
|
||||
|
||||
if(rc == SQLITE_READONLY)
|
||||
if (rc == SQLITE_READONLY)
|
||||
return -1;
|
||||
|
||||
setErrorString(sqlite3_errmsg(mDb));
|
||||
|
@ -167,45 +165,46 @@ qint64 ImageBlobDevice::writeData(const char *data, qint64 len)
|
|||
|
||||
qint64 ImageBlobDevice::readData(char *data, qint64 maxlen)
|
||||
{
|
||||
if(!mBlob)
|
||||
if (!mBlob)
|
||||
return -1;
|
||||
|
||||
int offset = int(pos());
|
||||
if(maxlen + offset >= mSize)
|
||||
if (maxlen + offset >= mSize)
|
||||
maxlen = mSize - offset;
|
||||
|
||||
if(!maxlen)
|
||||
if (!maxlen)
|
||||
return -1;
|
||||
|
||||
int rc = sqlite3_blob_read(mBlob, data, int(maxlen), offset);
|
||||
if(rc == SQLITE_OK)
|
||||
if (rc == SQLITE_OK)
|
||||
return maxlen;
|
||||
|
||||
setErrorString(sqlite3_errmsg(mDb));
|
||||
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;
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
int rc = sqlite3_prepare_v2(db.db(), sql_get_key_id, sizeof (sql_get_key_id) - 1, &stmt, nullptr);
|
||||
if(rc != SQLITE_OK)
|
||||
int rc =
|
||||
sqlite3_prepare_v2(db.db(), sql_get_key_id, sizeof(sql_get_key_id) - 1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK)
|
||||
return nullptr;
|
||||
|
||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
rc = sqlite3_step(stmt);
|
||||
|
||||
qint64 rowId = 0;
|
||||
if(rc != SQLITE_ROW)
|
||||
if (rc != SQLITE_ROW)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return nullptr;
|
||||
|
@ -214,7 +213,7 @@ ImageBlobDevice* getImage(sqlite3pp::database& db, const MetaDataManager::Key &k
|
|||
rowId = sqlite3_column_int64(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if(!rowId)
|
||||
if (!rowId)
|
||||
return nullptr;
|
||||
|
||||
ImageBlobDevice *dev = new ImageBlobDevice(db.db());
|
||||
|
@ -222,11 +221,11 @@ ImageBlobDevice* getImage(sqlite3pp::database& db, const MetaDataManager::Key &k
|
|||
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(?, ?)");
|
||||
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);
|
||||
else
|
||||
sqlite3_bind_null(cmd.stmt(), 2);
|
||||
|
|
|
@ -27,10 +27,9 @@
|
|||
typedef struct sqlite3 sqlite3;
|
||||
typedef struct sqlite3_blob sqlite3_blob;
|
||||
|
||||
namespace ImageMetaData
|
||||
{
|
||||
namespace ImageMetaData {
|
||||
|
||||
//TODO: move to utils
|
||||
// TODO: move to utils
|
||||
class ImageBlobDevice : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -38,7 +37,7 @@ public:
|
|||
ImageBlobDevice(sqlite3 *db, QObject *parent = nullptr);
|
||||
~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);
|
||||
|
||||
|
@ -61,8 +60,8 @@ private:
|
|||
QByteArray mColumn;
|
||||
};
|
||||
|
||||
ImageBlobDevice *getImage(sqlite3pp::database& db, const MetaDataManager::Key& key);
|
||||
void setImage(sqlite3pp::database& db, const MetaDataManager::Key &key, const void *data, int size);
|
||||
ImageBlobDevice *getImage(sqlite3pp::database &db, const MetaDataManager::Key &key);
|
||||
void setImage(sqlite3pp::database &db, const MetaDataManager::Key &key, const void *data, int size);
|
||||
|
||||
} // namespace ImageMetaData
|
||||
|
||||
|
|
|
@ -47,28 +47,34 @@ MeetingInformationDialog::MeetingInformationDialog(QWidget *parent) :
|
|||
ui->setupUi(this);
|
||||
|
||||
connect(ui->viewPictureBut, &QPushButton::clicked, this, &MeetingInformationDialog::showImage);
|
||||
connect(ui->importPictureBut, &QPushButton::clicked, this, &MeetingInformationDialog::importImage);
|
||||
connect(ui->removePictureBut, &QPushButton::clicked, this, &MeetingInformationDialog::removeImage);
|
||||
connect(ui->resetHeaderBut, &QPushButton::clicked, this, &MeetingInformationDialog::toggleHeader);
|
||||
connect(ui->resetFooterBut, &QPushButton::clicked, this, &MeetingInformationDialog::toggleFooter);
|
||||
connect(ui->startDate, &QDateEdit::dateChanged, this, &MeetingInformationDialog::updateMinumumDate);
|
||||
connect(ui->importPictureBut, &QPushButton::clicked, this,
|
||||
&MeetingInformationDialog::importImage);
|
||||
connect(ui->removePictureBut, &QPushButton::clicked, this,
|
||||
&MeetingInformationDialog::removeImage);
|
||||
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();
|
||||
sp.setRetainSizeWhenHidden(true);
|
||||
ui->headerEdit->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;
|
||||
font.setBold(true);
|
||||
font.setPointSize(18);
|
||||
ui->descrEdit->document()->setDefaultFont(font);
|
||||
|
||||
if(!loadData())
|
||||
if (!loadData())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Database Error"),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +88,7 @@ bool MeetingInformationDialog::loadData()
|
|||
{
|
||||
MetaDataManager *meta = Session->getMetaDataManager();
|
||||
|
||||
qint64 tmp = 0;
|
||||
qint64 tmp = 0;
|
||||
QDate date;
|
||||
|
||||
switch (meta->getInt64(tmp, MetaDataKey::MeetingStartDate))
|
||||
|
@ -93,7 +99,7 @@ bool MeetingInformationDialog::loadData()
|
|||
break;
|
||||
}
|
||||
case MetaDataKey::Result::NoMetaDataTable:
|
||||
return false; //Database has no well-formed metadata
|
||||
return false; // Database has no well-formed metadata
|
||||
default:
|
||||
date = QDate::currentDate();
|
||||
}
|
||||
|
@ -126,7 +132,7 @@ bool MeetingInformationDialog::loadData()
|
|||
text.clear();
|
||||
meta->getString(text, MetaDataKey::MeetingDescription);
|
||||
ui->descrEdit->setPlainText(text);
|
||||
//Align all text to center
|
||||
// Align all text to center
|
||||
QTextCursor c = ui->descrEdit->textCursor();
|
||||
c.select(QTextCursor::Document);
|
||||
QTextBlockFormat fmt;
|
||||
|
@ -145,11 +151,12 @@ bool MeetingInformationDialog::loadData()
|
|||
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);
|
||||
|
||||
if(isNull)
|
||||
if (isNull)
|
||||
{
|
||||
but->setText(tr("Set custom text"));
|
||||
lineEdit->setText(QString());
|
||||
|
@ -170,15 +177,18 @@ void MeetingInformationDialog::saveData()
|
|||
meta->setInt64(ui->showDatesBox->isChecked() ? 1 : 0, false, MetaDataKey::MeetingShowDates);
|
||||
|
||||
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->headerEdit->text().simplified(), headerIsNull, MetaDataKey::SheetHeaderText);
|
||||
meta->setString(ui->footerEdit->text().simplified(), footerIsNull, MetaDataKey::SheetFooterText);
|
||||
meta->setString(ui->headerEdit->text().simplified(), headerIsNull,
|
||||
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);
|
||||
}
|
||||
|
@ -189,10 +199,13 @@ void MeetingInformationDialog::saveData()
|
|||
buf.open(QIODevice::WriteOnly);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -203,25 +216,28 @@ void MeetingInformationDialog::showImage()
|
|||
{
|
||||
OwningQPointer<ImageViewer> dlg = new ImageViewer(this);
|
||||
|
||||
if(img.isNull() && !needsToSaveImg)
|
||||
if (img.isNull() && !needsToSaveImg)
|
||||
{
|
||||
std::unique_ptr<ImageMetaData::ImageBlobDevice> imageIO;
|
||||
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());
|
||||
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();
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "MeetingInformationDialog: error query image," << Session->m_Db.error_msg();
|
||||
}
|
||||
}
|
||||
|
@ -230,15 +246,15 @@ void MeetingInformationDialog::showImage()
|
|||
|
||||
dlg->exec();
|
||||
|
||||
if(!needsToSaveImg)
|
||||
img = QImage(); //Cleanup to free memory
|
||||
if (!needsToSaveImg)
|
||||
img = QImage(); // Cleanup to free memory
|
||||
}
|
||||
|
||||
void MeetingInformationDialog::importImage()
|
||||
{
|
||||
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->setAcceptMode(QFileDialog::AcceptOpen);
|
||||
dlg->setDirectory(RecentDirStore::getDir(meeting_image_key, RecentDirStore::Images));
|
||||
|
@ -246,28 +262,28 @@ void MeetingInformationDialog::importImage()
|
|||
QList<QByteArray> mimes = QImageReader::supportedMimeTypes();
|
||||
QStringList filters;
|
||||
filters.reserve(mimes.size() + 1);
|
||||
for(const QByteArray &ba : mimes)
|
||||
for (const QByteArray &ba : mimes)
|
||||
filters.append(QString::fromUtf8(ba));
|
||||
|
||||
filters << "application/octet-stream"; // will show "All files (*)"
|
||||
|
||||
dlg->setMimeTypeFilters(filters);
|
||||
|
||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
||||
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||
return;
|
||||
|
||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||
if(fileName.isEmpty())
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
RecentDirStore::setPath(meeting_image_key, fileName);
|
||||
|
||||
QImageReader reader(fileName);
|
||||
reader.setQuality(100);
|
||||
if(reader.canRead())
|
||||
if (reader.canRead())
|
||||
{
|
||||
QImage image = reader.read();
|
||||
if(image.isNull())
|
||||
if (image.isNull())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Importing error"),
|
||||
tr("The image format is not supported or the file is corrupted."));
|
||||
|
@ -275,7 +291,7 @@ void MeetingInformationDialog::importImage()
|
|||
return;
|
||||
}
|
||||
|
||||
img = image;
|
||||
img = image;
|
||||
needsToSaveImg = true;
|
||||
}
|
||||
}
|
||||
|
@ -284,10 +300,10 @@ void MeetingInformationDialog::removeImage()
|
|||
{
|
||||
int ret = QMessageBox::question(this, tr("Remove image?"),
|
||||
tr("Are you sure to remove the image logo?"));
|
||||
if(ret != QMessageBox::Yes)
|
||||
if (ret != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
img = QImage(); //Cleanup to free memory
|
||||
img = QImage(); // Cleanup to free memory
|
||||
needsToSaveImg = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,29 +21,29 @@
|
|||
|
||||
#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_set_metadata[] = "REPLACE INTO metadata(name, val) VALUES(?, ?)";
|
||||
constexpr char sql_set_metadata[] = "REPLACE INTO metadata(name, val) VALUES(?, ?)";
|
||||
|
||||
MetaDataManager::MetaDataManager(sqlite3pp::database &db) :
|
||||
mDb(db)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MetaDataKey::Result MetaDataManager::hasKey(const MetaDataManager::Key &key)
|
||||
{
|
||||
MetaDataKey::Result result = MetaDataKey::Result::NoMetaDataTable;
|
||||
if(!mDb.db())
|
||||
if (!mDb.db())
|
||||
return result;
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_has_metadata_key, sizeof (sql_has_metadata_key) - 1, &stmt, nullptr);
|
||||
if(rc != SQLITE_OK)
|
||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_has_metadata_key, sizeof(sql_has_metadata_key) - 1,
|
||||
&stmt, nullptr);
|
||||
if (rc != SQLITE_OK)
|
||||
return result;
|
||||
|
||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
|
@ -51,11 +51,11 @@ MetaDataKey::Result MetaDataManager::hasKey(const MetaDataManager::Key &key)
|
|||
|
||||
rc = sqlite3_step(stmt);
|
||||
|
||||
if(rc == SQLITE_ROW)
|
||||
if (rc == SQLITE_ROW)
|
||||
{
|
||||
result = MetaDataKey::Result::ValueFound;
|
||||
}
|
||||
else if(rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||
else if (rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||
{
|
||||
result = MetaDataKey::Result::ValueNotFound;
|
||||
}
|
||||
|
@ -68,19 +68,20 @@ MetaDataKey::Result MetaDataManager::hasKey(const MetaDataManager::Key &key)
|
|||
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;
|
||||
if(!mDb.db())
|
||||
if (!mDb.db())
|
||||
return result;
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_get_metadata, sizeof (sql_get_metadata) - 1, &stmt, nullptr);
|
||||
if(rc != SQLITE_OK)
|
||||
int rc =
|
||||
sqlite3_prepare_v2(mDb.db(), sql_get_metadata, sizeof(sql_get_metadata) - 1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK)
|
||||
return result;
|
||||
|
||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
|
@ -88,19 +89,19 @@ MetaDataKey::Result MetaDataManager::getInt64(qint64 &out, const Key& key)
|
|||
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -113,29 +114,30 @@ MetaDataKey::Result MetaDataManager::getInt64(qint64 &out, const Key& key)
|
|||
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;
|
||||
if(!mDb.db())
|
||||
if (!mDb.db())
|
||||
return result;
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_set_metadata, sizeof (sql_set_metadata) - 1, &stmt, nullptr);
|
||||
if(rc != SQLITE_OK)
|
||||
int rc =
|
||||
sqlite3_prepare_v2(mDb.db(), sql_set_metadata, sizeof(sql_set_metadata) - 1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK)
|
||||
return result;
|
||||
|
||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
}
|
||||
|
||||
if(setToNull)
|
||||
if (setToNull)
|
||||
rc = sqlite3_bind_null(stmt, 2);
|
||||
else
|
||||
rc = sqlite3_bind_int64(stmt, 2, in);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
|
@ -143,7 +145,7 @@ MetaDataKey::Result MetaDataManager::setInt64(qint64 in, bool setToNull, const K
|
|||
|
||||
rc = sqlite3_step(stmt);
|
||||
|
||||
if(rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||
if (rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||
{
|
||||
result = MetaDataKey::Result::ValueFound;
|
||||
}
|
||||
|
@ -156,19 +158,20 @@ MetaDataKey::Result MetaDataManager::setInt64(qint64 in, bool setToNull, const K
|
|||
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;
|
||||
if(!mDb.db())
|
||||
if (!mDb.db())
|
||||
return result;
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_get_metadata, sizeof (sql_get_metadata) - 1, &stmt, nullptr);
|
||||
if(rc != SQLITE_OK)
|
||||
int rc =
|
||||
sqlite3_prepare_v2(mDb.db(), sql_get_metadata, sizeof(sql_get_metadata) - 1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK)
|
||||
return result;
|
||||
|
||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
|
@ -176,21 +179,21 @@ MetaDataKey::Result MetaDataManager::getString(QString &out, const Key& key)
|
|||
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = MetaDataKey::Result::ValueFound;
|
||||
const int len = sqlite3_column_bytes(stmt, 0);
|
||||
const char *text = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 0));
|
||||
out = QString::fromUtf8(text, len);
|
||||
result = MetaDataKey::Result::ValueFound;
|
||||
const int len = sqlite3_column_bytes(stmt, 0);
|
||||
const char *text = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 0));
|
||||
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;
|
||||
}
|
||||
|
@ -203,19 +206,20 @@ MetaDataKey::Result MetaDataManager::getString(QString &out, const Key& key)
|
|||
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;
|
||||
if(!mDb.db())
|
||||
if (!mDb.db())
|
||||
return result;
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
int rc = sqlite3_prepare_v2(mDb.db(), sql_set_metadata, sizeof (sql_set_metadata) - 1, &stmt, nullptr);
|
||||
if(rc != SQLITE_OK)
|
||||
int rc =
|
||||
sqlite3_prepare_v2(mDb.db(), sql_set_metadata, sizeof(sql_set_metadata) - 1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK)
|
||||
return result;
|
||||
|
||||
rc = sqlite3_bind_text(stmt, 1, key.str, key.len, SQLITE_STATIC);
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
|
@ -223,13 +227,13 @@ MetaDataKey::Result MetaDataManager::setString(const QString& in, bool setToNull
|
|||
|
||||
QByteArray arr = in.toUtf8();
|
||||
|
||||
if(setToNull)
|
||||
if (setToNull)
|
||||
rc = sqlite3_bind_null(stmt, 2);
|
||||
else
|
||||
{
|
||||
rc = sqlite3_bind_text(stmt, 2, arr.data(), arr.size(), SQLITE_STATIC);
|
||||
}
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
|
@ -237,7 +241,7 @@ MetaDataKey::Result MetaDataManager::setString(const QString& in, bool setToNull
|
|||
|
||||
rc = sqlite3_step(stmt);
|
||||
|
||||
if(rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||
if (rc == SQLITE_OK || rc == SQLITE_DONE)
|
||||
{
|
||||
result = MetaDataKey::Result::ValueFound;
|
||||
}
|
||||
|
|
|
@ -27,42 +27,46 @@ namespace sqlite3pp {
|
|||
class database;
|
||||
}
|
||||
|
||||
namespace MetaDataKey
|
||||
{
|
||||
namespace MetaDataKey {
|
||||
enum Result
|
||||
{
|
||||
ValueFound = 0,
|
||||
ValueIsNull,
|
||||
ValueNotFound,
|
||||
NoMetaDataTable, //Format is too old, 'metadata' table is not present
|
||||
NoMetaDataTable, // Format is too old, 'metadata' table is not present
|
||||
|
||||
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
|
||||
constexpr char FormatVersionKey[] = "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'
|
||||
// Database
|
||||
constexpr char FormatVersionKey[] =
|
||||
"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
|
||||
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 MeetingEndDate[] = "meeting_end_date"; //INTEGER: End date in Juliand Day integer
|
||||
constexpr char MeetingLocation[] = "meeting_location"; //STRING: city name
|
||||
constexpr char MeetingDescription[] = "meeting_descr"; //STRING: brief description of the meeting
|
||||
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
|
||||
// Meeting
|
||||
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 MeetingEndDate[] = "meeting_end_date"; // INTEGER: End date in Juliand Day integer
|
||||
constexpr char MeetingLocation[] = "meeting_location"; // STRING: city name
|
||||
constexpr char MeetingDescription[] = "meeting_descr"; // STRING: brief description of the meeting
|
||||
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
|
||||
constexpr char SheetHeaderText[] = "sheet_header"; //STRING: sheet header text
|
||||
constexpr char SheetFooterText[] = "sheet_footer"; //STRING: sheet footer text
|
||||
// ODT Export Sheet
|
||||
constexpr char SheetHeaderText[] = "sheet_header"; // STRING: sheet header text
|
||||
constexpr char SheetFooterText[] = "sheet_footer"; // STRING: sheet footer text
|
||||
|
||||
//Jobs
|
||||
#define METADATA_MAKE_RS_KEY(category) ("job_default_stop_" ## #category)
|
||||
// Jobs
|
||||
#define METADATA_MAKE_RS_KEY(category) ("job_default_stop_"## #category)
|
||||
|
||||
//END Key constants
|
||||
}
|
||||
// END Key constants
|
||||
} // namespace MetaDataKey
|
||||
|
||||
class MetaDataManager
|
||||
{
|
||||
|
@ -71,16 +75,20 @@ public:
|
|||
|
||||
struct Key
|
||||
{
|
||||
template<int N>
|
||||
constexpr inline Key(const char (&val)[N]) :str(val), len(N - 1) {}
|
||||
template <int N>
|
||||
constexpr inline Key(const char (&val)[N]) :
|
||||
str(val),
|
||||
len(N - 1)
|
||||
{
|
||||
}
|
||||
|
||||
const char *str;
|
||||
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 getString(QString &out, const Key &key);
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
add_subdirectory(model)
|
||||
add_subdirectory(view)
|
||||
add_subdirectory(model) add_subdirectory(view)
|
||||
|
||||
set(MR_TIMETABLE_PLANNER_SOURCES
|
||||
${MR_TIMETABLE_PLANNER_SOURCES}
|
||||
graph/linegraphtypes.h
|
||||
graph/linegraphtypes.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
set(MR_TIMETABLE_PLANNER_SOURCES ${MR_TIMETABLE_PLANNER_SOURCES} graph / linegraphtypes.h graph
|
||||
/ linegraphtypes.cpp PARENT_SCOPE)
|
||||
|
|
|
@ -28,16 +28,14 @@ public:
|
|||
static const char *texts[];
|
||||
};
|
||||
|
||||
const char *LineGraphTypeNames::texts[] = {
|
||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "No Graph"),
|
||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Station"),
|
||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Segment"),
|
||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Line")
|
||||
};
|
||||
const char *LineGraphTypeNames::texts[] = {QT_TRANSLATE_NOOP("LineGraphTypeNames", "No Graph"),
|
||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Station"),
|
||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Segment"),
|
||||
QT_TRANSLATE_NOOP("LineGraphTypeNames", "Line")};
|
||||
|
||||
QString utils::getLineGraphTypeName(LineGraphType type)
|
||||
{
|
||||
if(type >= LineGraphType::NTypes)
|
||||
if (type >= LineGraphType::NTypes)
|
||||
return QString();
|
||||
return LineGraphTypeNames::tr(LineGraphTypeNames::texts[int(type)]);
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@
|
|||
*/
|
||||
enum class LineGraphType
|
||||
{
|
||||
NoGraph = 0, //!< No content displayed
|
||||
SingleStation, //!< Show a single station
|
||||
NoGraph = 0, //!< No content displayed
|
||||
SingleStation, //!< Show a single station
|
||||
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
|
||||
};
|
||||
|
||||
|
|
|
@ -41,34 +41,41 @@ LineGraphManager::LineGraphManager(QObject *parent) :
|
|||
m_hasScheduledUpdate(false)
|
||||
{
|
||||
auto session = Session;
|
||||
//Stations
|
||||
connect(session, &MeetingSession::stationNameChanged, this, &LineGraphManager::onStationNameChanged);
|
||||
connect(session, &MeetingSession::stationJobsPlanChanged, this, &LineGraphManager::onStationJobPlanChanged);
|
||||
connect(session, &MeetingSession::stationTrackPlanChanged, this, &LineGraphManager::onStationTrackPlanChanged);
|
||||
// Stations
|
||||
connect(session, &MeetingSession::stationNameChanged, this,
|
||||
&LineGraphManager::onStationNameChanged);
|
||||
connect(session, &MeetingSession::stationJobsPlanChanged, this,
|
||||
&LineGraphManager::onStationJobPlanChanged);
|
||||
connect(session, &MeetingSession::stationTrackPlanChanged, this,
|
||||
&LineGraphManager::onStationTrackPlanChanged);
|
||||
connect(session, &MeetingSession::stationRemoved, this, &LineGraphManager::onStationRemoved);
|
||||
|
||||
//Segments
|
||||
connect(session, &MeetingSession::segmentNameChanged, this, &LineGraphManager::onSegmentNameChanged);
|
||||
connect(session, &MeetingSession::segmentStationsChanged, this, &LineGraphManager::onSegmentStationsChanged);
|
||||
// Segments
|
||||
connect(session, &MeetingSession::segmentNameChanged, this,
|
||||
&LineGraphManager::onSegmentNameChanged);
|
||||
connect(session, &MeetingSession::segmentStationsChanged, this,
|
||||
&LineGraphManager::onSegmentStationsChanged);
|
||||
connect(session, &MeetingSession::segmentRemoved, this, &LineGraphManager::onSegmentRemoved);
|
||||
|
||||
//Lines
|
||||
// Lines
|
||||
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);
|
||||
|
||||
//Jobs
|
||||
// Jobs
|
||||
connect(session, &MeetingSession::jobChanged, this, &LineGraphManager::onJobChanged);
|
||||
connect(session, &MeetingSession::jobRemoved, this, &LineGraphManager::onJobRemoved);
|
||||
|
||||
//Settings
|
||||
connect(&AppSettings, &MRTPSettings::jobGraphOptionsChanged, this, &LineGraphManager::updateGraphOptions);
|
||||
// Settings
|
||||
connect(&AppSettings, &MRTPSettings::jobGraphOptionsChanged, this,
|
||||
&LineGraphManager::updateGraphOptions);
|
||||
m_followJobOnGraphChange = AppSettings.getFollowSelectionOnGraphChange();
|
||||
}
|
||||
|
||||
bool LineGraphManager::event(QEvent *ev)
|
||||
{
|
||||
if(ev->type() == QEvent::Type(CustomEvents::LineGraphManagerUpdate))
|
||||
if (ev->type() == QEvent::Type(CustomEvents::LineGraphManagerUpdate))
|
||||
{
|
||||
ev->accept();
|
||||
processPendingUpdates();
|
||||
|
@ -88,13 +95,13 @@ void LineGraphManager::registerScene(LineGraphScene *scene)
|
|||
connect(scene, &LineGraphScene::sceneActivated, this, &LineGraphManager::setActiveScene);
|
||||
connect(scene, &LineGraphScene::jobSelected, this, &LineGraphManager::onJobSelected);
|
||||
|
||||
if(m_followJobOnGraphChange)
|
||||
if (m_followJobOnGraphChange)
|
||||
connect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
||||
|
||||
if(scenes.count() == 1)
|
||||
if (scenes.count() == 1)
|
||||
{
|
||||
//This is the first scene registered
|
||||
//activate it so we have an active scene even if user does't activate one
|
||||
// This is the first scene registered
|
||||
// activate it so we have an active scene even if user does't activate one
|
||||
setActiveScene(scene);
|
||||
}
|
||||
}
|
||||
|
@ -109,17 +116,17 @@ void LineGraphManager::unregisterScene(LineGraphScene *scene)
|
|||
disconnect(scene, &LineGraphScene::sceneActivated, this, &LineGraphManager::setActiveScene);
|
||||
disconnect(scene, &LineGraphScene::jobSelected, this, &LineGraphManager::onJobSelected);
|
||||
|
||||
if(m_followJobOnGraphChange)
|
||||
if (m_followJobOnGraphChange)
|
||||
disconnect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
||||
|
||||
//Reset active scene if it is unregistered
|
||||
if(activeScene == scene)
|
||||
// Reset active scene if it is unregistered
|
||||
if (activeScene == scene)
|
||||
setActiveScene(nullptr);
|
||||
}
|
||||
|
||||
void LineGraphManager::clearAllGraphs()
|
||||
{
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
scene->loadGraph(0, LineGraphType::NoGraph, true);
|
||||
}
|
||||
|
@ -127,9 +134,9 @@ void LineGraphManager::clearAllGraphs()
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -137,61 +144,60 @@ void LineGraphManager::clearGraphsOfObject(db_id objectId, LineGraphType type)
|
|||
JobStopEntry LineGraphManager::getCurrentSelectedJob() const
|
||||
{
|
||||
JobStopEntry selectedJob;
|
||||
if(activeScene)
|
||||
if (activeScene)
|
||||
selectedJob = activeScene->getSelectedJob();
|
||||
return selectedJob;
|
||||
}
|
||||
|
||||
void LineGraphManager::scheduleUpdate()
|
||||
{
|
||||
if(m_hasScheduledUpdate)
|
||||
return; //Already scheduled
|
||||
if (m_hasScheduledUpdate)
|
||||
return; // Already scheduled
|
||||
|
||||
//Mark as scheduled and post event to ourself
|
||||
// Mark as scheduled and post event to ourself
|
||||
m_hasScheduledUpdate = true;
|
||||
QCoreApplication::postEvent(this,
|
||||
new QEvent(QEvent::Type(CustomEvents::LineGraphManagerUpdate)),
|
||||
Qt::HighEventPriority);
|
||||
QCoreApplication::postEvent(
|
||||
this, new QEvent(QEvent::Type(CustomEvents::LineGraphManagerUpdate)), Qt::HighEventPriority);
|
||||
}
|
||||
|
||||
void LineGraphManager::processPendingUpdates()
|
||||
{
|
||||
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;
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
if(timer.elapsed() > MAX_UPDATE_TIME_MS)
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
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();
|
||||
break;
|
||||
}
|
||||
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::NothingToDo))
|
||||
continue; //Skip
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::NothingToDo))
|
||||
continue; // Skip
|
||||
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
{
|
||||
scene->reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::ReloadJobs))
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::ReloadJobs))
|
||||
{
|
||||
scene->reloadJobs();
|
||||
}
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::ReloadStationNames))
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::ReloadStationNames))
|
||||
{
|
||||
scene->updateStationNames();
|
||||
}
|
||||
|
||||
//Manually cleare pending update and trigger redraw
|
||||
// Manually cleare pending update and trigger redraw
|
||||
scene->pendingUpdate = PendingUpdate::NothingToDo;
|
||||
emit scene->redrawGraph();
|
||||
}
|
||||
|
@ -202,28 +208,28 @@ void LineGraphManager::setActiveScene(IGraphScene *scene)
|
|||
{
|
||||
LineGraphScene *lineScene = qobject_cast<LineGraphScene *>(scene);
|
||||
|
||||
if(lineScene)
|
||||
if (lineScene)
|
||||
{
|
||||
if(activeScene == lineScene)
|
||||
if (activeScene == lineScene)
|
||||
return;
|
||||
|
||||
//NOTE: Only registere scenes can become active
|
||||
//Otherwise we cannot track if scene got destroyed and reset active scene.
|
||||
if(!scenes.contains(lineScene))
|
||||
// NOTE: Only registere scenes can become active
|
||||
// Otherwise we cannot track if scene got destroyed and reset active scene.
|
||||
if (!scenes.contains(lineScene))
|
||||
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();
|
||||
}
|
||||
|
||||
activeScene = lineScene;
|
||||
emit activeSceneChanged(activeScene);
|
||||
|
||||
//Triegger selection update or clear it
|
||||
// Triegger selection update or clear it
|
||||
JobStopEntry selectedJob;
|
||||
if(activeScene)
|
||||
if (activeScene)
|
||||
{
|
||||
selectedJob = activeScene->getSelectedJob();
|
||||
}
|
||||
|
@ -239,58 +245,60 @@ void LineGraphManager::onSceneDestroyed(QObject *obj)
|
|||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!graphObjId || scene->getGraphType() == LineGraphType::NoGraph)
|
||||
return; //No graph selected
|
||||
if (!graphObjId || scene->getGraphType() == LineGraphType::NoGraph)
|
||||
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();
|
||||
if(!selectedJob.jobId)
|
||||
return; //No job selected, nothing to do
|
||||
if (!selectedJob.jobId)
|
||||
return; // No job selected, nothing to do
|
||||
|
||||
LineGraphSelectionHelper helper(Session->m_Db);
|
||||
|
||||
LineGraphSelectionHelper::SegmentInfo info;
|
||||
if(!helper.tryFindJobStopInGraph(scene, selectedJob.jobId, info))
|
||||
return; //Cannot find job in current graph, give up
|
||||
if (!helper.tryFindJobStopInGraph(scene, selectedJob.jobId, info))
|
||||
return; // Cannot find job in current graph, give up
|
||||
|
||||
//Ensure job is visible
|
||||
scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart, info.departure);
|
||||
// Ensure job is visible
|
||||
scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart,
|
||||
info.departure);
|
||||
}
|
||||
|
||||
void LineGraphManager::onJobSelected(db_id jobId, int category, db_id stopId)
|
||||
{
|
||||
JobCategory cat = JobCategory(category);
|
||||
if(lastSelectedJob.jobId == jobId && lastSelectedJob.category == cat && lastSelectedJob.stopId == stopId)
|
||||
return; //Selection did not change
|
||||
if (lastSelectedJob.jobId == jobId && lastSelectedJob.category == cat
|
||||
&& lastSelectedJob.stopId == stopId)
|
||||
return; // Selection did not change
|
||||
|
||||
lastSelectedJob.jobId = jobId;
|
||||
lastSelectedJob.jobId = jobId;
|
||||
lastSelectedJob.category = cat;
|
||||
lastSelectedJob.stopId = stopId;
|
||||
lastSelectedJob.stopId = stopId;
|
||||
|
||||
if(jobId)
|
||||
if (jobId)
|
||||
Session->getViewManager()->requestJobEditor(jobId);
|
||||
else
|
||||
Session->getViewManager()->requestClearJob();
|
||||
|
||||
if(AppSettings.getSyncSelectionOnAllGraphs())
|
||||
if (AppSettings.getSyncSelectionOnAllGraphs())
|
||||
{
|
||||
//Sync selection among all registered scenes
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
// Sync selection among all registered scenes
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
scene->setSelectedJob(lastSelectedJob);
|
||||
}
|
||||
}
|
||||
|
||||
if(activeScene)
|
||||
if (activeScene)
|
||||
{
|
||||
const JobStopEntry selectedJob = activeScene->getSelectedJob();
|
||||
if(selectedJob.jobId == lastSelectedJob.jobId)
|
||||
if (selectedJob.jobId == lastSelectedJob.jobId)
|
||||
{
|
||||
emit jobSelected(lastSelectedJob.jobId, int(lastSelectedJob.category),
|
||||
lastSelectedJob.stopId);
|
||||
|
@ -302,23 +310,23 @@ void LineGraphManager::onStationNameChanged(db_id stationId)
|
|||
{
|
||||
bool found = false;
|
||||
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
continue; //Already flagged
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
continue; // Already flagged
|
||||
|
||||
if(scene->stations.contains(stationId))
|
||||
if (scene->stations.contains(stationId))
|
||||
{
|
||||
scene->pendingUpdate.setFlag(PendingUpdate::ReloadStationNames);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(found)
|
||||
if (found)
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
void LineGraphManager::onStationJobPlanChanged(const QSet<db_id>& stationIds)
|
||||
void LineGraphManager::onStationJobPlanChanged(const QSet<db_id> &stationIds)
|
||||
{
|
||||
onStationPlanChanged_internal(stationIds, int(PendingUpdate::ReloadJobs));
|
||||
}
|
||||
|
@ -330,9 +338,9 @@ void LineGraphManager::onStationTrackPlanChanged(const QSet<db_id> &stationIds)
|
|||
|
||||
void LineGraphManager::onStationRemoved(db_id stationId)
|
||||
{
|
||||
//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
|
||||
//The removed station
|
||||
// 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
|
||||
// The removed station
|
||||
clearGraphsOfObject(stationId, LineGraphType::SingleStation);
|
||||
}
|
||||
|
||||
|
@ -340,25 +348,25 @@ void LineGraphManager::onSegmentNameChanged(db_id segmentId)
|
|||
{
|
||||
QString segName;
|
||||
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
continue; //Already flagged
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
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=?");
|
||||
q.bind(1, segmentId);
|
||||
if(q.step() != SQLITE_ROW)
|
||||
if (q.step() != SQLITE_ROW)
|
||||
{
|
||||
qWarning() << "Graph: invalid segment ID" << segmentId;
|
||||
return;
|
||||
}
|
||||
|
||||
//Store segment name
|
||||
// Store segment name
|
||||
segName = q.getRows().get<QString>(0);
|
||||
}
|
||||
|
||||
|
@ -372,16 +380,16 @@ void LineGraphManager::onSegmentStationsChanged(db_id segmentId)
|
|||
{
|
||||
bool found = false;
|
||||
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
continue; //Already flagged
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
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);
|
||||
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);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(found)
|
||||
if (found)
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
void LineGraphManager::onSegmentRemoved(db_id segmentId)
|
||||
{
|
||||
//A segment can be removed only when is not on any line
|
||||
//And when no jobs pass through it.
|
||||
//So there is no need to update other line scenes because no line will contain
|
||||
//The removed segment
|
||||
// A segment can be removed only when is not on any line
|
||||
// And when no jobs pass through it.
|
||||
// So there is no need to update other line scenes because no line will contain
|
||||
// The removed segment
|
||||
clearGraphsOfObject(segmentId, LineGraphType::RailwaySegment);
|
||||
}
|
||||
|
||||
|
@ -413,25 +422,25 @@ void LineGraphManager::onLineNameChanged(db_id lineId)
|
|||
{
|
||||
QString lineName;
|
||||
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
continue; //Already flagged
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
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=?");
|
||||
q.bind(1, lineId);
|
||||
if(q.step() != SQLITE_ROW)
|
||||
if (q.step() != SQLITE_ROW)
|
||||
{
|
||||
qWarning() << "Graph: invalid line ID" << lineId;
|
||||
return;
|
||||
}
|
||||
|
||||
//Store line name
|
||||
// Store line name
|
||||
lineName = q.getRows().get<QString>(0);
|
||||
}
|
||||
|
||||
|
@ -445,60 +454,61 @@ void LineGraphManager::onLineSegmentsChanged(db_id lineId)
|
|||
{
|
||||
bool found = false;
|
||||
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
if(scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
continue; //Already flagged
|
||||
if (scene->pendingUpdate.testFlag(PendingUpdate::FullReload))
|
||||
continue; // Already flagged
|
||||
|
||||
if(scene->graphType == LineGraphType::RailwayLine && scene->graphObjectId == lineId)
|
||||
if (scene->graphType == LineGraphType::RailwayLine && scene->graphObjectId == lineId)
|
||||
{
|
||||
scene->pendingUpdate.setFlag(PendingUpdate::FullReload);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(found)
|
||||
if (found)
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
void LineGraphManager::onLineRemoved(db_id lineId)
|
||||
{
|
||||
//Lines do not affect segments and stations
|
||||
//So no other scene needs updating
|
||||
// Lines do not affect segments and stations
|
||||
// So no other scene needs updating
|
||||
clearGraphsOfObject(lineId, LineGraphType::RailwayLine);
|
||||
}
|
||||
|
||||
void LineGraphManager::onJobChanged(db_id jobId, db_id oldJobId)
|
||||
{
|
||||
//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.
|
||||
//In fact when a job changes ID, all station interested by this job get informed, and scenes reloaded
|
||||
// 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.
|
||||
// In fact when a job changes ID, all station interested by this job get informed, and scenes
|
||||
// reloaded
|
||||
|
||||
JobStopEntry selectedJob;
|
||||
selectedJob.jobId = jobId;
|
||||
|
||||
LineGraphScene::updateJobSelection(Session->m_Db, selectedJob);
|
||||
|
||||
if(!selectedJob.jobId)
|
||||
return; //Invalid job ID
|
||||
if (!selectedJob.jobId)
|
||||
return; // Invalid job ID
|
||||
|
||||
if(activeScene && AppSettings.getSyncSelectionOnAllGraphs())
|
||||
if (activeScene && AppSettings.getSyncSelectionOnAllGraphs())
|
||||
{
|
||||
//Update active scene before others in case selection is synced
|
||||
//This way all scenes get updated selection
|
||||
// Update active scene before others in case selection is synced
|
||||
// This way all scenes get updated selection
|
||||
JobStopEntry oldSelectedJob = activeScene->getSelectedJob();
|
||||
if(oldSelectedJob.jobId == oldJobId)
|
||||
if (oldSelectedJob.jobId == oldJobId)
|
||||
{
|
||||
activeScene->setSelectedJob(selectedJob);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Manually update all scenes
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
// Manually update all scenes
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
JobStopEntry oldSelectedJob = scene->getSelectedJob();
|
||||
if(oldSelectedJob.jobId == oldJobId)
|
||||
if (oldSelectedJob.jobId == oldJobId)
|
||||
{
|
||||
scene->setSelectedJob(selectedJob);
|
||||
}
|
||||
|
@ -508,64 +518,66 @@ void LineGraphManager::onJobChanged(db_id jobId, db_id oldJobId)
|
|||
|
||||
void LineGraphManager::onJobRemoved(db_id jobId)
|
||||
{
|
||||
//We already catch normal job removal with other signals
|
||||
if(jobId)
|
||||
// We already catch normal job removal with other signals
|
||||
if (jobId)
|
||||
return;
|
||||
|
||||
//If jobId is zero, it means all jobs have been deleted
|
||||
//Reload all scenes
|
||||
// If jobId is zero, it means all jobs have been deleted
|
||||
// Reload all scenes
|
||||
|
||||
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)))
|
||||
continue; //Already flagged
|
||||
continue; // Already flagged
|
||||
|
||||
scene->pendingUpdate.setFlag(PendingUpdate(PendingUpdate::ReloadJobs));
|
||||
found = true;
|
||||
}
|
||||
|
||||
if(found)
|
||||
if (found)
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
void LineGraphManager::updateGraphOptions()
|
||||
{
|
||||
//TODO: maybe get rid of theese variables in MeetingSession and always use AppSettings?
|
||||
int hourOffset = AppSettings.getHourOffset();
|
||||
Session->hourOffset = hourOffset;
|
||||
// TODO: maybe get rid of theese variables in MeetingSession and always use AppSettings?
|
||||
int hourOffset = AppSettings.getHourOffset();
|
||||
Session->hourOffset = hourOffset;
|
||||
|
||||
int horizOffset = AppSettings.getHorizontalOffset();
|
||||
Session->horizOffset = horizOffset;
|
||||
int horizOffset = AppSettings.getHorizontalOffset();
|
||||
Session->horizOffset = horizOffset;
|
||||
|
||||
int vertOffset = AppSettings.getVerticalOffset();
|
||||
Session->vertOffset = vertOffset;
|
||||
int vertOffset = AppSettings.getVerticalOffset();
|
||||
Session->vertOffset = vertOffset;
|
||||
|
||||
Session->stationOffset = AppSettings.getStationOffset();
|
||||
Session->stationOffset = AppSettings.getStationOffset();
|
||||
Session->platformOffset = AppSettings.getPlatformOffset();
|
||||
|
||||
Session->jobLineWidth = AppSettings.getJobLineWidth();
|
||||
Session->jobLineWidth = AppSettings.getJobLineWidth();
|
||||
|
||||
//Reload all graphs
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
// Reload all graphs
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
scene->reload();
|
||||
}
|
||||
|
||||
const bool oldVal = m_followJobOnGraphChange;
|
||||
const bool oldVal = m_followJobOnGraphChange;
|
||||
m_followJobOnGraphChange = AppSettings.getFollowSelectionOnGraphChange();
|
||||
|
||||
if(m_followJobOnGraphChange != oldVal)
|
||||
if (m_followJobOnGraphChange != oldVal)
|
||||
{
|
||||
//Update connections
|
||||
for(LineGraphScene *scene : qAsConst(scenes))
|
||||
// Update connections
|
||||
for (LineGraphScene *scene : qAsConst(scenes))
|
||||
{
|
||||
if(m_followJobOnGraphChange)
|
||||
connect(scene, &LineGraphScene::graphChanged, this, &LineGraphManager::onGraphChanged);
|
||||
if (m_followJobOnGraphChange)
|
||||
connect(scene, &LineGraphScene::graphChanged, this,
|
||||
&LineGraphManager::onGraphChanged);
|
||||
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;
|
||||
|
||||
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)))
|
||||
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));
|
||||
found = true;
|
||||
|
@ -591,6 +603,6 @@ void LineGraphManager::onStationPlanChanged_internal(const QSet<db_id> &stationI
|
|||
}
|
||||
}
|
||||
|
||||
if(found)
|
||||
if (found)
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
|
|
@ -82,7 +82,10 @@ public:
|
|||
* \brief get active scene
|
||||
* \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
|
||||
|
@ -151,32 +154,32 @@ public slots:
|
|||
void setActiveScene(IGraphScene *scene);
|
||||
|
||||
private slots:
|
||||
//Scenes
|
||||
// Scenes
|
||||
void onSceneDestroyed(QObject *obj);
|
||||
void onGraphChanged(int graphType_, db_id graphObjId, LineGraphScene *scene);
|
||||
void onJobSelected(db_id jobId, int category, db_id stopId);
|
||||
|
||||
//Stations
|
||||
// Stations
|
||||
void onStationNameChanged(db_id stationId);
|
||||
void onStationJobPlanChanged(const QSet<db_id> &stationIds);
|
||||
void onStationTrackPlanChanged(const QSet<db_id> &stationIds);
|
||||
void onStationRemoved(db_id stationId);
|
||||
|
||||
//Segments
|
||||
// Segments
|
||||
void onSegmentNameChanged(db_id segmentId);
|
||||
void onSegmentStationsChanged(db_id segmentId);
|
||||
void onSegmentRemoved(db_id segmentId);
|
||||
|
||||
//Lines
|
||||
// Lines
|
||||
void onLineNameChanged(db_id lineId);
|
||||
void onLineSegmentsChanged(db_id lineId);
|
||||
void onLineRemoved(db_id lineId);
|
||||
|
||||
//Jobs
|
||||
// Jobs
|
||||
void onJobChanged(db_id jobId, db_id oldJobId);
|
||||
void onJobRemoved(db_id jobId);
|
||||
|
||||
//Settings
|
||||
// Settings
|
||||
void updateGraphOptions();
|
||||
|
||||
private:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -57,18 +57,18 @@ public:
|
|||
*/
|
||||
enum class PendingUpdate
|
||||
{
|
||||
NothingToDo = 0x0, //!< No content needs updating
|
||||
ReloadJobs = 0x1, //!< Only Jobs need to be reloaded
|
||||
NothingToDo = 0x0, //!< No content needs updating
|
||||
ReloadJobs = 0x1, //!< Only Jobs need to be reloaded
|
||||
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)
|
||||
|
||||
LineGraphScene(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||
|
||||
void renderContents(QPainter *painter, const QRectF& sceneRect) override;
|
||||
void renderHeader(QPainter *painter, const QRectF& sceneRect,
|
||||
Qt::Orientation orient, double scroll) override;
|
||||
void renderContents(QPainter *painter, const QRectF &sceneRect) override;
|
||||
void renderHeader(QPainter *painter, const QRectF &sceneRect, Qt::Orientation orient,
|
||||
double scroll) override;
|
||||
|
||||
/*!
|
||||
* \brief Load graph contents
|
||||
|
@ -109,7 +109,7 @@ public:
|
|||
* \param pos Point in scene coordinates
|
||||
* \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
|
||||
{
|
||||
|
@ -154,7 +154,10 @@ public:
|
|||
*
|
||||
* \sa setDrawSelection()
|
||||
*/
|
||||
inline bool getDrawSelection() { return m_drawSelection; }
|
||||
inline bool getDrawSelection()
|
||||
{
|
||||
return m_drawSelection;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief setDrawSelection
|
||||
|
@ -165,7 +168,10 @@ public:
|
|||
*
|
||||
* \sa getDrawSelection()
|
||||
*/
|
||||
inline void setDrawSelection(bool val) { m_drawSelection = val; }
|
||||
inline void setDrawSelection(bool val)
|
||||
{
|
||||
m_drawSelection = val;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief requestShowZone
|
||||
|
@ -208,7 +214,6 @@ public slots:
|
|||
void reload();
|
||||
|
||||
private:
|
||||
|
||||
/*!
|
||||
* \brief Graph of the job while is moving
|
||||
*
|
||||
|
@ -308,7 +313,8 @@ private:
|
|||
* Load job segments and stores them in 'from' station
|
||||
* \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
|
||||
|
@ -324,7 +330,7 @@ private:
|
|||
friend class BackgroundHelper;
|
||||
friend class LineGraphManager;
|
||||
|
||||
sqlite3pp::database& mDb;
|
||||
sqlite3pp::database &mDb;
|
||||
|
||||
/*!
|
||||
* \brief Graph Object ID
|
||||
|
|
|
@ -27,10 +27,10 @@ using namespace sqlite3pp;
|
|||
LineGraphSelectionHelper::LineGraphSelectionHelper(sqlite3pp::database &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);
|
||||
|
||||
|
@ -72,7 +72,7 @@ bool LineGraphSelectionHelper::tryFindJobStopInGraph(LineGraphScene *scene, db_i
|
|||
case LineGraphType::NoGraph:
|
||||
case LineGraphType::NTypes:
|
||||
{
|
||||
//We need to load a new graph, give up
|
||||
// We need to load a new graph, give up
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -80,18 +80,18 @@ bool LineGraphSelectionHelper::tryFindJobStopInGraph(LineGraphScene *scene, db_i
|
|||
q.bind(1, jobId);
|
||||
q.bind(2, scene->getGraphObjectId());
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
//Get stop info
|
||||
auto stop = q.getRows();
|
||||
info.firstStopId = stop.get<db_id>(0);
|
||||
info.segmentId = stop.get<db_id>(1);
|
||||
// Get stop info
|
||||
auto stop = q.getRows();
|
||||
info.firstStopId = stop.get<db_id>(0);
|
||||
info.segmentId = stop.get<db_id>(1);
|
||||
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(scene->getGraphType() == LineGraphType::SingleStation)
|
||||
// If graph is SingleStation we already know the station ID
|
||||
if (scene->getGraphType() == LineGraphType::SingleStation)
|
||||
info.firstStationId = scene->getGraphObjectId();
|
||||
else
|
||||
info.firstStationId = stop.get<db_id>(4);
|
||||
|
@ -99,96 +99,98 @@ bool LineGraphSelectionHelper::tryFindJobStopInGraph(LineGraphScene *scene, db_i
|
|||
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"
|
||||
" FROM stops"
|
||||
" LEFT JOIN railway_connections c ON c.id=stops.next_segment_conn_id"
|
||||
" 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(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;
|
||||
|
||||
//Get first stop info
|
||||
auto stop = q.getRows();
|
||||
info.firstStopId = stop.get<db_id>(0);
|
||||
// Get first stop info
|
||||
auto stop = q.getRows();
|
||||
info.firstStopId = stop.get<db_id>(0);
|
||||
info.arrivalAndStart = stop.get<QTime>(1);
|
||||
info.departure = stop.get<QTime>(2);
|
||||
info.firstStationId = stop.get<db_id>(3);
|
||||
info.segmentId = stop.get<db_id>(4);
|
||||
info.departure = stop.get<QTime>(2);
|
||||
info.firstStationId = stop.get<db_id>(3);
|
||||
info.segmentId = stop.get<db_id>(4);
|
||||
q.reset();
|
||||
|
||||
//Try get a second stop after the first departure
|
||||
//NOTE: minimum 60 seconds of travel between 2 consecutive stops
|
||||
// Try get a second stop after the first departure
|
||||
// NOTE: minimum 60 seconds of travel between 2 consecutive stops
|
||||
q.bind(1, jobId);
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Get first stop info
|
||||
// Get first stop info
|
||||
stop = q.getRows();
|
||||
//db_id secondStopId = stop.get<db_id>(0);
|
||||
//QTime secondArrival = stop.get<QTime>(1);
|
||||
info.departure = stop.get<QTime>(2); //Overwrite departure
|
||||
// db_id secondStopId = stop.get<db_id>(0);
|
||||
// QTime secondArrival = stop.get<QTime>(1);
|
||||
info.departure = stop.get<QTime>(2); // Overwrite departure
|
||||
info.secondStationId = stop.get<db_id>(3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LineGraphSelectionHelper::tryFindNewGraphForJob(db_id jobId, SegmentInfo& info,
|
||||
db_id &outGraphObjId, LineGraphType &outGraphType)
|
||||
bool LineGraphSelectionHelper::tryFindNewGraphForJob(db_id jobId, SegmentInfo &info,
|
||||
db_id &outGraphObjId,
|
||||
LineGraphType &outGraphType)
|
||||
{
|
||||
if(!tryFindJobStopsAfter(jobId, info))
|
||||
return false; //No stops found
|
||||
if (!tryFindJobStopsAfter(jobId, info))
|
||||
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;
|
||||
outGraphType = LineGraphType::SingleStation;
|
||||
outGraphType = LineGraphType::SingleStation;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Try to find a railway line which contains this segment
|
||||
//FIXME: better criteria to choose a line (name?, number of segments?, prompt user?)
|
||||
// Try to find a railway line which contains this segment
|
||||
// FIXME: better criteria to choose a line (name?, number of segments?, prompt user?)
|
||||
query q(mDb, "SELECT ls.line_id"
|
||||
" FROM line_segments ls"
|
||||
" WHERE ls.seg_id=?");
|
||||
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);
|
||||
outGraphType = LineGraphType::RailwayLine;
|
||||
outGraphType = LineGraphType::RailwayLine;
|
||||
return true;
|
||||
}
|
||||
|
||||
//No lines found, use the railway segment
|
||||
// No lines found, use the railway segment
|
||||
outGraphObjId = info.segmentId;
|
||||
outGraphType = LineGraphType::RailwaySegment;
|
||||
outGraphType = LineGraphType::RailwaySegment;
|
||||
|
||||
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=?");
|
||||
q.bind(1, jobId);
|
||||
if(q.step() != SQLITE_ROW)
|
||||
return false; //Job doen't exist
|
||||
if (q.step() != SQLITE_ROW)
|
||||
return false; // Job doen't exist
|
||||
|
||||
JobStopEntry selectedJob;
|
||||
selectedJob.jobId = jobId;
|
||||
selectedJob.jobId = jobId;
|
||||
selectedJob.category = JobCategory(q.getRows().get<int>(0));
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||
//do not emit change because selection might be synced between all scenes
|
||||
//and because it's restored soon after
|
||||
// NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||
// do not emit change because selection might be synced between all scenes
|
||||
// and because it's restored soon after
|
||||
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);
|
||||
|
||||
//Restore previous selection
|
||||
// Restore previous selection
|
||||
scene->setSelectedJob(oldSelection, false);
|
||||
}
|
||||
|
||||
//Extract the info
|
||||
// Extract the info
|
||||
selectedJob.stopId = info.firstStopId;
|
||||
|
||||
if(!selectedJob.stopId)
|
||||
return false; //No stop found, abort
|
||||
if (!selectedJob.stopId)
|
||||
return false; // No stop found, abort
|
||||
|
||||
//Select job
|
||||
if(select)
|
||||
// Select job
|
||||
if (select)
|
||||
scene->setSelectedJob(selectedJob);
|
||||
|
||||
if(ensureVisible)
|
||||
if (ensureVisible)
|
||||
{
|
||||
return scene->requestShowZone(info.firstStationId, info.segmentId,
|
||||
info.arrivalAndStart, info.departure);
|
||||
return scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart,
|
||||
info.departure);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LineGraphSelectionHelper::requestCurrentJobPrevSegmentVisible(LineGraphScene *scene, bool goToStart)
|
||||
bool LineGraphSelectionHelper::requestCurrentJobPrevSegmentVisible(LineGraphScene *scene,
|
||||
bool goToStart)
|
||||
{
|
||||
JobStopEntry selectedJob = scene->getSelectedJob();
|
||||
if(!selectedJob.jobId)
|
||||
return false; //No job selected, nothing to do
|
||||
if (!selectedJob.jobId)
|
||||
return false; // No job selected, nothing to do
|
||||
|
||||
query q(mDb);
|
||||
|
||||
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,"
|
||||
"s2.departure, s2.station_id"
|
||||
" FROM stops s2"
|
||||
|
@ -263,71 +266,72 @@ bool LineGraphSelectionHelper::requestCurrentJobPrevSegmentVisible(LineGraphScen
|
|||
" WHERE s2.id=? AND s1.arrival < s2.arrival");
|
||||
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);
|
||||
if(jobId == selectedJob.jobId)
|
||||
if (jobId == selectedJob.jobId)
|
||||
{
|
||||
//Found stop and belongs to requested job
|
||||
info.firstStopId = stop.get<db_id>(1);
|
||||
// Found stop and belongs to requested job
|
||||
info.firstStopId = stop.get<db_id>(1);
|
||||
info.arrivalAndStart = stop.get<QTime>(2);
|
||||
info.firstStationId = stop.get<db_id>(3);
|
||||
info.segmentId = stop.get<db_id>(4);
|
||||
info.departure = stop.get<QTime>(5);
|
||||
info.firstStationId = stop.get<db_id>(3);
|
||||
info.segmentId = stop.get<db_id>(4);
|
||||
info.departure = stop.get<QTime>(5);
|
||||
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))
|
||||
return false; //No stops found, give up
|
||||
if (!tryFindJobStopsAfter(selectedJob.jobId, info))
|
||||
return false; // No stops found, give up
|
||||
}
|
||||
|
||||
db_id graphObjId = 0;
|
||||
db_id graphObjId = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
//NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||
//do not emit change because selection might be synced between all scenes
|
||||
//and because it's restored soon after
|
||||
scene->setSelectedJob(JobStopEntry{}, false); //Clear selection
|
||||
// NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||
// do not emit change because selection might be synced between all scenes
|
||||
// and because it's restored soon after
|
||||
scene->setSelectedJob(JobStopEntry{}, false); // Clear selection
|
||||
|
||||
//Select the graph
|
||||
// Select the graph
|
||||
scene->loadGraph(graphObjId, graphType);
|
||||
|
||||
//Restore selection
|
||||
// Restore selection
|
||||
selectedJob.stopId = info.firstStopId;
|
||||
scene->setSelectedJob(selectedJob); //This time emit
|
||||
scene->setSelectedJob(selectedJob); // This time emit
|
||||
|
||||
return scene->requestShowZone(info.firstStationId, info.segmentId,
|
||||
info.arrivalAndStart, info.departure);
|
||||
return scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart,
|
||||
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.
|
||||
//So it may not be 'next' but maybe 2 or 3 segments after current.
|
||||
// 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.
|
||||
|
||||
JobStopEntry selectedJob = scene->getSelectedJob();
|
||||
if(!selectedJob.jobId)
|
||||
return false; //No job selected, nothing to do
|
||||
if (!selectedJob.jobId)
|
||||
return false; // No job selected, nothing to do
|
||||
|
||||
query q(mDb);
|
||||
|
||||
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"
|
||||
" FROM stops s2"
|
||||
" 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");
|
||||
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);
|
||||
if(jobId == selectedJob.jobId)
|
||||
if (jobId == selectedJob.jobId)
|
||||
{
|
||||
//Found stop and belongs to requested job
|
||||
info.firstStopId = stop.get<db_id>(1);
|
||||
// Found stop and belongs to requested job
|
||||
info.firstStopId = stop.get<db_id>(1);
|
||||
info.arrivalAndStart = stop.get<QTime>(2);
|
||||
info.departure = stop.get<QTime>(3);
|
||||
info.firstStationId = stop.get<db_id>(4);
|
||||
info.segmentId = stop.get<db_id>(5);
|
||||
info.departure = stop.get<QTime>(3);
|
||||
info.firstStationId = stop.get<db_id>(4);
|
||||
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"
|
||||
" FROM stops s1"
|
||||
" WHERE s1.job_id=?");
|
||||
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
|
||||
auto stop = q.getRows();
|
||||
info.firstStopId = stop.get<db_id>(0);
|
||||
// Found stop and belongs to requested job
|
||||
auto stop = q.getRows();
|
||||
info.firstStopId = stop.get<db_id>(0);
|
||||
info.arrivalAndStart = stop.get<QTime>(1);
|
||||
info.departure = stop.get<QTime>(2);
|
||||
info.firstStationId = stop.get<db_id>(3);
|
||||
info.departure = stop.get<QTime>(2);
|
||||
info.firstStationId = stop.get<db_id>(3);
|
||||
}
|
||||
}
|
||||
|
||||
db_id graphObjId = 0;
|
||||
db_id graphObjId = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
//NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||
//do not emit change because selection might be synced between all scenes
|
||||
//and because it's restored soon after
|
||||
scene->setSelectedJob(JobStopEntry{}, false); //Clear selection
|
||||
// NOTE: clear selection to avoid LineGraphManager trying to follow selection
|
||||
// do not emit change because selection might be synced between all scenes
|
||||
// and because it's restored soon after
|
||||
scene->setSelectedJob(JobStopEntry{}, false); // Clear selection
|
||||
|
||||
//Select the graph
|
||||
// Select the graph
|
||||
scene->loadGraph(graphObjId, graphType);
|
||||
|
||||
//Restore selection
|
||||
// Restore selection
|
||||
selectedJob.stopId = info.firstStopId;
|
||||
scene->setSelectedJob(selectedJob); //This time emit
|
||||
scene->setSelectedJob(selectedJob); // This time emit
|
||||
|
||||
return scene->requestShowZone(info.firstStationId, info.segmentId,
|
||||
info.arrivalAndStart, info.departure);
|
||||
return scene->requestShowZone(info.firstStationId, info.segmentId, info.arrivalAndStart,
|
||||
info.departure);
|
||||
}
|
||||
|
|
|
@ -33,16 +33,15 @@ class database;
|
|||
class LineGraphSelectionHelper
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* \brief The SegmentInfo struct
|
||||
*/
|
||||
struct SegmentInfo
|
||||
{
|
||||
db_id segmentId = 0;
|
||||
db_id firstStationId = 0;
|
||||
db_id segmentId = 0;
|
||||
db_id firstStationId = 0;
|
||||
db_id secondStationId = 0;
|
||||
db_id firstStopId = 0;
|
||||
db_id firstStopId = 0;
|
||||
|
||||
/*!
|
||||
* \brief arrival and start
|
||||
|
@ -56,7 +55,7 @@ public:
|
|||
|
||||
LineGraphSelectionHelper(sqlite3pp::database &db);
|
||||
|
||||
//Low level API
|
||||
// Low level API
|
||||
|
||||
/*!
|
||||
* \brief find job in current graph
|
||||
|
@ -69,7 +68,7 @@ public:
|
|||
* If scene has NoGraph or does not contain requested job then returns false
|
||||
* 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
|
||||
|
@ -93,10 +92,11 @@ public:
|
|||
* 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.
|
||||
*/
|
||||
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:
|
||||
//High level API
|
||||
// High level API
|
||||
|
||||
/*!
|
||||
* \brief request job selection
|
||||
|
|
|
@ -21,5 +21,4 @@
|
|||
|
||||
StationGraphObject::StationGraphObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "app/session.h"
|
||||
|
||||
#include "graph/model/linegraphscene.h"
|
||||
#include "graph/model/linegraphscene.h"
|
||||
#include "utils/jobcategorystrings.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
@ -31,9 +31,9 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF& rect)
|
||||
void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF &rect)
|
||||
{
|
||||
//TODO: settings
|
||||
// TODO: settings
|
||||
QFont hourTextFont;
|
||||
setFontPointSizeDPI(hourTextFont, 15, painter);
|
||||
|
||||
|
@ -45,14 +45,14 @@ void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF& rect)
|
|||
painter->setFont(hourTextFont);
|
||||
painter->setPen(hourTextPen);
|
||||
|
||||
//qDebug() << "Drawing hours..." << rect << scroll;
|
||||
// qDebug() << "Drawing hours..." << rect << scroll;
|
||||
const QString fmt(QStringLiteral("%1:00"));
|
||||
|
||||
const qreal top = rect.top() - vertOffset;
|
||||
const qreal top = rect.top() - vertOffset;
|
||||
const qreal bottom = rect.bottom();
|
||||
|
||||
int h = qFloor(top / hourOffset);
|
||||
if(h < 0)
|
||||
int h = qFloor(top / hourOffset);
|
||||
if (h < 0)
|
||||
h = 0;
|
||||
|
||||
QRectF labelRect = rect;
|
||||
|
@ -60,9 +60,9 @@ void BackgroundHelper::drawHourPanel(QPainter *painter, const QRectF& rect)
|
|||
labelRect.setHeight(hourOffset);
|
||||
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));
|
||||
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)
|
||||
{
|
||||
const double horizOffset = Session->horizOffset;
|
||||
const double vertOffset = Session->vertOffset;
|
||||
const double hourOffset = Session->hourOffset;
|
||||
const double vertOffset = Session->vertOffset;
|
||||
const double hourOffset = Session->hourOffset;
|
||||
|
||||
QPen hourLinePen(AppSettings.getHourLineColor(), AppSettings.getHourLineWidth());
|
||||
|
||||
const qreal x1 = qMax(qreal(horizOffset), rect.left());
|
||||
const qreal x2 = rect.right();
|
||||
const qreal t = qMax(rect.top(), vertOffset);
|
||||
const qreal b = rect.bottom();
|
||||
const qreal t = qMax(rect.top(), vertOffset);
|
||||
const qreal b = rect.bottom();
|
||||
|
||||
|
||||
if(x1 > x2 || b < vertOffset || t > b)
|
||||
if (x1 > x2 || b < vertOffset || t > b)
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
if(firstH < 0)
|
||||
if (firstH < 0)
|
||||
firstH = 0;
|
||||
if(lastH > 24)
|
||||
if (lastH > 24)
|
||||
lastH = 24;
|
||||
|
||||
const int n = lastH - firstH + 1;
|
||||
if(n <= 0)
|
||||
if (n <= 0)
|
||||
return;
|
||||
|
||||
qreal y = vertOffset + firstH * hourOffset;
|
||||
qreal y = vertOffset + firstH * hourOffset;
|
||||
|
||||
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);
|
||||
y += hourOffset;
|
||||
|
@ -111,10 +110,11 @@ void BackgroundHelper::drawBackgroundHourLines(QPainter *painter, const QRectF &
|
|||
|
||||
painter->setPen(hourLinePen);
|
||||
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;
|
||||
stationFont.setBold(true);
|
||||
|
@ -132,23 +132,23 @@ void BackgroundHelper::drawStationHeader(QPainter *painter, LineGraphScene *scen
|
|||
QPen nonElectricPlatfPen(Qt::black);
|
||||
|
||||
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
|
||||
//and center platform label by going a back of half platformOffset
|
||||
const int leftOffset = -stationOffset/2 - platformOffset /2;
|
||||
// On left go back by half station offset to center station label
|
||||
// and center platform label by going a back of half platformOffset
|
||||
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;
|
||||
|
||||
if(right < r.left() || left >= r.right())
|
||||
continue; //Skip station, it's not visible
|
||||
if (right < r.left() || left >= r.right())
|
||||
continue; // Skip station, it's not visible
|
||||
|
||||
QRectF labelRect = r;
|
||||
labelRect.setLeft(left + margin);
|
||||
|
@ -160,20 +160,20 @@ void BackgroundHelper::drawStationHeader(QPainter *painter, LineGraphScene *scen
|
|||
painter->drawText(labelRect, Qt::AlignVCenter | Qt::AlignCenter, st.stationName);
|
||||
|
||||
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)
|
||||
//We need to compensate the half stationOffset used to center station label
|
||||
double xPos = left + stationOffset/2;
|
||||
// Go to start of station (first platform)
|
||||
// We need to compensate the half stationOffset used to center station label
|
||||
double xPos = left + stationOffset / 2;
|
||||
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);
|
||||
else
|
||||
painter->setPen(nonElectricPlatfPen);
|
||||
|
||||
if(platf.platformType.testFlag(utils::StationTrackType::Through))
|
||||
if (platf.platformType.testFlag(utils::StationTrackType::Through))
|
||||
painter->setFont(platfBoldFont);
|
||||
else
|
||||
painter->setFont(platfNormalFont);
|
||||
|
@ -191,33 +191,33 @@ void BackgroundHelper::drawStations(QPainter *painter, LineGraphScene *scene, co
|
|||
{
|
||||
const QRgb white = qRgb(255, 255, 255);
|
||||
|
||||
//const int horizOffset = Session->horizOffset;
|
||||
// const int horizOffset = Session->horizOffset;
|
||||
const int vertOffset = Session->vertOffset;
|
||||
//const int stationOffset = Session->stationOffset;
|
||||
const double platfOffset = Session->platformOffset;
|
||||
const int lastY = vertOffset + Session->hourOffset * 24 + 10;
|
||||
// const int stationOffset = Session->stationOffset;
|
||||
const double platfOffset = Session->platformOffset;
|
||||
const int lastY = vertOffset + Session->hourOffset * 24 + 10;
|
||||
|
||||
const int width = AppSettings.getPlatformLineWidth();
|
||||
const int width = AppSettings.getPlatformLineWidth();
|
||||
const QColor mainPlatfColor = AppSettings.getMainPlatfColor();
|
||||
|
||||
QPen platfPen (mainPlatfColor, width);
|
||||
QPen platfPen(mainPlatfColor, width);
|
||||
|
||||
QPointF top(0, vertOffset);
|
||||
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;
|
||||
|
||||
if(left > rect.right() || right < rect.left())
|
||||
continue; //Skip station, it's not visible
|
||||
if (left > rect.right() || right < rect.left())
|
||||
continue; // Skip station, it's not visible
|
||||
|
||||
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);
|
||||
else
|
||||
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;
|
||||
|
||||
QFont jobNameFont;
|
||||
|
@ -249,7 +250,7 @@ void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, co
|
|||
QPen selectedJobPen;
|
||||
|
||||
const JobStopEntry selectedJob = scene->getSelectedJob();
|
||||
if(drawSelection && selectedJob.jobId)
|
||||
if (drawSelection && selectedJob.jobId)
|
||||
{
|
||||
selectedJobPen.setWidthF(jobPen.widthF() * SelectedJobWidthFactor);
|
||||
selectedJobPen.setCapStyle(Qt::RoundCap);
|
||||
|
@ -266,48 +267,48 @@ void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, co
|
|||
JobCategory lastJobCategory = JobCategory::NCategories;
|
||||
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;
|
||||
|
||||
//Set a maximum right edge to Job labels
|
||||
//This allows to determine if they have to be drawn
|
||||
// Set a maximum right edge to Job labels
|
||||
// This allows to determine if they have to be drawn
|
||||
const double maxJobLabelX = right + stationOffset;
|
||||
|
||||
if(left > rect.right() || maxJobLabelX < rect.left())
|
||||
continue; //Skip station, it's not visible
|
||||
if (left > rect.right() || maxJobLabelX < rect.left())
|
||||
continue; // Skip station, it's not visible
|
||||
|
||||
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
|
||||
if(jobStop.arrivalY > rect.bottom() || jobStop.departureY < rect.top())
|
||||
continue; //Skip, job not visible
|
||||
// NOTE: departure comes AFTER arrival in time, opposite than job segment
|
||||
if (jobStop.arrivalY > rect.bottom() || jobStop.departureY < rect.top())
|
||||
continue; // Skip, job not visible
|
||||
|
||||
top.setY(jobStop.arrivalY);
|
||||
bottom.setY(jobStop.departureY);
|
||||
|
||||
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);
|
||||
|
||||
if(nullStopDuration)
|
||||
if (nullStopDuration)
|
||||
painter->drawPoint(top);
|
||||
else
|
||||
painter->drawLine(top, bottom);
|
||||
|
||||
//Reset pen
|
||||
// Reset pen
|
||||
painter->setPen(jobPen);
|
||||
}
|
||||
|
||||
if(lastJobCategory != jobStop.stop.category)
|
||||
if (lastJobCategory != jobStop.stop.category)
|
||||
{
|
||||
QColor color = Session->colorForCat(jobStop.stop.category);
|
||||
jobPen.setColor(color);
|
||||
|
@ -315,17 +316,18 @@ void BackgroundHelper::drawJobStops(QPainter *painter, LineGraphScene *scene, co
|
|||
lastJobCategory = jobStop.stop.category;
|
||||
}
|
||||
|
||||
if(nullStopDuration)
|
||||
if (nullStopDuration)
|
||||
painter->drawPoint(top);
|
||||
else
|
||||
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
|
||||
//Calculate width so it doesn't go after maxJobLabelX
|
||||
// Put label a bit to the left in respect to the stop arrival point
|
||||
// Calculate width so it doesn't go after maxJobLabelX
|
||||
const qreal topWithMargin = top.x() + platfOffset / 2;
|
||||
QRectF r(topWithMargin, top.y(), maxJobLabelX - topWithMargin, 25);
|
||||
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;
|
||||
|
||||
|
@ -357,7 +360,7 @@ void BackgroundHelper::drawJobSegments(QPainter *painter, LineGraphScene *scene,
|
|||
QPen selectedJobPen;
|
||||
|
||||
const JobStopEntry selectedJob = scene->getSelectedJob();
|
||||
if(drawSelection && selectedJob.jobId)
|
||||
if (drawSelection && selectedJob.jobId)
|
||||
{
|
||||
selectedJobPen.setWidthF(jobPen.widthF() * SelectedJobWidthFactor);
|
||||
selectedJobPen.setCapStyle(Qt::RoundCap);
|
||||
|
@ -371,47 +374,47 @@ void BackgroundHelper::drawJobSegments(QPainter *painter, LineGraphScene *scene,
|
|||
JobCategory lastJobCategory = JobCategory::NCategories;
|
||||
QTextOption textOption(Qt::AlignCenter);
|
||||
|
||||
//Iterate until one but last
|
||||
//This way we can always acces next station
|
||||
for(int i = 0; i < scene->stationPositions.size() - 1; i++)
|
||||
// Iterate until one but last
|
||||
// This way we can always acces next station
|
||||
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;
|
||||
double right = 0;
|
||||
const double left = stPos.xPos;
|
||||
double right = 0;
|
||||
|
||||
if(i < scene->stationPositions.size() - 2)
|
||||
if (i < scene->stationPositions.size() - 2)
|
||||
{
|
||||
const LineGraphScene::StationPosEntry& afterNextPos = scene->stationPositions.at(i + 2);
|
||||
right = afterNextPos.xPos - stationOffset;
|
||||
const LineGraphScene::StationPosEntry &afterNextPos = scene->stationPositions.at(i + 2);
|
||||
right = afterNextPos.xPos - stationOffset;
|
||||
}
|
||||
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())
|
||||
continue; //Skip station, it's not visible
|
||||
if (left > rect.right() || right < rect.left())
|
||||
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
|
||||
if(job.fromDeparture.y() > rect.bottom() || job.toArrival.y() < rect.top())
|
||||
continue; //Skip, job not visible
|
||||
// NOTE: departure comes BEFORE arrival in time, opposite than job stop
|
||||
if (job.fromDeparture.y() > rect.bottom() || job.toArrival.y() < rect.top())
|
||||
continue; // Skip, job not visible
|
||||
|
||||
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->drawLine(line);
|
||||
|
||||
//Reset pen
|
||||
// Reset pen
|
||||
painter->setPen(jobPen);
|
||||
}
|
||||
|
||||
if(lastJobCategory != job.category)
|
||||
if (lastJobCategory != job.category)
|
||||
{
|
||||
QColor color = Session->colorForCat(job.category);
|
||||
jobPen.setColor(color);
|
||||
|
@ -423,35 +426,35 @@ void BackgroundHelper::drawJobSegments(QPainter *painter, LineGraphScene *scene,
|
|||
|
||||
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();
|
||||
|
||||
//Move to line center, it will be rotation pivot
|
||||
// Move to line center, it will be rotation pivot
|
||||
painter->translate(line.center());
|
||||
|
||||
//Rotate by line angle
|
||||
// Rotate by line angle
|
||||
qreal angle = line.angle();
|
||||
if(job.fromDeparture.x() > job.toArrival.x())
|
||||
angle += 180.0; //Prevent flipping text
|
||||
if (job.fromDeparture.x() > job.toArrival.x())
|
||||
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();
|
||||
QRectF textRect(-lineLength / 2, -30, lineLength, 25);
|
||||
|
||||
//Try to avoid overlapping text of crossing jobs, move text towards arrival
|
||||
if(job.toArrival.x() > job.fromDeparture.x())
|
||||
// Try to avoid overlapping text of crossing jobs, move text towards arrival
|
||||
if (job.toArrival.x() > job.fromDeparture.x())
|
||||
textRect.moveLeft(textRect.left() + lineLength / 5);
|
||||
else
|
||||
textRect.moveLeft(textRect.left() - lineLength / 5);
|
||||
|
||||
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->drawText(textRect, jobName, textOption);
|
||||
|
||||
//Reset to old transformation
|
||||
// Reset to old transformation
|
||||
painter->setTransform(oldTransf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,21 +36,23 @@ class LineGraphScene;
|
|||
class BackgroundHelper
|
||||
{
|
||||
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:
|
||||
static constexpr double SelectedJobWidthFactor = 3.0;
|
||||
static constexpr int SelectedJobAlphaFactor = 127;
|
||||
static constexpr int SelectedJobAlphaFactor = 127;
|
||||
};
|
||||
|
||||
#endif // BACKGROUNDHELPER_H
|
||||
|
|
|
@ -49,20 +49,22 @@ LineGraphSelectionWidget::LineGraphSelectionWidget(QWidget *parent) :
|
|||
|
||||
QStringList items;
|
||||
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)));
|
||||
graphTypeCombo->addItems(items);
|
||||
graphTypeCombo->setCurrentIndex(0);
|
||||
|
||||
connect(graphTypeCombo, qOverload<int>(&QComboBox::activated), this, &LineGraphSelectionWidget::onTypeComboActivated);
|
||||
connect(objectCombo, &CustomCompletionLineEdit::completionDone, this, &LineGraphSelectionWidget::onCompletionDone);
|
||||
connect(graphTypeCombo, qOverload<int>(&QComboBox::activated), this,
|
||||
&LineGraphSelectionWidget::onTypeComboActivated);
|
||||
connect(objectCombo, &CustomCompletionLineEdit::completionDone, this,
|
||||
&LineGraphSelectionWidget::onCompletionDone);
|
||||
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||
}
|
||||
|
||||
LineGraphSelectionWidget::~LineGraphSelectionWidget()
|
||||
{
|
||||
if(matchModel)
|
||||
if (matchModel)
|
||||
{
|
||||
objectCombo->setModel(nullptr);
|
||||
delete matchModel;
|
||||
|
@ -77,7 +79,7 @@ LineGraphType LineGraphSelectionWidget::getGraphType() const
|
|||
|
||||
void LineGraphSelectionWidget::setGraphType(LineGraphType type)
|
||||
{
|
||||
if(getGraphType() == type)
|
||||
if (getGraphType() == type)
|
||||
return;
|
||||
|
||||
graphTypeCombo->setCurrentIndex(int(type));
|
||||
|
@ -98,16 +100,16 @@ const QString &LineGraphSelectionWidget::getObjectName() const
|
|||
|
||||
void LineGraphSelectionWidget::setObjectId(db_id objectId, const QString &name)
|
||||
{
|
||||
if(m_graphType == LineGraphType::NoGraph)
|
||||
return; //Object ID must be null
|
||||
if (m_graphType == LineGraphType::NoGraph)
|
||||
return; // Object ID must be null
|
||||
|
||||
m_name = name;
|
||||
if(!objectId)
|
||||
if (!objectId)
|
||||
m_name.clear();
|
||||
|
||||
objectCombo->setData(objectId, name);
|
||||
|
||||
if(m_objectId != objectId)
|
||||
if (m_objectId != objectId)
|
||||
emit graphChanged(int(m_graphType), m_objectId);
|
||||
}
|
||||
|
||||
|
@ -119,7 +121,7 @@ void LineGraphSelectionWidget::onTypeComboActivated(int index)
|
|||
|
||||
void LineGraphSelectionWidget::onCompletionDone()
|
||||
{
|
||||
if(!objectCombo->getData(m_objectId, m_name))
|
||||
if (!objectCombo->getData(m_objectId, m_name))
|
||||
return;
|
||||
|
||||
emit graphChanged(int(m_graphType), m_objectId);
|
||||
|
@ -127,17 +129,17 @@ void LineGraphSelectionWidget::onCompletionDone()
|
|||
|
||||
void LineGraphSelectionWidget::setupModel(LineGraphType type)
|
||||
{
|
||||
if(type != m_graphType)
|
||||
if (type != m_graphType)
|
||||
{
|
||||
//Clear old model
|
||||
if(matchModel)
|
||||
// Clear old model
|
||||
if (matchModel)
|
||||
{
|
||||
objectCombo->setModel(nullptr);
|
||||
delete matchModel;
|
||||
matchModel = nullptr;
|
||||
}
|
||||
|
||||
//Manually clear line edit
|
||||
// Manually clear line edit
|
||||
m_objectId = 0;
|
||||
m_name.clear();
|
||||
objectCombo->setData(m_objectId, m_name);
|
||||
|
@ -147,7 +149,7 @@ void LineGraphSelectionWidget::setupModel(LineGraphType type)
|
|||
case LineGraphType::NoGraph:
|
||||
default:
|
||||
{
|
||||
//Prevent recursion on loadGraph() calling back to us
|
||||
// Prevent recursion on loadGraph() calling back to us
|
||||
type = LineGraphType::NoGraph;
|
||||
break;
|
||||
}
|
||||
|
@ -168,14 +170,13 @@ void LineGraphSelectionWidget::setupModel(LineGraphType type)
|
|||
case LineGraphType::RailwayLine:
|
||||
{
|
||||
LinesMatchModel *m = new LinesMatchModel(Session->m_Db, true, this);
|
||||
matchModel = m;
|
||||
matchModel = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(matchModel)
|
||||
if (matchModel)
|
||||
objectCombo->setModel(matchModel);
|
||||
}
|
||||
m_graphType = type;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
db_id getObjectId() 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);
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ LineGraphToolbar::LineGraphToolbar(QWidget *parent) :
|
|||
lay->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
selectionWidget = new LineGraphSelectionWidget;
|
||||
connect(selectionWidget, &LineGraphSelectionWidget::graphChanged, this, &LineGraphToolbar::onWidgetGraphChanged);
|
||||
connect(selectionWidget, &LineGraphSelectionWidget::graphChanged, this,
|
||||
&LineGraphToolbar::onWidgetGraphChanged);
|
||||
lay->addWidget(selectionWidget);
|
||||
|
||||
redrawBut = new QPushButton(tr("Redraw"));
|
||||
|
@ -70,57 +71,59 @@ LineGraphToolbar::LineGraphToolbar(QWidget *parent) :
|
|||
zoomSpinBox->setRange(25, 400);
|
||||
zoomSpinBox->setValue(mZoom);
|
||||
zoomSpinBox->setSuffix(QChar('%'));
|
||||
connect(zoomSpinBox, qOverload<int>(&QSpinBox::valueChanged), this, &LineGraphToolbar::updateZoomLevel);
|
||||
connect(zoomSpinBox, qOverload<int>(&QSpinBox::valueChanged), this,
|
||||
&LineGraphToolbar::updateZoomLevel);
|
||||
lay->addWidget(zoomSpinBox);
|
||||
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||
|
||||
//Accept focus events by click
|
||||
// Accept focus events by click
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
|
||||
//Install event filter to catch focus events on children widgets
|
||||
for(QObject *child : selectionWidget->children())
|
||||
// Install event filter to catch focus events on children widgets
|
||||
for (QObject *child : selectionWidget->children())
|
||||
{
|
||||
if(child->isWidgetType())
|
||||
if (child->isWidgetType())
|
||||
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);
|
||||
}
|
||||
|
||||
LineGraphToolbar::~LineGraphToolbar()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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(m_scene)
|
||||
// If any of our child widgets receives focus, activate our scene
|
||||
if (m_scene)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -130,14 +133,14 @@ bool LineGraphToolbar::eventFilter(QObject *watched, QEvent *ev)
|
|||
void LineGraphToolbar::resetToolbarToScene()
|
||||
{
|
||||
LineGraphType type = LineGraphType::NoGraph;
|
||||
db_id objectId = 0;
|
||||
db_id objectId = 0;
|
||||
QString name;
|
||||
|
||||
if(m_scene)
|
||||
if (m_scene)
|
||||
{
|
||||
type = m_scene->getGraphType();
|
||||
type = m_scene->getGraphType();
|
||||
objectId = m_scene->getGraphObjectId();
|
||||
name = m_scene->getGraphObjectName();
|
||||
name = m_scene->getGraphObjectName();
|
||||
}
|
||||
|
||||
selectionWidget->setGraphType(type);
|
||||
|
@ -146,7 +149,7 @@ void LineGraphToolbar::resetToolbarToScene()
|
|||
|
||||
void LineGraphToolbar::updateZoomLevel(int zoom)
|
||||
{
|
||||
if(mZoom == zoom)
|
||||
if (mZoom == zoom)
|
||||
return;
|
||||
|
||||
mZoom = zoom;
|
||||
|
@ -160,13 +163,13 @@ void LineGraphToolbar::updateZoomLevel(int zoom)
|
|||
void LineGraphToolbar::onWidgetGraphChanged(int type, db_id objectId)
|
||||
{
|
||||
LineGraphType graphType = LineGraphType(type);
|
||||
if(graphType == LineGraphType::NoGraph)
|
||||
if (graphType == LineGraphType::NoGraph)
|
||||
objectId = 0;
|
||||
|
||||
if(graphType != LineGraphType::NoGraph && !objectId)
|
||||
return; //User is still selecting an object
|
||||
if (graphType != LineGraphType::NoGraph && !objectId)
|
||||
return; // User is still selecting an object
|
||||
|
||||
if(m_scene)
|
||||
if (m_scene)
|
||||
m_scene->loadGraph(objectId, graphType);
|
||||
}
|
||||
|
||||
|
@ -175,7 +178,7 @@ void LineGraphToolbar::onSceneGraphChanged(int type, db_id objectId)
|
|||
selectionWidget->setGraphType(LineGraphType(type));
|
||||
|
||||
QString name;
|
||||
if(m_scene && m_scene->getGraphObjectId() == objectId)
|
||||
if (m_scene && m_scene->getGraphObjectId() == objectId)
|
||||
name = m_scene->getGraphObjectName();
|
||||
selectionWidget->setObjectId(objectId, name);
|
||||
}
|
||||
|
@ -183,12 +186,12 @@ void LineGraphToolbar::onSceneGraphChanged(int type, db_id objectId)
|
|||
void LineGraphToolbar::onSceneDestroyed()
|
||||
{
|
||||
m_scene = nullptr;
|
||||
resetToolbarToScene(); //Clear UI
|
||||
resetToolbarToScene(); // Clear UI
|
||||
}
|
||||
|
||||
void LineGraphToolbar::focusInEvent(QFocusEvent *e)
|
||||
{
|
||||
if(m_scene)
|
||||
if (m_scene)
|
||||
m_scene->activateScene();
|
||||
|
||||
QWidget::focusInEvent(e);
|
||||
|
|
|
@ -31,27 +31,28 @@
|
|||
LineGraphView::LineGraphView(QWidget *parent) :
|
||||
BasicGraphView(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool LineGraphView::viewportEvent(QEvent *e)
|
||||
{
|
||||
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());
|
||||
|
||||
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(),
|
||||
JobCategoryName::jobName(job.jobId, job.category),
|
||||
QToolTip::showText(ev->globalPos(), JobCategoryName::jobName(job.jobId, job.category),
|
||||
viewport());
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
QToolTip::hideText();
|
||||
}
|
||||
|
||||
|
@ -71,11 +72,11 @@ void LineGraphView::mouseDoubleClickEvent(QMouseEvent *e)
|
|||
{
|
||||
LineGraphScene *lineScene = qobject_cast<LineGraphScene *>(scene());
|
||||
|
||||
if(!lineScene || lineScene->getGraphType() == LineGraphType::NoGraph)
|
||||
return; //Nothing to select
|
||||
if (!lineScene || lineScene->getGraphType() == LineGraphType::NoGraph)
|
||||
return; // Nothing to select
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ LineGraphWidget::LineGraphWidget(QWidget *parent) :
|
|||
{
|
||||
QVBoxLayout *lay = new QVBoxLayout(this);
|
||||
|
||||
toolBar = new LineGraphToolbar(this);
|
||||
toolBar = new LineGraphToolbar(this);
|
||||
|
||||
lay->addWidget(toolBar);
|
||||
|
||||
|
@ -45,12 +45,13 @@ LineGraphWidget::LineGraphWidget(QWidget *parent) :
|
|||
|
||||
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);
|
||||
view->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::requestZoom, view, &LineGraphView::setZoomLevel);
|
||||
|
@ -59,7 +60,7 @@ LineGraphWidget::LineGraphWidget(QWidget *parent) :
|
|||
|
||||
bool LineGraphWidget::tryLoadGraph(db_id graphObjId, LineGraphType type)
|
||||
{
|
||||
if(!m_scene)
|
||||
if (!m_scene)
|
||||
return false;
|
||||
|
||||
return m_scene->loadGraph(graphObjId, type);
|
||||
|
|
|
@ -46,9 +46,20 @@ class LineGraphWidget : public QWidget
|
|||
public:
|
||||
explicit LineGraphWidget(QWidget *parent = nullptr);
|
||||
|
||||
inline LineGraphScene *getScene() const { return m_scene; }
|
||||
inline LineGraphView *getView() const { return view; }
|
||||
inline LineGraphToolbar *getToolbar() const { return toolBar; }
|
||||
inline LineGraphScene *getScene() const
|
||||
{
|
||||
return m_scene;
|
||||
}
|
||||
|
||||
inline LineGraphView *getView() const
|
||||
{
|
||||
return view;
|
||||
}
|
||||
|
||||
inline LineGraphToolbar *getToolbar() const
|
||||
{
|
||||
return toolBar;
|
||||
}
|
||||
|
||||
bool tryLoadGraph(db_id graphObjId, LineGraphType type);
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
|
||||
#include "app/scopedebug.h"
|
||||
|
||||
|
||||
EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::EditStopDialog),
|
||||
|
@ -57,12 +56,13 @@ EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
|||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
//Stop
|
||||
helper = new StopEditingHelper(Session->m_Db, stopModel,
|
||||
ui->outGateTrackSpin, ui->arrivalTimeEdit, ui->departureTimeEdit,
|
||||
this);
|
||||
connect(helper, &StopEditingHelper::nextSegmentChosen, this, &EditStopDialog::updateAdditionalNotes);
|
||||
connect(helper, &StopEditingHelper::stationTrackChosen, this, &EditStopDialog::updateAdditionalNotes);
|
||||
// Stop
|
||||
helper = new StopEditingHelper(Session->m_Db, stopModel, ui->outGateTrackSpin,
|
||||
ui->arrivalTimeEdit, ui->departureTimeEdit, this);
|
||||
connect(helper, &StopEditingHelper::nextSegmentChosen, this,
|
||||
&EditStopDialog::updateAdditionalNotes);
|
||||
connect(helper, &StopEditingHelper::stationTrackChosen, this,
|
||||
&EditStopDialog::updateAdditionalNotes);
|
||||
|
||||
CustomCompletionLineEdit *mStationEdit = helper->getStationEdit();
|
||||
CustomCompletionLineEdit *mStTrackEdit = helper->getStTrackEdit();
|
||||
|
@ -72,17 +72,17 @@ EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
|||
ui->curStopLay->setWidget(2, QFormLayout::FieldRole, mStTrackEdit);
|
||||
ui->curStopLay->setWidget(3, QFormLayout::FieldRole, mOutGateEdit);
|
||||
|
||||
//Coupling
|
||||
couplingMgr = new RSCouplingInterface(Session->m_Db, this);
|
||||
// Coupling
|
||||
couplingMgr = new RSCouplingInterface(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);
|
||||
ui->coupledView->setModel(coupledModel);
|
||||
ui->coupledLayout->insertWidget(1, ps);
|
||||
|
||||
uncoupledModel = new StopCouplingModel(Session->m_Db, this);
|
||||
ps = new ModelPageSwitcher(true, this);
|
||||
ps = new ModelPageSwitcher(true, this);
|
||||
ps->setModel(uncoupledModel);
|
||||
ui->uncoupledView->setModel(uncoupledModel);
|
||||
ui->uncoupledLayout->insertWidget(1, ps);
|
||||
|
@ -93,28 +93,32 @@ EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
|||
|
||||
ui->coupledView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
ui->uncoupledView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ui->coupledView, &QAbstractItemView::customContextMenuRequested, this, &EditStopDialog::couplingCustomContextMenuRequested);
|
||||
connect(ui->uncoupledView, &QAbstractItemView::customContextMenuRequested, this, &EditStopDialog::couplingCustomContextMenuRequested);
|
||||
connect(ui->coupledView, &QAbstractItemView::customContextMenuRequested, this,
|
||||
&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);
|
||||
ps = new ModelPageSwitcher(true, this);
|
||||
ps = new ModelPageSwitcher(true, this);
|
||||
ps->setModel(trainAssetModelBefore);
|
||||
ui->assetBeforeView->setModel(trainAssetModelBefore);
|
||||
ui->trainAssetGridLayout->addWidget(ps, 2, 0);
|
||||
|
||||
trainAssetModelAfter = new TrainAssetModel(Session->m_Db, this);
|
||||
ps = new ModelPageSwitcher(true, this);
|
||||
ps = new ModelPageSwitcher(true, this);
|
||||
ps->setModel(trainAssetModelAfter);
|
||||
ui->assetAfterView->setModel(trainAssetModelAfter);
|
||||
ui->trainAssetGridLayout->addWidget(ps, 2, 1);
|
||||
|
||||
ui->assetBeforeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
ui->assetAfterView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ui->assetBeforeView, &QAbstractItemView::customContextMenuRequested, this, &EditStopDialog::couplingCustomContextMenuRequested);
|
||||
connect(ui->assetAfterView, &QAbstractItemView::customContextMenuRequested, this, &EditStopDialog::couplingCustomContextMenuRequested);
|
||||
connect(ui->assetBeforeView, &QAbstractItemView::customContextMenuRequested, this,
|
||||
&EditStopDialog::couplingCustomContextMenuRequested);
|
||||
connect(ui->assetAfterView, &QAbstractItemView::customContextMenuRequested, this,
|
||||
&EditStopDialog::couplingCustomContextMenuRequested);
|
||||
|
||||
//Setup Crossings/Passings
|
||||
// Setup Crossings/Passings
|
||||
passingsModel = new JobPassingsModel(this);
|
||||
ui->passingsView->setModel(passingsModel);
|
||||
|
||||
|
@ -123,13 +127,15 @@ EditStopDialog::EditStopDialog(StopModel *m, QWidget *parent) :
|
|||
|
||||
connect(ui->calcPassingsBut, &QPushButton::clicked, this, &EditStopDialog::calcPassings);
|
||||
|
||||
//BIG TODO: temporarily disable option to Cancel dialog
|
||||
//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
|
||||
// BIG TODO: temporarily disable option to Cancel dialog
|
||||
// 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
|
||||
ui->buttonBox->setStandardButtons(QDialogButtonBox::Ok);
|
||||
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setToolTip(tr("Press SHIFT modifier and click to save changes"
|
||||
" without recalculating travel times."));
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)
|
||||
->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::rejected, this, &QDialog::reject);
|
||||
|
@ -149,15 +155,15 @@ void EditStopDialog::clearUi()
|
|||
{
|
||||
helper->stopOutTrackTimer();
|
||||
|
||||
stopIdx = QModelIndex();
|
||||
stopIdx = QModelIndex();
|
||||
|
||||
m_jobId = 0;
|
||||
m_jobId = 0;
|
||||
m_jobCat = JobCategory::FREIGHT;
|
||||
|
||||
trainAssetModelBefore->setStop(0, QTime(), TrainAssetModel::BeforeStop);
|
||||
trainAssetModelAfter->setStop(0, QTime(), TrainAssetModel::AfterStop);
|
||||
|
||||
//TODO: clear UI properly
|
||||
// TODO: clear UI properly
|
||||
}
|
||||
|
||||
void EditStopDialog::showBeforeAsset(bool val)
|
||||
|
@ -172,78 +178,79 @@ void EditStopDialog::showAfterAsset(bool val)
|
|||
ui->assetAfterLabel->setVisible(val);
|
||||
}
|
||||
|
||||
void EditStopDialog::setStop(const QModelIndex& idx)
|
||||
void EditStopDialog::setStop(const QModelIndex &idx)
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
if(!idx.isValid())
|
||||
if (!idx.isValid())
|
||||
{
|
||||
clearUi();
|
||||
return;
|
||||
}
|
||||
|
||||
m_jobId = stopModel->getJobId();
|
||||
m_jobCat = stopModel->getCategory();
|
||||
m_jobId = stopModel->getJobId();
|
||||
m_jobCat = stopModel->getCategory();
|
||||
|
||||
stopIdx = idx;
|
||||
stopIdx = idx;
|
||||
|
||||
const StopItem& curStop = stopModel->getItemAt(idx.row());
|
||||
const StopItem &curStop = stopModel->getItemAt(idx.row());
|
||||
StopItem prevStop;
|
||||
if(idx.row() == 0)
|
||||
prevStop = StopItem(); //First stop has no previous stop
|
||||
if (idx.row() == 0)
|
||||
prevStop = StopItem(); // First stop has no previous stop
|
||||
else
|
||||
prevStop = stopModel->getItemAt(idx.row() - 1);
|
||||
|
||||
helper->setStop(curStop, prevStop);
|
||||
|
||||
//Setup Train Asset
|
||||
// Setup Train Asset
|
||||
trainAssetModelBefore->setStop(m_jobId, curStop.arrival, TrainAssetModel::BeforeStop);
|
||||
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);
|
||||
|
||||
//Hide train asset after stop on Last stop
|
||||
// Hide train asset after stop on Last stop
|
||||
showAfterAsset(curStop.type != StopType::Last);
|
||||
|
||||
//Coupling operations
|
||||
// Coupling operations
|
||||
coupledModel->setStop(curStop.stopId, RsOp::Coupled);
|
||||
uncoupledModel->setStop(curStop.stopId, RsOp::Uncoupled);
|
||||
|
||||
//Update UI
|
||||
// Update UI
|
||||
updateInfo();
|
||||
|
||||
//Calc passings
|
||||
// Calc passings
|
||||
calcPassings();
|
||||
|
||||
//Update Title
|
||||
// Update Title
|
||||
const QString jobName = JobCategoryName::jobName(m_jobId, m_jobCat);
|
||||
setWindowTitle(jobName);
|
||||
}
|
||||
|
||||
void EditStopDialog::updateInfo()
|
||||
{
|
||||
const StopItem& curStop = helper->getCurItem();
|
||||
const StopItem& prevStop = helper->getPrevItem();
|
||||
const StopItem &curStop = helper->getCurItem();
|
||||
const StopItem &prevStop = helper->getPrevItem();
|
||||
|
||||
const QString inGateStr = helper->getGateString(curStop.fromGate.gateId,
|
||||
prevStop.nextSegment.reversed);
|
||||
const QString inGateStr =
|
||||
helper->getGateString(curStop.fromGate.gateId, prevStop.nextSegment.reversed);
|
||||
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->curStopBox->setTitle(tr("First Stop"));
|
||||
}
|
||||
else
|
||||
{
|
||||
//Show box of previous stop
|
||||
// Show box of previous stop
|
||||
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;
|
||||
if(prevStop.stationId)
|
||||
if (prevStop.stationId)
|
||||
{
|
||||
query q(Session->m_Db, "SELECT name FROM stations WHERE id=?");
|
||||
q.bind(1, prevStop.stationId);
|
||||
|
@ -252,17 +259,17 @@ void EditStopDialog::updateInfo()
|
|||
}
|
||||
ui->prevStEdit->setText(prevStName);
|
||||
|
||||
const QString outGateStr = helper->getGateString(prevStop.toGate.gateId,
|
||||
prevStop.nextSegment.reversed);
|
||||
const QString outGateStr =
|
||||
helper->getGateString(prevStop.toGate.gateId, prevStop.nextSegment.reversed);
|
||||
ui->prevOutGateEdit->setText(outGateStr);
|
||||
}
|
||||
|
||||
const QString descr = stopModel->getDescription(curStop);
|
||||
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->editUncoupledBut->setEnabled(false);
|
||||
}
|
||||
|
@ -276,13 +283,12 @@ void EditStopDialog::saveDataToModel()
|
|||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
const StopItem& curStop = helper->getCurItem();
|
||||
const StopItem& prevStop = helper->getPrevItem();
|
||||
const StopItem &curStop = helper->getCurItem();
|
||||
const StopItem &prevStop = helper->getPrevItem();
|
||||
|
||||
if(ui->descriptionEdit->document()->isModified())
|
||||
if (ui->descriptionEdit->document()->isModified())
|
||||
{
|
||||
stopModel->setDescription(stopIdx,
|
||||
ui->descriptionEdit->toPlainText());
|
||||
stopModel->setDescription(stopIdx, ui->descriptionEdit->toPlainText());
|
||||
}
|
||||
|
||||
bool avoidTimeRecalc = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||
|
@ -291,8 +297,8 @@ void EditStopDialog::saveDataToModel()
|
|||
|
||||
void EditStopDialog::importJobRS()
|
||||
{
|
||||
const StopItem& curStop = helper->getCurItem();
|
||||
if(!curStop.stationId)
|
||||
const StopItem &curStop = helper->getCurItem();
|
||||
if (!curStop.stationId)
|
||||
{
|
||||
QMessageBox::warning(this, tr("Import Error"),
|
||||
tr("In order to import rollingstock from other<br>"
|
||||
|
@ -305,48 +311,49 @@ void EditStopDialog::importJobRS()
|
|||
jobsMatch.setDefaultId(JobMatchModel::StopId);
|
||||
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);
|
||||
dlg->setDescription(tr("Please choose a Job among the ones stopping at <b>%1</b> before <b>%2</b>.<br>"
|
||||
"All rollingstock uncoupled by selected Job at current station<br>"
|
||||
"will be coupled to current Job.")
|
||||
.arg(stName,
|
||||
curStop.departure.toString("HH:mm")));
|
||||
dlg->setDescription(
|
||||
tr("Please choose a Job among the ones stopping at <b>%1</b> before <b>%2</b>.<br>"
|
||||
"All rollingstock uncoupled by selected Job at current station<br>"
|
||||
"will be coupled to current Job.")
|
||||
.arg(stName, curStop.departure.toString("HH:mm")));
|
||||
dlg->setPlaceholder(tr("Job number without category"));
|
||||
|
||||
//Select model
|
||||
// Select model
|
||||
int ret = dlg->exec();
|
||||
if(ret != QDialog::Accepted || !dlg)
|
||||
if (ret != QDialog::Accepted || !dlg)
|
||||
return;
|
||||
|
||||
db_id otherJobStopId = dlg->getItemId();
|
||||
if(!otherJobStopId)
|
||||
if (!otherJobStopId)
|
||||
return;
|
||||
|
||||
//Import rollingstock
|
||||
// Import rollingstock
|
||||
int count = couplingMgr->importRSFromJob(otherJobStopId);
|
||||
|
||||
//Refresh views
|
||||
// Refresh views
|
||||
coupledModel->refreshData(true);
|
||||
trainAssetModelAfter->refreshData(true);
|
||||
|
||||
//Tell user it's completed
|
||||
QMessageBox::information(this, tr("Importation Finished"),
|
||||
tr("<b>%1</b> rollingstock items were successfully imported")
|
||||
.arg(count));
|
||||
// Tell user it's completed
|
||||
QMessageBox::information(
|
||||
this, tr("Importation Finished"),
|
||||
tr("<b>%1</b> rollingstock items were successfully imported").arg(count));
|
||||
}
|
||||
|
||||
void EditStopDialog::editCoupled()
|
||||
{
|
||||
const StopItem& curStop = helper->getCurItem();
|
||||
const StopItem &curStop = helper->getCurItem();
|
||||
|
||||
coupledModel->clearCache();
|
||||
trainAssetModelAfter->clearCache();
|
||||
|
||||
OwningQPointer<RSCoupleDialog> dlg = new RSCoupleDialog(couplingMgr, RsOp::Coupled, this);
|
||||
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();
|
||||
|
||||
|
@ -356,14 +363,15 @@ void EditStopDialog::editCoupled()
|
|||
|
||||
void EditStopDialog::editUncoupled()
|
||||
{
|
||||
const StopItem& curStop = helper->getCurItem();
|
||||
const StopItem &curStop = helper->getCurItem();
|
||||
|
||||
uncoupledModel->clearCache();
|
||||
trainAssetModelAfter->clearCache();
|
||||
|
||||
OwningQPointer<RSCoupleDialog> dlg = new RSCoupleDialog(couplingMgr, RsOp::Uncoupled, this);
|
||||
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();
|
||||
|
||||
|
@ -381,20 +389,21 @@ void EditStopDialog::calcPassings()
|
|||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
const StopItem& curStop = helper->getCurItem();
|
||||
const StopItem &curStop = helper->getCurItem();
|
||||
|
||||
JobStopDirectionHelper dirHelper(Session->m_Db);
|
||||
utils::Side myDirection = dirHelper.getStopOutSide(curStop.stopId);
|
||||
|
||||
query q(Session->m_Db, "SELECT s.id, s.job_id, jobs.category, s.arrival, s.departure,"
|
||||
"t1.name,t2.name"
|
||||
" FROM stops s"
|
||||
" JOIN jobs ON jobs.id=s.job_id"
|
||||
" LEFT JOIN station_gate_connections g1 ON g1.id=s.in_gate_conn"
|
||||
" LEFT JOIN station_gate_connections g2 ON g2.id=s.out_gate_conn"
|
||||
" LEFT JOIN station_tracks t1 ON t1.id=g1.track_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 <> ?");
|
||||
query q(Session->m_Db,
|
||||
"SELECT s.id, s.job_id, jobs.category, s.arrival, s.departure,"
|
||||
"t1.name,t2.name"
|
||||
" FROM stops s"
|
||||
" JOIN jobs ON jobs.id=s.job_id"
|
||||
" LEFT JOIN station_gate_connections g1 ON g1.id=s.in_gate_conn"
|
||||
" LEFT JOIN station_gate_connections g2 ON g2.id=s.out_gate_conn"
|
||||
" LEFT JOIN station_tracks t1 ON t1.id=g1.track_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(2, curStop.arrival);
|
||||
|
@ -403,27 +412,27 @@ void EditStopDialog::calcPassings()
|
|||
|
||||
QVector<JobPassingsModel::Entry> passings, crossings;
|
||||
|
||||
for(auto r : q)
|
||||
for (auto r : q)
|
||||
{
|
||||
JobPassingsModel::Entry e;
|
||||
|
||||
db_id otherStopId = r.get<db_id>(0);
|
||||
e.jobId = r.get<db_id>(1);
|
||||
e.category = JobCategory(r.get<int>(2));
|
||||
e.arrival = r.get<QTime>(3);
|
||||
e.departure = r.get<QTime>(4);
|
||||
e.platform = r.get<int>(5);
|
||||
e.jobId = r.get<db_id>(1);
|
||||
e.category = JobCategory(r.get<int>(2));
|
||||
e.arrival = r.get<QTime>(3);
|
||||
e.departure = r.get<QTime>(4);
|
||||
e.platform = r.get<int>(5);
|
||||
|
||||
e.platform = r.get<QString>(6);
|
||||
if(e.platform.isEmpty())
|
||||
e.platform = r.get<QString>(7); //Use out gate to get track name
|
||||
e.platform = r.get<QString>(6);
|
||||
if (e.platform.isEmpty())
|
||||
e.platform = r.get<QString>(7); // Use out gate to get track name
|
||||
|
||||
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
||||
|
||||
if(myDirection == otherDir)
|
||||
passings.append(e); //Same direction -> Passing
|
||||
if (myDirection == otherDir)
|
||||
passings.append(e); // Same direction -> Passing
|
||||
else
|
||||
crossings.append(e); //Opposite direction -> Crossing
|
||||
crossings.append(e); // Opposite direction -> Crossing
|
||||
}
|
||||
|
||||
q.reset();
|
||||
|
@ -435,20 +444,21 @@ void EditStopDialog::calcPassings()
|
|||
ui->crossingsView->resizeColumnsToContents();
|
||||
}
|
||||
|
||||
void EditStopDialog::couplingCustomContextMenuRequested(const QPoint& pos)
|
||||
void EditStopDialog::couplingCustomContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
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());
|
||||
if(!view)
|
||||
return; //Error: not called by the view?
|
||||
if (!view)
|
||||
return; // Error: not called by the view?
|
||||
|
||||
if(menu->exec(view->viewport()->mapToGlobal(pos)) != act)
|
||||
return; //User didn't select 'Refresh' action
|
||||
if (menu->exec(view->viewport()->mapToGlobal(pos)) != act)
|
||||
return; // User didn't select 'Refresh' action
|
||||
|
||||
//Refresh data
|
||||
// Refresh data
|
||||
coupledModel->refreshData(true);
|
||||
uncoupledModel->refreshData(true);
|
||||
trainAssetModelBefore->refreshData(true);
|
||||
|
@ -457,7 +467,7 @@ void EditStopDialog::couplingCustomContextMenuRequested(const QPoint& pos)
|
|||
|
||||
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("
|
||||
"SELECT coupling.rs_id AS rs_id, MAX(stops.arrival)"
|
||||
|
@ -468,11 +478,11 @@ int EditStopDialog::getTrainSpeedKmH(bool afterStop)
|
|||
" HAVING coupling.operation=1)"
|
||||
" JOIN rs_list ON rs_list.id=rs_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,
|
||||
//by adding 1 minute we include the current stop but leave out the next one
|
||||
if(afterStop)
|
||||
// HACK: 1 minute is the min interval between stops,
|
||||
// by adding 1 minute we include the current stop but leave out the next one
|
||||
if (afterStop)
|
||||
q.bind(2, curStop.arrival.addSecs(60));
|
||||
else
|
||||
q.bind(2, curStop.arrival);
|
||||
|
@ -483,48 +493,48 @@ int EditStopDialog::getTrainSpeedKmH(bool afterStop)
|
|||
|
||||
void EditStopDialog::updateAdditionalNotes()
|
||||
{
|
||||
const StopItem& curStop = helper->getCurItem();
|
||||
const StopItem &curStop = helper->getCurItem();
|
||||
|
||||
QString msg;
|
||||
|
||||
//Check direction
|
||||
if(curStop.fromGate.gateConnId && curStop.toGate.gateConnId
|
||||
&& curStop.type != StopType::First && curStop.type != StopType::Last)
|
||||
// Check direction
|
||||
if (curStop.fromGate.gateConnId && curStop.toGate.gateConnId && curStop.type != StopType::First
|
||||
&& curStop.type != StopType::Last)
|
||||
{
|
||||
//Ignore First and Last stop (sometimes they have fake in/out gates set which might trigger this message)
|
||||
//Both entry and exit path are set, check direction
|
||||
if(curStop.fromGate.stationTrackSide == curStop.toGate.stationTrackSide)
|
||||
// Ignore First and Last stop (sometimes they have fake in/out gates set which might trigger
|
||||
// this message) Both entry and exit path are set, check direction
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
//Check line traction
|
||||
if(curStop.type != StopType::Last && curStop.nextSegment.segmentId)
|
||||
// Check line traction
|
||||
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 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);
|
||||
}
|
||||
|
||||
if(!msg.isEmpty())
|
||||
msg.append("\n\n"); //Separate from previous message
|
||||
if (!msg.isEmpty())
|
||||
msg.append("\n\n"); // Separate from previous message
|
||||
|
||||
if(nextSegmentElectrified)
|
||||
if (nextSegmentElectrified)
|
||||
msg.append(tr("Electric traction is ALLOWED."));
|
||||
else
|
||||
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(tr("(Different traction then previous line!)"));
|
||||
}
|
||||
|
@ -536,7 +546,7 @@ void EditStopDialog::updateAdditionalNotes()
|
|||
|
||||
void EditStopDialog::setReadOnly(bool value)
|
||||
{
|
||||
readOnly = value;
|
||||
readOnly = value;
|
||||
|
||||
CustomCompletionLineEdit *mStationEdit = helper->getStationEdit();
|
||||
CustomCompletionLineEdit *mStTrackEdit = helper->getStTrackEdit();
|
||||
|
@ -557,73 +567,78 @@ void EditStopDialog::setReadOnly(bool value)
|
|||
|
||||
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
|
||||
//But not if we are Last stop (size - 1 - AddHere)
|
||||
//because the train doesn't have to leave the station
|
||||
// Check if train has at least one engine after this stop
|
||||
// But not if we are Last stop (size - 1 - AddHere)
|
||||
// because the train doesn't have to leave the station
|
||||
bool electricOnNonElectrifiedLine = false;
|
||||
if(!couplingMgr->hasEngineAfterStop(&electricOnNonElectrifiedLine) || electricOnNonElectrifiedLine)
|
||||
if (!couplingMgr->hasEngineAfterStop(&electricOnNonElectrifiedLine)
|
||||
|| electricOnNonElectrifiedLine)
|
||||
{
|
||||
int ret = QMessageBox::warning(this,
|
||||
tr("No Engine Left"),
|
||||
electricOnNonElectrifiedLine ?
|
||||
tr("It seems you have uncoupled all job engines except for electric ones "
|
||||
"but the line is not electrified\n"
|
||||
"(The train isn't able to move)\n"
|
||||
"Do you want to couple a non electric engine?") :
|
||||
tr("It seems you have uncoupled all job engines\n"
|
||||
"(The train isn't able to move)\n"
|
||||
"Do you want to couple an engine?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
int ret = QMessageBox::warning(
|
||||
this, tr("No Engine Left"),
|
||||
electricOnNonElectrifiedLine
|
||||
? tr("It seems you have uncoupled all job engines except for electric ones "
|
||||
"but the line is not electrified\n"
|
||||
"(The train isn't able to move)\n"
|
||||
"Do you want to couple a non electric engine?")
|
||||
: tr("It seems you have uncoupled all job engines\n"
|
||||
"(The train isn't able to move)\n"
|
||||
"Do you want to couple an engine?"),
|
||||
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
|
||||
if(originalSpeedAfterStop != newSpeedAfterStop)
|
||||
if (originalSpeedAfterStop != newSpeedAfterStop)
|
||||
{
|
||||
int speedBefore = originalSpeedAfterStop;
|
||||
int speedAfter = newSpeedAfterStop;
|
||||
int speedBefore = originalSpeedAfterStop;
|
||||
int speedAfter = newSpeedAfterStop;
|
||||
|
||||
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);
|
||||
if(speedBefore == 0)
|
||||
if (speedBefore == 0)
|
||||
{
|
||||
//If speed is null (likely because there weren't RS coupled before)
|
||||
//Fall back to line max speed
|
||||
// If speed is null (likely because there weren't RS coupled before)
|
||||
// Fall back to line max speed
|
||||
speedBefore = lineSpeed;
|
||||
}
|
||||
if(speedAfter == 0)
|
||||
if (speedAfter == 0)
|
||||
{
|
||||
//If speed is null (likely because there isn't RS coupled after this stop)
|
||||
//Fall back to line max speed
|
||||
// If speed is null (likely because there isn't RS coupled after this stop)
|
||||
// Fall back to line max speed
|
||||
speedAfter = lineSpeed;
|
||||
}
|
||||
int ret = QMessageBox::question(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>"
|
||||
"Do you want to rebase travel times to this new speed?<br>"
|
||||
"NOTE: this doesn't affect stop times but you will lose manual adjustments to travel times")
|
||||
.arg(speedBefore).arg(speedAfter),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
|
||||
int ret = QMessageBox::question(
|
||||
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>"
|
||||
"Do you want to rebase travel times to this new speed?<br>"
|
||||
"NOTE: this doesn't affect stop times but you will lose manual adjustments to "
|
||||
"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
|
||||
|
|
|
@ -95,11 +95,11 @@ private:
|
|||
StopCouplingModel *coupledModel;
|
||||
StopCouplingModel *uncoupledModel;
|
||||
|
||||
TrainAssetModel *trainAssetModelBefore;
|
||||
TrainAssetModel *trainAssetModelAfter;
|
||||
TrainAssetModel *trainAssetModelBefore;
|
||||
TrainAssetModel *trainAssetModelAfter;
|
||||
|
||||
JobPassingsModel *passingsModel;
|
||||
JobPassingsModel *crossingsModel;
|
||||
JobPassingsModel *passingsModel;
|
||||
JobPassingsModel *crossingsModel;
|
||||
|
||||
bool readOnly;
|
||||
};
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "utils/delegates/sql/customcompletionlineedit.h"
|
||||
#include "shifts/shiftcombomodel.h"
|
||||
|
||||
|
||||
#include "utils/owningqpointer.h"
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
|
@ -55,7 +54,6 @@
|
|||
|
||||
#include <QCloseEvent>
|
||||
|
||||
|
||||
JobPathEditor::JobPathEditor(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::JobPathEditor),
|
||||
|
@ -69,7 +67,7 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
|||
|
||||
QStringList catNames;
|
||||
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)));
|
||||
}
|
||||
|
@ -79,17 +77,18 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
|||
ui->categoryCombo->setCurrentIndex(-1);
|
||||
|
||||
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;
|
||||
QFormLayout::ItemRole unusedRole;
|
||||
ui->formLayout->getWidgetPosition(ui->categoryCombo, &categoryRow, &unusedRole);
|
||||
ui->formLayout->insertRow(categoryRow + 1, tr("Shift:"), shiftCombo);
|
||||
|
||||
//Stops
|
||||
// Stops
|
||||
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);
|
||||
|
||||
delegate = new StopDelegate(Session->m_Db, this);
|
||||
|
@ -99,7 +98,7 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
|||
ui->stopsView->setMovement(QListView::Static);
|
||||
ui->stopsView->setSelectionMode(QListView::ContiguousSelection);
|
||||
|
||||
//Next/Prev Jobs
|
||||
// Next/Prev Jobs
|
||||
prevJobsModel = new NextPrevRSJobsModel(Session->m_Db, this);
|
||||
prevJobsModel->setMode(NextPrevRSJobsModel::PrevJobs);
|
||||
ui->prevJobsView->setModel(prevJobsModel);
|
||||
|
@ -108,11 +107,12 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
|||
nextJobsModel->setMode(NextPrevRSJobsModel::NextJobs);
|
||||
ui->nextJobsView->setModel(nextJobsModel);
|
||||
|
||||
|
||||
connect(ui->categoryCombo, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated), stopModel, &StopModel::setCategory);
|
||||
connect(ui->categoryCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
|
||||
stopModel, &StopModel::setCategory);
|
||||
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::edited, this, &JobPathEditor::setEdited);
|
||||
|
@ -123,14 +123,17 @@ JobPathEditor::JobPathEditor(QWidget *parent) :
|
|||
connect(ui->sheetBut, &QPushButton::clicked, this, &JobPathEditor::onSaveSheet);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
connect(ui->nextJobsView, &QListView::customContextMenuRequested, this, &JobPathEditor::showJobContextMenu);
|
||||
connect(ui->nextJobsView, &QListView::customContextMenuRequested, this,
|
||||
&JobPathEditor::showJobContextMenu);
|
||||
|
||||
connect(Session, &MeetingSession::jobRemoved, this, &JobPathEditor::onJobRemoved);
|
||||
connect(&AppSettings, &MRTPSettings::jobColorsChanged, this, &JobPathEditor::updateSpinColor);
|
||||
|
@ -149,16 +152,16 @@ JobPathEditor::~JobPathEditor()
|
|||
|
||||
bool JobPathEditor::setJob(db_id jobId)
|
||||
{
|
||||
if(!canSetJob)
|
||||
return false; //We are busy - (Avoid nested loop calls from inside 'saveChanges()')
|
||||
if (!canSetJob)
|
||||
return false; // We are busy - (Avoid nested loop calls from inside 'saveChanges()')
|
||||
|
||||
if(!isClear && stopModel->getJobId() == jobId)
|
||||
return true; //Fake return, we already set this job
|
||||
if (!isClear && stopModel->getJobId() == jobId)
|
||||
return true; // Fake return, we already set this job
|
||||
|
||||
if(isEdited())
|
||||
if (isEdited())
|
||||
{
|
||||
if(!maybeSave())
|
||||
return false; //User still wants to edit the current job
|
||||
if (!maybeSave())
|
||||
return false; // User still wants to edit the current job
|
||||
}
|
||||
|
||||
return setJob_internal(jobId);
|
||||
|
@ -168,32 +171,32 @@ bool JobPathEditor::setJob_internal(db_id jobId)
|
|||
{
|
||||
DEBUG_IMPORTANT_ENTRY;
|
||||
|
||||
if(!canSetJob)
|
||||
return false; //We are busy - (Avoid nested loop calls from inside 'saveChanges()')
|
||||
if (!canSetJob)
|
||||
return false; // We are busy - (Avoid nested loop calls from inside 'saveChanges()')
|
||||
|
||||
if(!isClear && stopModel->getJobId() == jobId)
|
||||
return true; //Fake return, we already set this job
|
||||
if (!isClear && stopModel->getJobId() == jobId)
|
||||
return true; // Fake return, we already set this job
|
||||
|
||||
isClear = false;
|
||||
|
||||
stopJobNumberTimer();
|
||||
|
||||
//Load from database
|
||||
if(!stopModel->loadJobStops(jobId))
|
||||
// Load from database
|
||||
if (!stopModel->loadJobStops(jobId))
|
||||
{
|
||||
//Error: job could not be loaded, maybe invalid jobId
|
||||
// Error: job could not be loaded, maybe invalid jobId
|
||||
clearJob();
|
||||
setEnabled(false);
|
||||
|
||||
QMessageBox::warning(this, tr("Error Loading Job"),
|
||||
tr("<b>Job %1</b> could not be loaded.<br>"
|
||||
"Maybe it's number was changed or maybe it doesn't exist at all.")
|
||||
.arg(jobId));
|
||||
tr("<b>Job %1</b> could not be loaded.<br>"
|
||||
"Maybe it's number was changed or maybe it doesn't exist at all.")
|
||||
.arg(jobId));
|
||||
|
||||
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);
|
||||
|
||||
prevJobsModel->setJobId(jobId);
|
||||
|
@ -204,16 +207,16 @@ bool JobPathEditor::setJob_internal(db_id jobId)
|
|||
|
||||
void JobPathEditor::startJobNumberTimer()
|
||||
{
|
||||
//Give user a small time to scroll values in ID QSpinBox
|
||||
//This will skip eventual non available IDs (already existent)
|
||||
//On timeout check ID and reset to old value if not available
|
||||
// Give user a small time to scroll values in ID QSpinBox
|
||||
// This will skip eventual non available IDs (already existent)
|
||||
// On timeout check ID and reset to old value if not available
|
||||
stopJobNumberTimer();
|
||||
jobNumberTimerId = startTimer(700);
|
||||
}
|
||||
|
||||
void JobPathEditor::stopJobNumberTimer()
|
||||
{
|
||||
if(jobNumberTimerId)
|
||||
if (jobNumberTimerId)
|
||||
{
|
||||
killTimer(jobNumberTimerId);
|
||||
jobNumberTimerId = 0;
|
||||
|
@ -222,15 +225,16 @@ void JobPathEditor::stopJobNumberTimer()
|
|||
|
||||
void JobPathEditor::checkJobNumberValid()
|
||||
{
|
||||
//Kill timer
|
||||
// Kill timer
|
||||
stopJobNumberTimer();
|
||||
|
||||
db_id jobId = ui->jobIdSpin->value();
|
||||
if(!stopModel->setNewJobId(jobId))
|
||||
if (!stopModel->setNewJobId(jobId))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid"),
|
||||
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
|
||||
*/
|
||||
|
||||
if(out)
|
||||
if (out)
|
||||
*out = 0;
|
||||
|
||||
if(!clearJob())
|
||||
return false; //Busy JobPathEditor
|
||||
if (!clearJob())
|
||||
return false; // Busy JobPathEditor
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(out)
|
||||
if (out)
|
||||
*out = jobId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JobPathEditor::showStopsContextMenu(const QPoint& pos)
|
||||
void JobPathEditor::showStopsContextMenu(const QPoint &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;
|
||||
|
||||
OwningQPointer<QMenu> menu = new QMenu(this);
|
||||
QAction *toggleTransitAct = menu->addAction(tr("Toggle transit"));
|
||||
QAction *setToTransitAct = menu->addAction(tr("Set transit"));
|
||||
QAction *unsetTransit = menu->addAction(tr("Unset transit"));
|
||||
QAction *toggleTransitAct = menu->addAction(tr("Toggle transit"));
|
||||
QAction *setToTransitAct = menu->addAction(tr("Set transit"));
|
||||
QAction *unsetTransit = menu->addAction(tr("Unset transit"));
|
||||
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"));
|
||||
menu->insertSeparator(editStopAct);
|
||||
QAction *removeStopAct = menu->addAction(tr("Remove"));
|
||||
|
@ -296,24 +300,24 @@ void JobPathEditor::showStopsContextMenu(const QPoint& pos)
|
|||
removeStopAct->setEnabled(!m_readOnly);
|
||||
|
||||
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();
|
||||
|
||||
QItemSelectionRange range;
|
||||
QItemSelection s = ui->stopsView->selectionModel()->selection();
|
||||
if(s.count() > 0)
|
||||
if (s.count() > 0)
|
||||
{
|
||||
//Take the first range only
|
||||
range = s.at(0); //Save range for later
|
||||
// Take the first range only
|
||||
range = s.at(0); // Save range for later
|
||||
}
|
||||
|
||||
//Select only 1 index
|
||||
// Select only 1 index
|
||||
sm->select(index, QItemSelectionModel::ClearAndSelect);
|
||||
|
||||
if(act == editStopAct)
|
||||
if (act == editStopAct)
|
||||
{
|
||||
OwningQPointer<EditStopDialog> dlg = new EditStopDialog(stopModel, this);
|
||||
dlg->setReadOnly(m_readOnly);
|
||||
|
@ -322,86 +326,87 @@ void JobPathEditor::showStopsContextMenu(const QPoint& pos)
|
|||
return;
|
||||
}
|
||||
|
||||
if(act == showStationSVG)
|
||||
if (act == showStationSVG)
|
||||
{
|
||||
Session->getViewManager()->requestStSVGPlan(stop.stationId, true, stop.arrival);
|
||||
}
|
||||
|
||||
if(m_readOnly)
|
||||
if (m_readOnly)
|
||||
return;
|
||||
|
||||
if(range.isValid())
|
||||
if (range.isValid())
|
||||
{
|
||||
StopType type = StopType::ToggleType;
|
||||
bool useRange = true;
|
||||
if(act == toggleTransitAct)
|
||||
if (act == toggleTransitAct)
|
||||
type = StopType::ToggleType;
|
||||
else if(act == setToTransitAct)
|
||||
else if (act == setToTransitAct)
|
||||
type = StopType::Transit;
|
||||
else if(act == unsetTransit)
|
||||
else if (act == unsetTransit)
|
||||
type = StopType::Normal;
|
||||
else
|
||||
useRange = false;
|
||||
|
||||
if(useRange)
|
||||
if (useRange)
|
||||
{
|
||||
stopModel->setStopTypeRange(range.top(), range.bottom(), type);
|
||||
//Select only the range we changed (unselect possible other indexes)
|
||||
sm->select(QItemSelection(range.topLeft(), range.bottomRight()), QItemSelectionModel::ClearAndSelect);
|
||||
// Select only the range we changed (unselect possible other indexes)
|
||||
sm->select(QItemSelection(range.topLeft(), range.bottomRight()),
|
||||
QItemSelectionModel::ClearAndSelect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(act == removeStopAct)
|
||||
if (act == removeStopAct)
|
||||
{
|
||||
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;
|
||||
|
||||
if(jobView == ui->prevJobsView)
|
||||
if (jobView == ui->prevJobsView)
|
||||
jobModel = prevJobsModel;
|
||||
|
||||
QModelIndex index = jobView->indexAt(pos);
|
||||
QModelIndex index = jobView->indexAt(pos);
|
||||
|
||||
NextPrevRSJobsModel::Item item = jobModel->getItemAtRow(index.row());
|
||||
|
||||
OwningQPointer<QMenu> menu = new QMenu(this);
|
||||
QAction *goToStop = menu->addAction(tr("Go to Stop"));
|
||||
QAction *goToJob = menu->addAction(tr("Show Job"));
|
||||
QAction *showRSPlan = menu->addAction(tr("Show RS Plan"));
|
||||
OwningQPointer<QMenu> menu = new QMenu(this);
|
||||
QAction *goToStop = menu->addAction(tr("Go to Stop"));
|
||||
QAction *goToJob = menu->addAction(tr("Show Job"));
|
||||
QAction *showRSPlan = menu->addAction(tr("Show RS Plan"));
|
||||
menu->addSeparator();
|
||||
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());
|
||||
goToJob->setEnabled(index.isValid() && item.otherJobId != 0);
|
||||
showRSPlan->setEnabled(index.isValid());
|
||||
|
||||
QAction *act = menu->exec(jobView->viewport()->mapToGlobal(pos));
|
||||
|
||||
if(act == goToStop)
|
||||
if (act == goToStop)
|
||||
{
|
||||
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;
|
||||
}
|
||||
Session->getViewManager()->requestJobSelection(item.otherJobId, true, true);
|
||||
}
|
||||
else if(act == showRSPlan)
|
||||
else if (act == showRSPlan)
|
||||
{
|
||||
Session->getViewManager()->requestRSInfo(item.rsId);
|
||||
}
|
||||
else if(act == refreshViews)
|
||||
else if (act == refreshViews)
|
||||
{
|
||||
prevJobsModel->refreshData();
|
||||
nextJobsModel->refreshData();
|
||||
|
@ -412,18 +417,18 @@ bool JobPathEditor::clearJob()
|
|||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
if(!canSetJob)
|
||||
if (!canSetJob)
|
||||
return false;
|
||||
|
||||
if(isEdited())
|
||||
if (isEdited())
|
||||
{
|
||||
if(!maybeSave())
|
||||
if (!maybeSave())
|
||||
return false;
|
||||
}
|
||||
|
||||
isClear = true;
|
||||
|
||||
//Reset color
|
||||
// Reset color
|
||||
ui->jobIdSpin->setPalette(QPalette());
|
||||
|
||||
stopModel->clearJob();
|
||||
|
@ -438,23 +443,23 @@ bool JobPathEditor::clearJob()
|
|||
|
||||
void JobPathEditor::done(int res)
|
||||
{
|
||||
if(res == Accepted)
|
||||
if (res == Accepted)
|
||||
{
|
||||
//Accepted: save changes
|
||||
if(!saveChanges())
|
||||
return; //Give user a second chance to edit job
|
||||
// Accepted: save changes
|
||||
if (!saveChanges())
|
||||
return; // Give user a second chance to edit job
|
||||
}
|
||||
else
|
||||
{
|
||||
//Rejected: discard changes
|
||||
// Rejected: discard changes
|
||||
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);
|
||||
if(res == QDialog::Accepted)
|
||||
if (res == QDialog::Accepted)
|
||||
emit accepted();
|
||||
else if(res == QDialog::Rejected)
|
||||
else if (res == QDialog::Rejected)
|
||||
emit rejected();
|
||||
emit finished(res);
|
||||
}
|
||||
|
@ -463,7 +468,7 @@ bool JobPathEditor::saveChanges()
|
|||
{
|
||||
DEBUG_IMPORTANT_ENTRY;
|
||||
|
||||
if(!canSetJob)
|
||||
if (!canSetJob)
|
||||
return false;
|
||||
canSetJob = false;
|
||||
|
||||
|
@ -474,15 +479,14 @@ bool JobPathEditor::saveChanges()
|
|||
stopModel->removeLastIfEmpty();
|
||||
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,
|
||||
tr("Error"),
|
||||
int res = QMessageBox::warning(this, tr("Error"),
|
||||
tr("You must register at least 2 stops.\n"
|
||||
"Do you want to delete this job?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if(res == QMessageBox::Yes)
|
||||
if (res == QMessageBox::Yes)
|
||||
{
|
||||
qDebug() << "User wants to delete job:" << stopModel->getJobId();
|
||||
stopModel->commitChanges();
|
||||
|
@ -494,19 +498,18 @@ bool JobPathEditor::saveChanges()
|
|||
}
|
||||
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!
|
||||
if(stopModel->getNewShiftId())
|
||||
// Re-check shift because user may have added stops so this job could last longer!
|
||||
if (stopModel->getNewShiftId())
|
||||
{
|
||||
auto times = stopModel->getFirstLastTimes();
|
||||
|
||||
ShiftBusyModel model(Session->m_Db);
|
||||
model.loadData(stopModel->getNewShiftId(),
|
||||
stopModel->getJobId(),
|
||||
times.first, times.second);
|
||||
if(model.hasConcurrentJobs())
|
||||
model.loadData(stopModel->getNewShiftId(), stopModel->getJobId(), times.first,
|
||||
times.second);
|
||||
if (model.hasConcurrentJobs())
|
||||
{
|
||||
OwningQPointer<ShiftBusyDlg> dlg = new ShiftBusyDlg(this);
|
||||
dlg->setModel(&model);
|
||||
|
@ -525,7 +528,7 @@ bool JobPathEditor::saveChanges()
|
|||
prevJobsModel->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);
|
||||
|
||||
canSetJob = true;
|
||||
|
@ -536,28 +539,29 @@ void JobPathEditor::discardChanges()
|
|||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
if(!canSetJob)
|
||||
if (!canSetJob)
|
||||
return;
|
||||
|
||||
canSetJob = false;
|
||||
|
||||
closeStopEditor(); //Close before rolling savepoint
|
||||
closeStopEditor(); // Close before rolling savepoint
|
||||
|
||||
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)
|
||||
//Because this hides 'AddHere' so after 'loadJobStops()'
|
||||
//Before 'clearJob()' because sets isEdited = false and
|
||||
// After re-load but before possible 'clearJob()' (Below)
|
||||
// Because this hides 'AddHere' so after 'loadJobStops()'
|
||||
// Before 'clearJob()' because sets isEdited = false and
|
||||
//'maybeSave()' doesn't be called in an infinite loop
|
||||
|
||||
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
|
||||
//This usually happens when you create a new job but then you change your mind and press 'Discard'
|
||||
// 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'
|
||||
qDebug() << "User wants to delete job:" << stopModel->getJobId();
|
||||
stopModel->commitChanges();
|
||||
JobsHelper::removeJob(Session->m_Db, stopModel->getJobId());
|
||||
|
@ -574,11 +578,9 @@ db_id JobPathEditor::currentJobId() const
|
|||
bool JobPathEditor::maybeSave()
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
QMessageBox::StandardButton ret = QMessageBox::question(this,
|
||||
tr("Save?"),
|
||||
tr("Do you want to save changes to job %1")
|
||||
.arg(stopModel->getJobId()),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
QMessageBox::StandardButton ret = QMessageBox::question(
|
||||
this, tr("Save?"), tr("Do you want to save changes to job %1").arg(stopModel->getJobId()),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
switch (ret)
|
||||
{
|
||||
case QMessageBox::Yes:
|
||||
|
@ -594,7 +596,7 @@ bool JobPathEditor::maybeSave()
|
|||
|
||||
void JobPathEditor::updateSpinColor()
|
||||
{
|
||||
if(!isClear)
|
||||
if (!isClear)
|
||||
{
|
||||
QColor col = Session->colorForCat(stopModel->getCategory());
|
||||
setSpinColor(col);
|
||||
|
@ -603,7 +605,7 @@ void JobPathEditor::updateSpinColor()
|
|||
|
||||
void JobPathEditor::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if(e->timerId() == jobNumberTimerId)
|
||||
if (e->timerId() == jobNumberTimerId)
|
||||
{
|
||||
checkJobNumberValid();
|
||||
return;
|
||||
|
@ -614,10 +616,10 @@ void JobPathEditor::timerEvent(QTimerEvent *e)
|
|||
|
||||
void JobPathEditor::onJobRemoved(db_id jobId)
|
||||
{
|
||||
//If the job shown is about to be removed clear JobPathEditor
|
||||
if(stopModel->getJobId() == jobId)
|
||||
// If the job shown is about to be removed clear JobPathEditor
|
||||
if (stopModel->getJobId() == jobId)
|
||||
{
|
||||
if(clearJob())
|
||||
if (clearJob())
|
||||
setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
@ -627,7 +629,7 @@ void JobPathEditor::onJobIdChanged(db_id jobId)
|
|||
ui->jobIdSpin->setValue(int(jobId));
|
||||
}
|
||||
|
||||
void JobPathEditor::setSpinColor(const QColor& col)
|
||||
void JobPathEditor::setSpinColor(const QColor &col)
|
||||
{
|
||||
QPalette pal = ui->jobIdSpin->palette();
|
||||
pal.setColor(QPalette::Text, col);
|
||||
|
@ -644,15 +646,13 @@ void JobPathEditor::onJobShiftChanged(db_id shiftId)
|
|||
{
|
||||
shiftCombo->setData(shiftId);
|
||||
|
||||
if(shiftId)
|
||||
if (shiftId)
|
||||
{
|
||||
auto times = stopModel->getFirstLastTimes();
|
||||
|
||||
ShiftBusyModel model(Session->m_Db);
|
||||
model.loadData(shiftId,
|
||||
stopModel->getJobId(),
|
||||
times.first, times.second);
|
||||
if(model.hasConcurrentJobs())
|
||||
model.loadData(shiftId, stopModel->getJobId(), times.first, times.second);
|
||||
if (model.hasConcurrentJobs())
|
||||
{
|
||||
OwningQPointer<ShiftBusyDlg> dlg = new ShiftBusyDlg(this);
|
||||
dlg->setModel(&model);
|
||||
|
@ -667,8 +667,7 @@ void JobPathEditor::onJobShiftChanged(db_id shiftId)
|
|||
|
||||
void JobPathEditor::onShiftError()
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Empty Job"),
|
||||
QMessageBox::warning(this, tr("Empty Job"),
|
||||
tr("Before setting a shift you should add stops to this job"),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
|
@ -686,7 +685,7 @@ void JobPathEditor::setEdited(bool val)
|
|||
|
||||
void JobPathEditor::setReadOnly(bool readOnly)
|
||||
{
|
||||
if(m_readOnly == readOnly)
|
||||
if (m_readOnly == readOnly)
|
||||
return;
|
||||
|
||||
m_readOnly = readOnly;
|
||||
|
@ -697,12 +696,12 @@ void JobPathEditor::setReadOnly(bool 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();
|
||||
if(size > 0)
|
||||
if (size > 0)
|
||||
ui->stopsView->setRowHidden(size - 1, m_readOnly);
|
||||
|
||||
if(m_readOnly)
|
||||
if (m_readOnly)
|
||||
{
|
||||
ui->stopsView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
}
|
||||
|
@ -716,7 +715,7 @@ void JobPathEditor::onSaveSheet()
|
|||
{
|
||||
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->setAcceptMode(QFileDialog::AcceptSave);
|
||||
dlg->setDirectory(RecentDirStore::getDir(job_sheet_key, RecentDirStore::Documents));
|
||||
|
@ -726,12 +725,12 @@ void JobPathEditor::onSaveSheet()
|
|||
filters << FileFormats::tr(FileFormats::odtFormat);
|
||||
dlg->setNameFilters(filters);
|
||||
|
||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
||||
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||
return;
|
||||
|
||||
QString fileName = dlg->selectedUrls().value(0).toLocalFile();
|
||||
|
||||
if(fileName.isEmpty())
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
RecentDirStore::setPath(job_sheet_key, fileName);
|
||||
|
@ -743,14 +742,14 @@ void JobPathEditor::onSaveSheet()
|
|||
utils::OpenFileInFolderDlg::askUser(tr("Job Sheet Saved"), fileName, this);
|
||||
}
|
||||
|
||||
void JobPathEditor::onStopIndexClicked(const QModelIndex& index)
|
||||
void JobPathEditor::onStopIndexClicked(const QModelIndex &index)
|
||||
{
|
||||
DEBUG_ENTRY;
|
||||
|
||||
if(m_readOnly)
|
||||
if (m_readOnly)
|
||||
return;
|
||||
|
||||
if(stopModel->isAddHere(index))
|
||||
if (stopModel->isAddHere(index))
|
||||
{
|
||||
qDebug() << index << "AddHere";
|
||||
|
||||
|
@ -758,22 +757,22 @@ void JobPathEditor::onStopIndexClicked(const QModelIndex& index)
|
|||
|
||||
int row = index.row();
|
||||
|
||||
if(row > 0)
|
||||
if (row > 0)
|
||||
{
|
||||
//idx - 1 is former Last Stop (now it became a normal Stop)
|
||||
//idx is new Last Stop (former AddHere)
|
||||
//idx + 1 is the new AddHere
|
||||
// idx - 1 is former Last Stop (now it became a normal Stop)
|
||||
// idx is new Last Stop (former AddHere)
|
||||
// idx + 1 is the new AddHere
|
||||
|
||||
//Edit former Last Stop
|
||||
// Edit former Last Stop
|
||||
QModelIndex prev = stopModel->index(row - 1, 0);
|
||||
ui->stopsView->setCurrentIndex(prev);
|
||||
ui->stopsView->scrollTo(prev);
|
||||
ui->stopsView->edit(prev);
|
||||
|
||||
//Tell editor to popup lines combo
|
||||
//QAbstractItemView::edit doesn't let you pass additional arguments
|
||||
//So we work around by emitting a signal
|
||||
//See 'StopDelegate::createEditor()'
|
||||
// Tell editor to popup lines combo
|
||||
// QAbstractItemView::edit doesn't let you pass additional arguments
|
||||
// So we work around by emitting a signal
|
||||
// See 'StopDelegate::createEditor()'
|
||||
emit delegate->popupEditorSegmentCombo();
|
||||
}
|
||||
else
|
||||
|
@ -794,8 +793,8 @@ bool JobPathEditor::getCanSetJob() const
|
|||
void JobPathEditor::closeStopEditor()
|
||||
{
|
||||
QModelIndex idx = ui->stopsView->currentIndex();
|
||||
QWidget *ed = ui->stopsView->indexWidget(idx);
|
||||
if(ed == nullptr)
|
||||
QWidget *ed = ui->stopsView->indexWidget(idx);
|
||||
if (ed == nullptr)
|
||||
return;
|
||||
emit delegate->commitData(ed);
|
||||
emit delegate->closeEditor(ed);
|
||||
|
@ -803,10 +802,10 @@ void JobPathEditor::closeStopEditor()
|
|||
|
||||
void JobPathEditor::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
//TODO: prevent QDockWidget closing even if we ignore this event
|
||||
if(isEdited())
|
||||
// TODO: prevent QDockWidget closing even if we ignore this event
|
||||
if (isEdited())
|
||||
{
|
||||
if(maybeSave())
|
||||
if (maybeSave())
|
||||
e->accept();
|
||||
else
|
||||
e->ignore();
|
||||
|
@ -820,7 +819,7 @@ void JobPathEditor::closeEvent(QCloseEvent *e)
|
|||
void JobPathEditor::selectStop(db_id stopId)
|
||||
{
|
||||
int row = stopModel->getStopRow(stopId);
|
||||
if(row >= 0)
|
||||
if (row >= 0)
|
||||
{
|
||||
QModelIndex idx = stopModel->index(row, 0);
|
||||
ui->stopsView->setCurrentIndex(idx);
|
||||
|
|
|
@ -48,7 +48,7 @@ class JobPathEditor : public QDialog
|
|||
|
||||
public:
|
||||
explicit JobPathEditor(QWidget *parent = nullptr);
|
||||
~JobPathEditor()override;
|
||||
~JobPathEditor() override;
|
||||
|
||||
bool setJob(db_id jobId);
|
||||
bool createNewJob(db_id *out = nullptr);
|
||||
|
@ -122,10 +122,10 @@ private:
|
|||
|
||||
int jobNumberTimerId;
|
||||
|
||||
//TODO: there are too many bools
|
||||
// TODO: there are too many bools
|
||||
bool isClear;
|
||||
|
||||
bool canSetJob; //TODO: better name
|
||||
bool canSetJob; // TODO: better name
|
||||
bool m_readOnly;
|
||||
};
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ JobPassingsModel::JobPassingsModel(QObject *parent) :
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ QVariant JobPassingsModel::data(const QModelIndex &idx, int role) const
|
|||
if (!idx.isValid() || idx.row() >= m_data.size() || idx.column() >= NCols)
|
||||
return QVariant();
|
||||
|
||||
const Entry& e = m_data.at(idx.row());
|
||||
const Entry &e = m_data.at(idx.row());
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
|
@ -97,7 +97,7 @@ QVariant JobPassingsModel::data(const QModelIndex &idx, int role) const
|
|||
{
|
||||
QFont f;
|
||||
f.setPointSize(10);
|
||||
if(idx.column() == JobNameCol)
|
||||
if (idx.column() == JobNameCol)
|
||||
f.setBold(true);
|
||||
return f;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@ class JobPassingsModel : public QAbstractTableModel
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns {
|
||||
enum Columns
|
||||
{
|
||||
JobNameCol = 0,
|
||||
ArrivalCol,
|
||||
DepartureCol,
|
||||
|
@ -60,7 +61,7 @@ public:
|
|||
|
||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||
|
||||
void setJobs(const QVector<Entry>& vec);
|
||||
void setJobs(const QVector<Entry> &vec);
|
||||
|
||||
private:
|
||||
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
|
||||
{
|
||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
{
|
||||
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)
|
||||
return QVariant();
|
||||
|
||||
const Item& item = m_data.at(idx.row());
|
||||
const Item &item = m_data.at(idx.row());
|
||||
|
||||
switch (role)
|
||||
{
|
||||
|
@ -77,8 +77,8 @@ QVariant NextPrevRSJobsModel::data(const QModelIndex &idx, int role) const
|
|||
{
|
||||
case JobIdCol:
|
||||
{
|
||||
if(item.otherJobCat == JobCategory::NCategories)
|
||||
return tr("Depot"); //Rollingstock item taken from/released to depot
|
||||
if (item.otherJobCat == JobCategory::NCategories)
|
||||
return tr("Depot"); // Rollingstock item taken from/released to depot
|
||||
return JobCategoryName::jobName(item.otherJobId, item.otherJobCat);
|
||||
}
|
||||
case RsNameCol:
|
||||
|
@ -90,9 +90,9 @@ QVariant NextPrevRSJobsModel::data(const QModelIndex &idx, int role) const
|
|||
}
|
||||
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;
|
||||
f.setItalic(true);
|
||||
return f;
|
||||
|
@ -108,34 +108,38 @@ QVariant NextPrevRSJobsModel::data(const QModelIndex &idx, int role) const
|
|||
|
||||
void NextPrevRSJobsModel::refreshData()
|
||||
{
|
||||
//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,"
|
||||
" %min(s1.%time0), stops.id, s1.job_id AS job_id, j1.category"
|
||||
" FROM stops"
|
||||
" JOIN coupling c ON c.stop_id=stops.id"
|
||||
" JOIN rs_list ON rs_list.id=c.rs_id"
|
||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" LEFT JOIN coupling c1 ON c1.rs_id=c.rs_id"
|
||||
" LEFT JOIN stops s1 ON s1.id=c1.stop_id"
|
||||
" LEFT JOIN jobs j1 ON j1.id=s1.job_id"
|
||||
" WHERE stops.job_id=?1 AND c.operation=%rem AND c1.operation=%add AND s1.%time0 %gt stops.%time1"
|
||||
" GROUP BY c.rs_id"
|
||||
" UNION ALL "
|
||||
"SELECT c.id, c.rs_id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type, stops.%time0,"
|
||||
" %max(s1.%time0), stops.id, NULL AS job_id, NULL"
|
||||
" FROM stops"
|
||||
" JOIN coupling c ON c.stop_id=stops.id"
|
||||
" JOIN rs_list ON rs_list.id=c.rs_id"
|
||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" LEFT JOIN coupling c1 ON c1.rs_id=c.rs_id"
|
||||
" LEFT JOIN stops s1 ON s1.id=c1.stop_id"
|
||||
" 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";
|
||||
// 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,"
|
||||
" %min(s1.%time0), stops.id, s1.job_id AS job_id, j1.category"
|
||||
" FROM stops"
|
||||
" JOIN coupling c ON c.stop_id=stops.id"
|
||||
" JOIN rs_list ON rs_list.id=c.rs_id"
|
||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" LEFT JOIN coupling c1 ON c1.rs_id=c.rs_id"
|
||||
" LEFT JOIN stops s1 ON s1.id=c1.stop_id"
|
||||
" LEFT JOIN jobs j1 ON j1.id=s1.job_id"
|
||||
" WHERE stops.job_id=?1 AND c.operation=%rem AND c1.operation=%add AND s1.%time0 %gt "
|
||||
"stops.%time1"
|
||||
" GROUP BY c.rs_id"
|
||||
" UNION ALL "
|
||||
"SELECT c.id, c.rs_id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type, "
|
||||
"stops.%time0,"
|
||||
" %max(s1.%time0), stops.id, NULL AS job_id, NULL"
|
||||
" FROM stops"
|
||||
" JOIN coupling c ON c.stop_id=stops.id"
|
||||
" JOIN rs_list ON rs_list.id=c.rs_id"
|
||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" LEFT JOIN coupling c1 ON c1.rs_id=c.rs_id"
|
||||
" LEFT JOIN stops s1 ON s1.id=c1.stop_id"
|
||||
" 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("%time1", "departure");
|
||||
|
@ -148,7 +152,7 @@ void NextPrevRSJobsModel::refreshData()
|
|||
}
|
||||
else
|
||||
{
|
||||
//Invert all
|
||||
// Invert all
|
||||
sql.replace("%time0", "departure");
|
||||
sql.replace("%time1", "arrival");
|
||||
sql.replace("%min", "MAX");
|
||||
|
@ -194,33 +198,29 @@ void NextPrevRSJobsModel::refreshData()
|
|||
beginResetModel();
|
||||
m_data.clear();
|
||||
|
||||
for(auto row : q)
|
||||
for (auto row : q)
|
||||
{
|
||||
Item item;
|
||||
item.couplingId = row.get<db_id>(0);
|
||||
item.rsId = row.get<db_id>(1);
|
||||
item.couplingId = row.get<db_id>(0);
|
||||
item.rsId = row.get<db_id>(1);
|
||||
|
||||
int number = row.get<int>(2);
|
||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 3);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 3));
|
||||
int number = row.get<int>(2);
|
||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 3);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 3));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 4);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 4));
|
||||
RsType rsType = RsType(row.get<int>(5));
|
||||
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 4);
|
||||
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 4));
|
||||
RsType rsType = RsType(row.get<int>(5));
|
||||
|
||||
item.rsName = rs_utils::formatNameRef(modelName,
|
||||
modelNameLen,
|
||||
number,
|
||||
modelSuffix,
|
||||
modelSuffixLen,
|
||||
rsType);
|
||||
item.rsName = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||
modelSuffixLen, rsType);
|
||||
|
||||
item.opTime = row.get<QTime>(6);
|
||||
//Ignore column 7, which is used just for MIN/MAX
|
||||
item.stopId = row.get<db_id>(8);
|
||||
item.otherJobId = row.get<db_id>(9);
|
||||
// Ignore column 7, which is used just for MIN/MAX
|
||||
item.stopId = row.get<db_id>(8);
|
||||
item.otherJobId = row.get<db_id>(9);
|
||||
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;
|
||||
|
||||
m_data.append(item);
|
||||
|
@ -245,7 +245,7 @@ db_id NextPrevRSJobsModel::jobId() const
|
|||
void NextPrevRSJobsModel::setJobId(db_id newJobId)
|
||||
{
|
||||
m_jobId = newJobId;
|
||||
if(m_jobId)
|
||||
if (m_jobId)
|
||||
refreshData();
|
||||
else
|
||||
clearData();
|
||||
|
@ -259,7 +259,7 @@ NextPrevRSJobsModel::Mode NextPrevRSJobsModel::mode() const
|
|||
void NextPrevRSJobsModel::setMode(Mode newMode)
|
||||
{
|
||||
m_mode = newMode;
|
||||
if(m_jobId)
|
||||
if (m_jobId)
|
||||
refreshData();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,8 @@ public:
|
|||
{
|
||||
db_id otherJobId = 0;
|
||||
db_id couplingId = 0;
|
||||
db_id rsId = 0;
|
||||
db_id stopId = 0;
|
||||
db_id rsId = 0;
|
||||
db_id stopId = 0;
|
||||
|
||||
QString rsName;
|
||||
QTime opTime;
|
||||
|
@ -73,7 +73,8 @@ public:
|
|||
NextPrevRSJobsModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||
|
||||
// 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:
|
||||
int rowCount(const QModelIndex &p = QModelIndex()) const override;
|
||||
|
@ -93,7 +94,6 @@ public:
|
|||
Item getItemAtRow(int row) const;
|
||||
|
||||
private:
|
||||
|
||||
sqlite3pp::database &mDb;
|
||||
|
||||
db_id m_jobId = 0;
|
||||
|
|
|
@ -39,16 +39,15 @@ RSCouplingInterface::RSCouplingInterface(database &db, QObject *parent) :
|
|||
" coupling(stop_id,rs_id,operation)"
|
||||
" VALUES(?, ?, ?)")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RSCouplingInterface::loadCouplings(StopModel *model, db_id stopId, db_id jobId, QTime arr)
|
||||
{
|
||||
stopsModel = model;
|
||||
|
||||
m_stopId = stopId;
|
||||
m_jobId = jobId;
|
||||
arrival = arr;
|
||||
m_stopId = stopId;
|
||||
m_jobId = jobId;
|
||||
arrival = arr;
|
||||
|
||||
coupled.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=?");
|
||||
q.bind(1, m_stopId);
|
||||
|
||||
for(auto rs : q)
|
||||
for (auto rs : q)
|
||||
{
|
||||
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);
|
||||
else
|
||||
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
|
||||
{
|
||||
if(op == RsOp::Coupled)
|
||||
if (op == RsOp::Coupled)
|
||||
return coupled.contains(rsId);
|
||||
else
|
||||
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->markRsToUpdate(rsId);
|
||||
|
||||
if(on)
|
||||
if (on)
|
||||
{
|
||||
if(coupled.contains(rsId))
|
||||
if (coupled.contains(rsId))
|
||||
{
|
||||
qWarning() << "Error already checked:" << rsId;
|
||||
return true;
|
||||
|
@ -99,78 +99,79 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
|||
" AND stops.arrival<?");
|
||||
q_RS_lastOp.bind(1, rsId);
|
||||
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
|
||||
if(ret == SQLITE_ROW)
|
||||
bool isOccupied = false; // No Op means RS is turned off in a depot so it isn't occupied
|
||||
if (ret == SQLITE_ROW)
|
||||
{
|
||||
auto row = q_RS_lastOp.getRows();
|
||||
RsOp operation = RsOp(row.get<int>(1)); //Get last operation
|
||||
jobId = row.get<db_id>(2);
|
||||
isOccupied = (operation == RsOp::Coupled);
|
||||
auto row = q_RS_lastOp.getRows();
|
||||
RsOp operation = RsOp(row.get<int>(1)); // Get last operation
|
||||
jobId = row.get<db_id>(2);
|
||||
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
|
||||
<< "Rs:" << rsId << "Already coupled by this job:" << m_jobId;
|
||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||
<< "Already coupled by this job:" << m_jobId;
|
||||
|
||||
QMessageBox::warning(qApp->activeWindow(),
|
||||
tr("Error"),
|
||||
QMessageBox::warning(qApp->activeWindow(), tr("Error"),
|
||||
tr("Error while adding coupling operation.\n"
|
||||
"Rollingstock %1 is already coupled by this job (%2)")
|
||||
.arg(rsName).arg(m_jobId),
|
||||
.arg(rsName)
|
||||
.arg(m_jobId),
|
||||
QMessageBox::Ok);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId
|
||||
<< "Rs:" << rsId << "Occupied by this job:" << jobId;
|
||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||
<< "Occupied by this job:" << jobId;
|
||||
|
||||
int but = QMessageBox::warning(qApp->activeWindow(),
|
||||
tr("Error"),
|
||||
tr("Error while adding coupling operation.\n"
|
||||
"Rollingstock %1 is already coupled to another job (%2)\n"
|
||||
"Do you still want to couple it?")
|
||||
.arg(rsName).arg(jobId),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
int but =
|
||||
QMessageBox::warning(qApp->activeWindow(), tr("Error"),
|
||||
tr("Error while adding coupling operation.\n"
|
||||
"Rollingstock %1 is already coupled to another job (%2)\n"
|
||||
"Do you still want to couple it?")
|
||||
.arg(rsName)
|
||||
.arg(jobId),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
|
||||
if(but == QMessageBox::No)
|
||||
return false; //Abort
|
||||
if (but == QMessageBox::No)
|
||||
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"
|
||||
" FROM rs_list"
|
||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" WHERE rs_list.id=?");
|
||||
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;
|
||||
}
|
||||
|
||||
auto rs = q_getRSType.getRows();
|
||||
RsType type = RsType(rs.get<int>(0));
|
||||
auto rs = q_getRSType.getRows();
|
||||
RsType type = RsType(rs.get<int>(0));
|
||||
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(),
|
||||
tr("Warning"),
|
||||
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"
|
||||
"Do you still want to couple it?")
|
||||
.arg(rsName),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if(but == QMessageBox::No)
|
||||
return false; //Cancel coupling operation
|
||||
int but = QMessageBox::warning(
|
||||
qApp->activeWindow(), tr("Warning"),
|
||||
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"
|
||||
"Do you still want to couple it?")
|
||||
.arg(rsName),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (but == QMessageBox::No)
|
||||
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();
|
||||
q_addCoupling.reset();
|
||||
|
||||
if(ret != SQLITE_OK)
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId
|
||||
<< "Rs:" << rsId << "Op: Coupled " << "Ret:" << ret
|
||||
<< mDb.error_msg();
|
||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||
<< "Op: Coupled "
|
||||
<< "Ret:" << ret << mDb.error_msg();
|
||||
return false;
|
||||
}
|
||||
|
||||
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"
|
||||
" FROM coupling"
|
||||
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
||||
" JOIN stops s1 ON s1.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(2, rsId);
|
||||
q.bind(3, int(RsOp::Coupled));
|
||||
|
||||
if(q.step() == SQLITE_ROW)
|
||||
if (q.step() == SQLITE_ROW)
|
||||
{
|
||||
auto r = q.getRows();
|
||||
db_id stopId = r.get<db_id>(0);
|
||||
QTime arr = r.get<QTime>(1);
|
||||
db_id stId = r.get<db_id>(2);
|
||||
auto r = q.getRows();
|
||||
db_id stopId = r.get<db_id>(0);
|
||||
QTime arr = r.get<QTime>(1);
|
||||
db_id stId = r.get<db_id>(2);
|
||||
QString stName = r.get<QString>(3);
|
||||
|
||||
qDebug() << "Found coupling, RS:" << rsId << "Stop:" << stopId << "St:" << stId << arr;
|
||||
|
||||
int but = QMessageBox::question(qApp->activeWindow(),
|
||||
tr("Delete coupling?"),
|
||||
tr("You couple %1 also in a next stop in %2 at %3.\n"
|
||||
"Do you want to remove the other coupling operation?")
|
||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
if(but == QMessageBox::Yes)
|
||||
int but =
|
||||
QMessageBox::question(qApp->activeWindow(), tr("Delete coupling?"),
|
||||
tr("You couple %1 also in a next stop in %2 at %3.\n"
|
||||
"Do you want to remove the other coupling operation?")
|
||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
if (but == QMessageBox::Yes)
|
||||
{
|
||||
qDebug() << "Deleting coupling";
|
||||
|
||||
|
@ -226,11 +228,11 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
|||
ret = q_deleteCoupling.execute();
|
||||
q_deleteCoupling.reset();
|
||||
|
||||
if(ret != SQLITE_OK)
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
qWarning() << "Error while deleting next coupling op. Stop:" << stopId
|
||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
||||
<< mDb.error_msg();
|
||||
<< "Rs:" << rsId << "Op: Uncoupled "
|
||||
<< "Ret:" << ret << mDb.error_msg();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -242,7 +244,7 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
|||
else
|
||||
{
|
||||
int row = coupled.indexOf(rsId);
|
||||
if(row == -1)
|
||||
if (row == -1)
|
||||
return false;
|
||||
|
||||
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();
|
||||
q_deleteCoupling.reset();
|
||||
|
||||
if(ret != SQLITE_OK)
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
qWarning() << "Error while deleting coupling op. Stop:" << m_stopId
|
||||
<< "Rs:" << rsId << "Op: Coupled " << "Ret:" << ret
|
||||
<< mDb.error_msg();
|
||||
qWarning() << "Error while deleting coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||
<< "Op: Coupled "
|
||||
<< "Ret:" << ret << mDb.error_msg();
|
||||
return false;
|
||||
}
|
||||
|
||||
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"
|
||||
" FROM coupling"
|
||||
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
||||
" JOIN stops s1 ON s1.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(2, rsId);
|
||||
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();
|
||||
db_id stopId = r.get<db_id>(0);
|
||||
QTime arr = r.get<QTime>(1);
|
||||
db_id stId = r.get<db_id>(2);
|
||||
auto r = q.getRows();
|
||||
db_id stopId = r.get<db_id>(0);
|
||||
QTime arr = r.get<QTime>(1);
|
||||
db_id stId = r.get<db_id>(2);
|
||||
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(),
|
||||
tr("Delete uncoupling?"),
|
||||
tr("You don't couple %1 anymore.\n"
|
||||
"Do you want to remove also the uncoupling operation in %2 at %3?")
|
||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
if(but == QMessageBox::Yes)
|
||||
int but = QMessageBox::question(
|
||||
qApp->activeWindow(), tr("Delete uncoupling?"),
|
||||
tr("You don't couple %1 anymore.\n"
|
||||
"Do you want to remove also the uncoupling operation in %2 at %3?")
|
||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
if (but == QMessageBox::Yes)
|
||||
{
|
||||
qDebug() << "Deleting coupling";
|
||||
|
||||
|
@ -296,11 +300,11 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
|||
ret = q_deleteCoupling.execute();
|
||||
q_deleteCoupling.reset();
|
||||
|
||||
if(ret != SQLITE_OK)
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
qWarning() << "Error while deleting next uncoupling op. Stop:" << stopId
|
||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
||||
<< mDb.error_msg();
|
||||
<< "Rs:" << rsId << "Op: Uncoupled "
|
||||
<< "Ret:" << ret << mDb.error_msg();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -313,14 +317,14 @@ bool RSCouplingInterface::coupleRS(db_id rsId, const QString& rsName, bool on, b
|
|||
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->markRsToUpdate(rsId);
|
||||
|
||||
if(on)
|
||||
if (on)
|
||||
{
|
||||
if(uncoupled.contains(rsId))
|
||||
if (uncoupled.contains(rsId))
|
||||
{
|
||||
qWarning() << "Error already checked:" << rsId;
|
||||
return true;
|
||||
|
@ -332,44 +336,46 @@ bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString& rsName, bool on)
|
|||
int ret = q_addCoupling.execute();
|
||||
q_addCoupling.reset();
|
||||
|
||||
if(ret != SQLITE_OK)
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId
|
||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
||||
<< mDb.error_msg();
|
||||
qWarning() << "Error while adding coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||
<< "Op: Uncoupled "
|
||||
<< "Ret:" << ret << mDb.error_msg();
|
||||
return false;
|
||||
}
|
||||
|
||||
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"
|
||||
" FROM coupling"
|
||||
" JOIN stops s2 ON s2.id=coupling.stop_id"
|
||||
" JOIN stops s1 ON s1.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(2, rsId);
|
||||
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();
|
||||
db_id stopId = r.get<db_id>(0);
|
||||
QTime arr = r.get<QTime>(1);
|
||||
db_id stId = r.get<db_id>(2);
|
||||
auto r = q.getRows();
|
||||
db_id stopId = r.get<db_id>(0);
|
||||
QTime arr = r.get<QTime>(1);
|
||||
db_id stId = r.get<db_id>(2);
|
||||
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(),
|
||||
tr("Delete uncoupling?"),
|
||||
tr("You uncouple %1 also in %2 at %3.\n"
|
||||
"Do you want to remove the other uncoupling operation?")
|
||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
if(but == QMessageBox::Yes)
|
||||
int but =
|
||||
QMessageBox::question(qApp->activeWindow(), tr("Delete uncoupling?"),
|
||||
tr("You uncouple %1 also in %2 at %3.\n"
|
||||
"Do you want to remove the other uncoupling operation?")
|
||||
.arg(rsName, stName, arr.toString("HH:mm")),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
if (but == QMessageBox::Yes)
|
||||
{
|
||||
qDebug() << "Deleting coupling";
|
||||
|
||||
|
@ -378,11 +384,11 @@ bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString& rsName, bool on)
|
|||
ret = q_deleteCoupling.execute();
|
||||
q_deleteCoupling.reset();
|
||||
|
||||
if(ret != SQLITE_OK)
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
qWarning() << "Error while deleting next uncoupling op. Stop:" << stopId
|
||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
||||
<< mDb.error_msg();
|
||||
<< "Rs:" << rsId << "Op: Uncoupled "
|
||||
<< "Ret:" << ret << mDb.error_msg();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -394,7 +400,7 @@ bool RSCouplingInterface::uncoupleRS(db_id rsId, const QString& rsName, bool on)
|
|||
else
|
||||
{
|
||||
int row = uncoupled.indexOf(rsId);
|
||||
if(row == -1)
|
||||
if (row == -1)
|
||||
return false;
|
||||
|
||||
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();
|
||||
q_deleteCoupling.reset();
|
||||
|
||||
if(ret != SQLITE_OK)
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
qWarning() << "Error while deleting coupling op. Stop:" << m_stopId
|
||||
<< "Rs:" << rsId << "Op: Uncoupled " << "Ret:" << ret
|
||||
<< mDb.error_msg();
|
||||
qWarning() << "Error while deleting coupling op. Stop:" << m_stopId << "Rs:" << rsId
|
||||
<< "Op: Uncoupled "
|
||||
<< "Ret:" << ret << mDb.error_msg();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -426,48 +432,45 @@ int RSCouplingInterface::importRSFromJob(db_id otherStopId)
|
|||
" WHERE coupling.stop_id=? AND coupling.operation=0");
|
||||
q_getUncoupled.bind(1, otherStopId);
|
||||
|
||||
int count = 0;
|
||||
int count = 0;
|
||||
bool lineElectrified = stopsModel->isRailwayElectrifiedAfterStop(m_stopId);
|
||||
|
||||
QElapsedTimer timer;
|
||||
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);
|
||||
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);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(q_getUncoupled.stmt(), 3));
|
||||
RsType rsType = RsType(rs.get<int>(4));
|
||||
const char *modelSuffix =
|
||||
reinterpret_cast<char const *>(sqlite3_column_text(q_getUncoupled.stmt(), 3));
|
||||
RsType rsType = RsType(rs.get<int>(4));
|
||||
|
||||
QString rsName = rs_utils::formatNameRef(modelName,
|
||||
modelNameLen,
|
||||
number,
|
||||
modelSuffix,
|
||||
modelSuffixLen,
|
||||
rsType);
|
||||
QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||
modelSuffixLen, rsType);
|
||||
|
||||
//TODO: optimize work
|
||||
if(coupleRS(rsId, rsName, true, !lineElectrified))
|
||||
// TODO: optimize work
|
||||
if (coupleRS(rsId, rsName, true, !lineElectrified))
|
||||
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(
|
||||
qApp->activeWindow(),
|
||||
tr("Continue Importation?"),
|
||||
tr("Rollingstock importation is taking more time than expected.\n"
|
||||
"Do you want to continue?"));
|
||||
qApp->activeWindow(), tr("Continue Importation?"),
|
||||
tr("Rollingstock importation is taking more time than expected.\n"
|
||||
"Do you want to continue?"));
|
||||
|
||||
if(ret == QMessageBox::No)
|
||||
return count; //Abort here
|
||||
if (ret == QMessageBox::No)
|
||||
return count; // Abort here
|
||||
|
||||
timer.restart(); //Count again
|
||||
timer.restart(); // Count again
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,13 +490,14 @@ bool RSCouplingInterface::hasEngineAfterStop(bool *isElectricOnNonElectrifiedLin
|
|||
" LIMIT 1");
|
||||
q_hasEngine.bind(1, m_jobId);
|
||||
q_hasEngine.bind(2, arrival);
|
||||
if(q_hasEngine.step() != SQLITE_ROW)
|
||||
return false; //No engine
|
||||
if (q_hasEngine.step() != SQLITE_ROW)
|
||||
return false; // No engine
|
||||
|
||||
if(isElectricOnNonElectrifiedLine)
|
||||
if (isElectricOnNonElectrifiedLine)
|
||||
{
|
||||
RsEngineSubType subType = RsEngineSubType(q_hasEngine.getRows().get<int>(1));
|
||||
*isElectricOnNonElectrifiedLine = (subType == RsEngineSubType::Electric) && (!isRailwayElectrified());
|
||||
*isElectricOnNonElectrifiedLine =
|
||||
(subType == RsEngineSubType::Electric) && (!isRailwayElectrified());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -35,18 +35,18 @@ QVariant RSListOnDemandModel::data(const QModelIndex &idx, int role) const
|
|||
if (!idx.isValid() || row >= curItemCount || idx.column() >= NCols)
|
||||
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);
|
||||
|
||||
//Temporarily return null
|
||||
// Temporarily return null
|
||||
return role == Qt::DisplayRole ? QVariant("...") : QVariant();
|
||||
}
|
||||
|
||||
const RSItem& item = cache.at(row - cacheFirstRow);
|
||||
const RSItem &item = cache.at(row - cacheFirstRow);
|
||||
|
||||
switch (role)
|
||||
{
|
||||
|
@ -63,9 +63,9 @@ QVariant RSListOnDemandModel::data(const QModelIndex &idx, int role) const
|
|||
}
|
||||
case Qt::FontRole:
|
||||
{
|
||||
if(item.type == RsType::Engine)
|
||||
if (item.type == RsType::Engine)
|
||||
{
|
||||
//Engines in bold
|
||||
// Engines in bold
|
||||
QFont f;
|
||||
f.setBold(true);
|
||||
return f;
|
||||
|
|
|
@ -38,9 +38,13 @@ class RSListOnDemandModel : public IPagedItemModelImpl<RSListOnDemandModel, RSLi
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum { BatchSize = 50 };
|
||||
enum
|
||||
{
|
||||
BatchSize = 50
|
||||
};
|
||||
|
||||
enum Columns {
|
||||
enum Columns
|
||||
{
|
||||
Name = 0,
|
||||
NCols
|
||||
};
|
||||
|
|
|
@ -25,17 +25,12 @@
|
|||
|
||||
#include <QBrush>
|
||||
|
||||
|
||||
RSProxyModel::RSProxyModel(RSCouplingInterface *mgr,
|
||||
RsOp o,
|
||||
RsType type,
|
||||
QObject *parent) :
|
||||
QAbstractListModel (parent),
|
||||
RSProxyModel::RSProxyModel(RSCouplingInterface *mgr, RsOp o, RsType type, QObject *parent) :
|
||||
QAbstractListModel(parent),
|
||||
couplingMgr(mgr),
|
||||
op(o),
|
||||
targetType(type)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if(!idx.isValid() || idx.column() > 0 || idx.row() >= m_data.size())
|
||||
if (!idx.isValid() || idx.column() > 0 || idx.row() >= m_data.size())
|
||||
return QVariant();
|
||||
|
||||
const RsItem& item = m_data.at(idx.row());
|
||||
const RsItem &item = m_data.at(idx.row());
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
return QBrush(qRgb(255, 86, 255)); //Solid light magenta #FF56FF
|
||||
// Error: already coupled or already uncoupled or not coupled at all before this stop
|
||||
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
|
||||
return QBrush(qRgb(255, 61, 67)); //Solid light red #FF3d43
|
||||
// Error: RS is not in this station
|
||||
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
|
||||
return QBrush(qRgb(0, 0, 255), Qt::FDiagPattern); //Blue
|
||||
// Warn Electric traction not possible
|
||||
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;
|
||||
}
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
if(item.flag == ErrNotCoupledBefore)
|
||||
if (item.flag == ErrNotCoupledBefore)
|
||||
{
|
||||
//Error
|
||||
return tr("Rollingstock <b>%1</b> cannot be uncoupled here because it wasn't coupled to this job before this stop "
|
||||
// Error
|
||||
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>"
|
||||
"Please remove the tick").arg(item.rsName);
|
||||
"Please remove the tick")
|
||||
.arg(item.rsName);
|
||||
}
|
||||
if(item.flag == ErrAlreadyCoupled)
|
||||
if (item.flag == ErrAlreadyCoupled)
|
||||
{
|
||||
//Error
|
||||
if(item.jobId == couplingMgr->getJobId())
|
||||
// Error
|
||||
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>"
|
||||
"Please remove the tick").arg(item.rsName);
|
||||
}else{
|
||||
return tr("Rollingstock <b>%1</b> cannot be coupled here because it was already coupled before this stop<br>"
|
||||
return tr("Rollingstock <b>%1</b> cannot be coupled here because it was already "
|
||||
"coupled to this job before this stop<br>"
|
||||
"Please remove the tick")
|
||||
.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>"
|
||||
"Please remove the tick")
|
||||
.arg(item.rsName,
|
||||
JobCategoryName::jobName(item.jobId, item.jobCat));
|
||||
.arg(item.rsName, JobCategoryName::jobName(item.jobId, item.jobCat));
|
||||
}
|
||||
}
|
||||
if(item.flag == WrongStation)
|
||||
if (item.flag == WrongStation)
|
||||
{
|
||||
//Error
|
||||
return tr("Rollingstock <b>%1</b> cannot be coupled here because it is not in this station.<br>"
|
||||
"Please remove the tick").arg(item.rsName);
|
||||
// Error
|
||||
return tr("Rollingstock <b>%1</b> cannot be coupled here because it is not in this "
|
||||
"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
|
||||
return tr("Engine <b>%1</b> is electric but the line is not electrified!").arg(item.rsName);
|
||||
// Warn Electric traction not possible
|
||||
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>.")
|
||||
.arg(item.rsName,
|
||||
JobCategoryName::jobName(item.jobId, item.jobCat),
|
||||
item.time.toString("HH:mm"));
|
||||
return tr("Rollingstock <b>%1</b> is coupled in this station also by <b>%2</b> at "
|
||||
"<b>%3</b>.")
|
||||
.arg(item.rsName, JobCategoryName::jobName(item.jobId, item.jobCat),
|
||||
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>.")
|
||||
.arg(item.rsName,
|
||||
JobCategoryName::jobName(item.jobId, item.jobCat),
|
||||
item.time.toString("HH:mm"));
|
||||
.arg(item.rsName, JobCategoryName::jobName(item.jobId, item.jobCat),
|
||||
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 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")
|
||||
.arg(item.rsName);
|
||||
return tr("Rollingstock <b>%1</b> is never used in this session. You can couple it for "
|
||||
"the first time from any one station")
|
||||
.arg(item.rsName);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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
|
||||
ret = couplingMgr->coupleRS(item.rsId, item.rsName, state == Qt::Checked, targetType == 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);
|
||||
else
|
||||
ret = couplingMgr->uncoupleRS(item.rsId, item.rsName, state == Qt::Checked);
|
||||
|
||||
if(ret)
|
||||
if (ret)
|
||||
emit dataChanged(idx, idx);
|
||||
|
||||
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
|
||||
{
|
||||
if(index.isValid())
|
||||
return Qt::ItemIsEnabled
|
||||
| Qt::ItemNeverHasChildren
|
||||
| Qt::ItemIsSelectable
|
||||
| Qt::ItemIsUserCheckable;
|
||||
if (index.isValid())
|
||||
return Qt::ItemIsEnabled | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable
|
||||
| Qt::ItemIsUserCheckable;
|
||||
return Qt::NoItemFlags;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,11 +33,7 @@ class RSProxyModel : public QAbstractListModel
|
|||
Q_OBJECT
|
||||
|
||||
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;
|
||||
|
||||
|
@ -48,28 +44,28 @@ public:
|
|||
|
||||
enum RSItemFlg
|
||||
{
|
||||
NoFlag = 0,
|
||||
WrongStation = 1,
|
||||
LastOperation = 2,
|
||||
HasNextOperation = 3,
|
||||
FirstUseOfRS = 4,
|
||||
UnusedRS = 5,
|
||||
NoFlag = 0,
|
||||
WrongStation = 1,
|
||||
LastOperation = 2,
|
||||
HasNextOperation = 3,
|
||||
FirstUseOfRS = 4,
|
||||
UnusedRS = 5,
|
||||
ErrNotCoupledBefore = 6,
|
||||
ErrAlreadyCoupled = 7
|
||||
ErrAlreadyCoupled = 7
|
||||
};
|
||||
|
||||
struct RsItem
|
||||
{
|
||||
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;
|
||||
int flag;
|
||||
QTime time; //Can be next or previous operation time
|
||||
QTime time; // Can be next or previous operation time
|
||||
JobCategory jobCat;
|
||||
RsEngineSubType engineType;
|
||||
};
|
||||
|
||||
void loadData(const QVector<RsItem>& items);
|
||||
void loadData(const QVector<RsItem> &items);
|
||||
|
||||
private:
|
||||
QVector<RsItem> m_data;
|
||||
|
|
|
@ -26,7 +26,6 @@ using namespace sqlite3pp;
|
|||
|
||||
#include "utils/rs_utils.h"
|
||||
|
||||
|
||||
StopCouplingModel::StopCouplingModel(sqlite3pp::database &db, QObject *parent) :
|
||||
RSListOnDemandModel(db, parent),
|
||||
m_stopId(0),
|
||||
|
@ -46,65 +45,65 @@ qint64 StopCouplingModel::recalcTotalItemCount()
|
|||
|
||||
void StopCouplingModel::setStop(db_id stopId, RsOp op)
|
||||
{
|
||||
m_stopId = stopId;
|
||||
m_stopId = stopId;
|
||||
m_operation = op;
|
||||
|
||||
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);
|
||||
|
||||
int offset = first + curPage * ItemsPerPage;
|
||||
|
||||
QByteArray sql = "SELECT coupling.rs_id,rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
||||
" FROM coupling"
|
||||
" JOIN rs_list ON rs_list.id=coupling.rs_id"
|
||||
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" WHERE coupling.stop_id=?2 AND coupling.operation=?3"
|
||||
" ORDER BY rs_models.type,rs_models.name,rs_list.number,rs_models.suffix";
|
||||
QByteArray sql =
|
||||
"SELECT coupling.rs_id,rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
||||
" FROM coupling"
|
||||
" JOIN rs_list ON rs_list.id=coupling.rs_id"
|
||||
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" 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";
|
||||
if(offset)
|
||||
if (offset)
|
||||
sql += " OFFSET ?2";
|
||||
|
||||
q.prepare(sql);
|
||||
q.bind(1, BatchSize);
|
||||
q.bind(2, m_stopId);
|
||||
q.bind(3, int(m_operation));
|
||||
if(offset)
|
||||
if (offset)
|
||||
q.bind(2, offset);
|
||||
|
||||
QVector<RSItem> vec(BatchSize);
|
||||
|
||||
auto it = q.begin();
|
||||
auto it = q.begin();
|
||||
const auto end = q.end();
|
||||
|
||||
int i = 0;
|
||||
int i = 0;
|
||||
|
||||
for(; it != end; ++it)
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
auto r = *it;
|
||||
RSItem &item = vec[i];
|
||||
item.rsId = r.get<db_id>(0);
|
||||
auto r = *it;
|
||||
RSItem &item = vec[i];
|
||||
item.rsId = r.get<db_id>(0);
|
||||
|
||||
int number = r.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 2);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 2));
|
||||
int number = r.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 2);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 2));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(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));
|
||||
int modelSuffixLen = sqlite3_column_bytes(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.name = rs_utils::formatNameRef(modelName, modelNameLen,
|
||||
number,
|
||||
modelSuffix, modelSuffixLen,
|
||||
item.type);
|
||||
item.name = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||
modelSuffixLen, item.type);
|
||||
i++;
|
||||
}
|
||||
|
||||
if(i < BatchSize)
|
||||
if (i < BatchSize)
|
||||
vec.remove(i, BatchSize - i);
|
||||
|
||||
postResult(vec, first);
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include "rslistondemandmodel.h"
|
||||
|
||||
|
||||
class StopCouplingModel : public RSListOnDemandModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,9 +36,9 @@ struct StopItem
|
|||
{
|
||||
struct Gate
|
||||
{
|
||||
db_id gateConnId = 0;
|
||||
db_id gateId = 0;
|
||||
int gateTrackNum = -1;
|
||||
db_id gateConnId = 0;
|
||||
db_id gateId = 0;
|
||||
int gateTrackNum = -1;
|
||||
utils::Side stationTrackSide = utils::Side::NSides;
|
||||
};
|
||||
|
||||
|
@ -48,7 +48,7 @@ struct StopItem
|
|||
db_id segmentId = 0;
|
||||
int inTrackNum = -1;
|
||||
int outTrackNum = -1;
|
||||
bool reversed = false;
|
||||
bool reversed = false;
|
||||
};
|
||||
|
||||
db_id stopId = 0;
|
||||
|
@ -62,12 +62,11 @@ struct StopItem
|
|||
QTime arrival;
|
||||
QTime departure;
|
||||
|
||||
int addHere = 0;
|
||||
int addHere = 0;
|
||||
|
||||
StopType type = StopType::Normal;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief The StopModel class
|
||||
*
|
||||
|
@ -80,7 +79,7 @@ class StopModel : public QAbstractListModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StopModel(sqlite3pp::database& db, QObject *parent = nullptr);
|
||||
StopModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||
|
||||
// QAbstractListModel
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
@ -105,7 +104,7 @@ public:
|
|||
|
||||
// Editing
|
||||
void addStop();
|
||||
void removeStop(const QModelIndex& idx);
|
||||
void removeStop(const QModelIndex &idx);
|
||||
void removeLastIfEmpty();
|
||||
|
||||
void uncoupleStillCoupledAtLastStop();
|
||||
|
@ -118,7 +117,8 @@ public:
|
|||
db_id getNewShiftId() const;
|
||||
|
||||
// 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);
|
||||
|
||||
|
@ -129,7 +129,7 @@ public:
|
|||
// Convinience
|
||||
int getStopRow(db_id stopId) const;
|
||||
|
||||
bool isAddHere(const QModelIndex& idx);
|
||||
bool isAddHere(const QModelIndex &idx);
|
||||
|
||||
std::pair<QTime, QTime> getFirstLastTimes() const;
|
||||
|
||||
|
@ -139,10 +139,18 @@ public:
|
|||
bool isRailwayElectrifiedAfterStop(db_id stopId) const;
|
||||
bool isRailwayElectrifiedAfterRow(int row) const;
|
||||
|
||||
inline StopItem getItemAt(int row) const { 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; }
|
||||
|
||||
inline StopItem getItemAt(int row) const
|
||||
{
|
||||
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
|
||||
void rebaseTimesToSpeed(int firstIdx, QTime firstArr, QTime firstDep);
|
||||
|
@ -150,8 +158,7 @@ public:
|
|||
|
||||
bool trySelectTrackForStop(StopItem &item);
|
||||
|
||||
bool trySetTrackConnections(StopItem &item, db_id trackId,
|
||||
QString *outErr);
|
||||
bool trySetTrackConnections(StopItem &item, db_id trackId, QString *outErr);
|
||||
|
||||
bool trySelectNextSegment(StopItem &item, db_id segmentId, int suggestedOutGateTrk,
|
||||
db_id nextStationId, db_id &out_gateId, db_id &out_suggestedTrackId);
|
||||
|
@ -162,7 +169,7 @@ signals:
|
|||
void categoryChanged(int newCat);
|
||||
void jobIdChanged(db_id jobId);
|
||||
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:
|
||||
void setCategory(int value);
|
||||
|
@ -182,25 +189,29 @@ private:
|
|||
db_id createStop(db_id jobId, const QTime &arr, const QTime &dep, StopType type);
|
||||
void deleteStop(db_id stopId);
|
||||
|
||||
bool updateCurrentInGate(StopItem& curStop, const StopItem::Segment& prevSeg);
|
||||
bool updateStopTime(StopItem& item, int row, bool propagate, const QTime &oldArr, const QTime &oldDep);
|
||||
bool updateCurrentInGate(StopItem &curStop, const StopItem::Segment &prevSeg);
|
||||
bool updateStopTime(StopItem &item, int row, bool propagate, const QTime &oldArr,
|
||||
const QTime &oldDep);
|
||||
|
||||
int calcTravelTime(db_id segmentId);
|
||||
int defaultStopTimeSec();
|
||||
|
||||
void shiftStopsBy24hoursFrom(const QTime& startTime);
|
||||
void shiftStopsBy24hoursFrom(const QTime &startTime);
|
||||
|
||||
friend class RSCouplingInterface;
|
||||
bool startInfoEditing();
|
||||
bool startStopsEditing();
|
||||
bool endStopsEditing();
|
||||
inline void markRsToUpdate(db_id rsId) { rsToUpdate.insert(rsId); }
|
||||
inline void markRsToUpdate(db_id rsId)
|
||||
{
|
||||
rsToUpdate.insert(rsId);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
sqlite3pp::database& mDb;
|
||||
sqlite3pp::database &mDb;
|
||||
|
||||
QVector<StopItem> stops;
|
||||
|
||||
|
@ -218,8 +229,8 @@ private:
|
|||
|
||||
enum EditState
|
||||
{
|
||||
NotEditing = 0,
|
||||
InfoEditing = 1,
|
||||
NotEditing = 0,
|
||||
InfoEditing = 1,
|
||||
StopsEditing = 2
|
||||
};
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ using namespace sqlite3pp;
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
TrainAssetModel::TrainAssetModel(database& db, QObject *parent) :
|
||||
TrainAssetModel::TrainAssetModel(database &db, QObject *parent) :
|
||||
RSListOnDemandModel(db, parent),
|
||||
m_jobId(0),
|
||||
m_mode(BeforeStop)
|
||||
|
@ -45,30 +45,33 @@ qint64 TrainAssetModel::recalcTotalItemCount()
|
|||
" GROUP BY coupling.rs_id"
|
||||
" HAVING coupling.operation=1)");
|
||||
q.bind(1, m_jobId);
|
||||
//HACK: 1 minute is the min interval between stops,
|
||||
//by adding 1 minute we include the current stop but leave out the next one
|
||||
if(m_mode == AfterStop)
|
||||
// HACK: 1 minute is the min interval between stops,
|
||||
// by adding 1 minute we include the current stop but leave out the next one
|
||||
if (m_mode == AfterStop)
|
||||
q.bind(2, m_arrival.addSecs(60));
|
||||
else
|
||||
q.bind(2, m_arrival);
|
||||
int ret = q.step();
|
||||
if(ret != SQLITE_ROW)
|
||||
if (ret != SQLITE_ROW)
|
||||
qWarning() << "TrainAssetModel: " << mDb.error_msg() << mDb.error_code();
|
||||
|
||||
const qint64 count = q.getRows().get<int>(0);
|
||||
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);
|
||||
|
||||
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("
|
||||
"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"
|
||||
" JOIN coupling ON coupling.stop_id=stops.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 += " LIMIT ?1";
|
||||
if(offset)
|
||||
if (offset)
|
||||
sql += " OFFSET ?2";
|
||||
|
||||
q.prepare(sql);
|
||||
q.bind(1, BatchSize);
|
||||
q.bind(3, m_jobId);
|
||||
//HACK: 1 minute is the min interval between stops,
|
||||
//by adding 1 minute we include the current stop but leave out the next one
|
||||
if(m_mode == AfterStop)
|
||||
// HACK: 1 minute is the min interval between stops,
|
||||
// by adding 1 minute we include the current stop but leave out the next one
|
||||
if (m_mode == AfterStop)
|
||||
q.bind(4, m_arrival.addSecs(60));
|
||||
else
|
||||
q.bind(4, m_arrival);
|
||||
if(offset)
|
||||
if (offset)
|
||||
q.bind(2, offset);
|
||||
|
||||
QVector<RSItem> vec(BatchSize);
|
||||
|
||||
auto it = q.begin();
|
||||
auto it = q.begin();
|
||||
const auto end = q.end();
|
||||
|
||||
int i = 0;
|
||||
for(; it != end; ++it)
|
||||
int i = 0;
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
auto r = *it;
|
||||
RSItem &item = vec[i];
|
||||
item.rsId = r.get<db_id>(0);
|
||||
auto r = *it;
|
||||
RSItem &item = vec[i];
|
||||
item.rsId = r.get<db_id>(0);
|
||||
|
||||
int number = r.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 2);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 2));
|
||||
int number = r.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 2);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 2));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(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));
|
||||
int modelSuffixLen = sqlite3_column_bytes(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.name = rs_utils::formatNameRef(modelName, modelNameLen,
|
||||
number,
|
||||
modelSuffix, modelSuffixLen,
|
||||
item.type);
|
||||
item.name = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||
modelSuffixLen, item.type);
|
||||
i++;
|
||||
}
|
||||
|
||||
if(i < BatchSize)
|
||||
if (i < BatchSize)
|
||||
vec.remove(i, BatchSize - i);
|
||||
|
||||
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)
|
||||
{
|
||||
m_jobId = jobId;
|
||||
m_jobId = jobId;
|
||||
m_arrival = arrival;
|
||||
m_mode = mode;
|
||||
m_mode = mode;
|
||||
|
||||
refreshData(true);
|
||||
}
|
||||
|
|
|
@ -27,12 +27,13 @@ class TrainAssetModel : public RSListOnDemandModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Mode {
|
||||
enum Mode
|
||||
{
|
||||
BeforeStop,
|
||||
AfterStop
|
||||
};
|
||||
|
||||
TrainAssetModel(sqlite3pp::database& db, QObject *parent = nullptr);
|
||||
TrainAssetModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||
|
||||
// TrainAssetModel
|
||||
void setStop(db_id jobId, QTime arrival, Mode mode);
|
||||
|
|
|
@ -36,15 +36,15 @@
|
|||
#include "app/session.h"
|
||||
|
||||
RSCoupleDialog::RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent) :
|
||||
QDialog (parent),
|
||||
QDialog(parent),
|
||||
couplingMgr(mgr),
|
||||
legend(nullptr),
|
||||
m_showLegend(false),
|
||||
op(o)
|
||||
{
|
||||
engModel = new RSProxyModel(couplingMgr, op, RsType::Engine, this);
|
||||
coachModel = new RSProxyModel(couplingMgr, op, RsType::Coach, this);
|
||||
freightModel = new RSProxyModel(couplingMgr, op, RsType::FreightWagon, this);
|
||||
engModel = new RSProxyModel(couplingMgr, op, RsType::Engine, this);
|
||||
coachModel = new RSProxyModel(couplingMgr, op, RsType::Coach, this);
|
||||
freightModel = new RSProxyModel(couplingMgr, op, RsType::FreightWagon, this);
|
||||
|
||||
QGridLayout *lay = new QGridLayout(this);
|
||||
|
||||
|
@ -86,7 +86,8 @@ RSCoupleDialog::RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent
|
|||
showHideLegendBut = new QPushButton;
|
||||
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::rejected, this, &QDialog::reject);
|
||||
buttonLay->addWidget(box);
|
||||
|
@ -100,13 +101,14 @@ RSCoupleDialog::RSCoupleDialog(RSCouplingInterface *mgr, RsOp o, QWidget *parent
|
|||
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;
|
||||
|
||||
sqlite3pp::query q(db);
|
||||
|
||||
if(op == RsOp::Coupled)
|
||||
if (op == RsOp::Coupled)
|
||||
{
|
||||
/* Show Couple-able RS:
|
||||
* - 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
|
||||
*/
|
||||
|
||||
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 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"
|
||||
" UNION ALL"
|
||||
// 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"
|
||||
" UNION ALL"
|
||||
|
||||
//Select RS uncoupled before our arrival (included RS uncoupled at exact same time) (except uncoupled by us)
|
||||
" SELECT 2 AS p, coupling.rs_id AS rs_id, MAX(stops.arrival) AS arr, stops.job_id AS job_id"
|
||||
" FROM stops"
|
||||
" JOIN coupling ON coupling.stop_id=stops.id"
|
||||
" WHERE stops.station_id=?1 AND stops.arrival <= ?2 AND stops.id<>?3"
|
||||
" GROUP BY coupling.rs_id"
|
||||
" HAVING coupling.operation=0"
|
||||
" UNION ALL"
|
||||
// Select RS uncoupled before our arrival (included RS uncoupled at exact same time)
|
||||
// (except uncoupled by us)
|
||||
" SELECT 2 AS p, coupling.rs_id AS rs_id, MAX(stops.arrival) AS arr, stops.job_id AS "
|
||||
"job_id"
|
||||
" FROM stops"
|
||||
" JOIN coupling ON coupling.stop_id=stops.id"
|
||||
" WHERE stops.station_id=?1 AND stops.arrival <= ?2 AND stops.id<>?3"
|
||||
" 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 3 AS p, coupling.rs_id, MIN(stops.arrival) AS arr, stops.job_id AS job_id"
|
||||
" FROM coupling"
|
||||
" JOIN stops ON stops.id=coupling.stop_id"
|
||||
" WHERE stops.station_id=?1 AND stops.arrival > ?2"
|
||||
" GROUP BY coupling.rs_id"
|
||||
" HAVING coupling.operation=1"
|
||||
" UNION ALL"
|
||||
// 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"
|
||||
" FROM coupling"
|
||||
" JOIN stops ON stops.id=coupling.stop_id"
|
||||
" WHERE stops.station_id=?1 AND stops.arrival > ?2"
|
||||
" GROUP BY coupling.rs_id"
|
||||
" HAVING coupling.operation=1"
|
||||
" UNION ALL"
|
||||
|
||||
//Select coupled RS for first time
|
||||
" SELECT 4 AS p, rs_list.id AS rs_id, NULL AS arr, NULL AS job_id"
|
||||
" FROM rs_list"
|
||||
" WHERE NOT EXISTS ("
|
||||
" 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)"
|
||||
" UNION ALL"
|
||||
// Select coupled RS for first time
|
||||
" SELECT 4 AS p, rs_list.id AS rs_id, NULL AS arr, NULL AS job_id"
|
||||
" FROM rs_list"
|
||||
" WHERE NOT EXISTS ("
|
||||
" 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)"
|
||||
" UNION ALL"
|
||||
|
||||
//Select unused RS (RS without any operation)
|
||||
" SELECT 5 AS p, rs_list.id AS rs_id, NULL AS arr, NULL AS job_id"
|
||||
" FROM rs_list"
|
||||
" WHERE NOT EXISTS (SELECT coupling.rs_id FROM coupling WHERE coupling.rs_id=rs_list.id)"
|
||||
" UNION ALL"
|
||||
// Select unused RS (RS without any operation)
|
||||
" SELECT 5 AS p, rs_list.id AS rs_id, NULL AS arr, NULL AS job_id"
|
||||
" FROM rs_list"
|
||||
" WHERE NOT EXISTS (SELECT coupling.rs_id FROM coupling WHERE coupling.rs_id=rs_list.id)"
|
||||
" UNION ALL"
|
||||
|
||||
//Select RS coupled before our arrival (already coupled by this job or occupied by other job)
|
||||
" SELECT 7 AS p, c1.rs_id, MAX(s1.arrival) AS arr, s1.job_id AS job_id"
|
||||
" FROM coupling c1"
|
||||
" JOIN coupling c2 ON c2.rs_id=c1.rs_id"
|
||||
" JOIN stops s1 ON s1.id=c2.stop_id"
|
||||
" WHERE c1.stop_id=?3 AND c1.operation=1 AND s1.arrival<?2"
|
||||
" GROUP BY c1.rs_id"
|
||||
" HAVING c2.operation=1"
|
||||
" ) AS sub"
|
||||
// Select RS coupled before our arrival (already coupled by this job or occupied by other
|
||||
// job)
|
||||
" SELECT 7 AS p, c1.rs_id, MAX(s1.arrival) AS arr, s1.job_id AS job_id"
|
||||
" FROM coupling c1"
|
||||
" JOIN coupling c2 ON c2.rs_id=c1.rs_id"
|
||||
" JOIN stops s1 ON s1.id=c2.stop_id"
|
||||
" WHERE c1.stop_id=?3 AND c1.operation=1 AND s1.arrival<?2"
|
||||
" GROUP BY c1.rs_id"
|
||||
" 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
|
||||
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" LEFT JOIN jobs ON jobs.id=sub.job_id"
|
||||
" GROUP BY sub.rs_id"
|
||||
" ORDER BY rs_models.name, rs_list.number");
|
||||
" 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
|
||||
" LEFT JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" 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(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
|
||||
*/
|
||||
|
||||
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("
|
||||
"SELECT 8 AS p, coupling.rs_id AS rs_id, MAX(stops.arrival) AS arr"
|
||||
" FROM stops"
|
||||
" JOIN coupling ON coupling.stop_id=stops.id"
|
||||
" WHERE stops.arrival<?2"
|
||||
" GROUP BY coupling.rs_id"
|
||||
" HAVING coupling.operation=1 AND stops.job_id=?1"
|
||||
" UNION ALL"
|
||||
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("
|
||||
"SELECT 8 AS p, coupling.rs_id AS rs_id, MAX(stops.arrival) AS arr"
|
||||
" FROM stops"
|
||||
" JOIN coupling ON coupling.stop_id=stops.id"
|
||||
" WHERE stops.arrival<?2"
|
||||
" 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 6 AS p, coupling.rs_id AS rs_id, NULL AS arr FROM coupling WHERE coupling.stop_id=?3 AND coupling.operation=0"
|
||||
") 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
|
||||
" 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");
|
||||
// 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"
|
||||
") 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
|
||||
" 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(2, arrival);
|
||||
q.bind(3, stopId);
|
||||
}
|
||||
|
||||
for(auto rs : q)
|
||||
for (auto rs : q)
|
||||
{
|
||||
/*Priority flag:
|
||||
* 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
|
||||
* (It could have wrong operation in other station that should be fixed by user,
|
||||
* 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
|
||||
* 4: The RS is used for first time
|
||||
* 5: The RS is unsed
|
||||
* 6: RS was not coupled before this stop and you are trying to uncouple it
|
||||
* 7: Normal RS uncouple-able, used to win against 6
|
||||
*/
|
||||
* 3: The RS is free but a job will couple it in the future so you should bring it back here
|
||||
* before that time 4: The RS is used for first time 5: The RS is unsed 6: RS was not
|
||||
* coupled before this stop and you are trying to uncouple it 7: Normal RS uncouple-able,
|
||||
* used to win against 6
|
||||
*/
|
||||
|
||||
RSProxyModel::RsItem item;
|
||||
item.flag = rs.get<int>(0);
|
||||
item.rsId = rs.get<db_id>(1);
|
||||
item.flag = rs.get<int>(0);
|
||||
item.rsId = rs.get<db_id>(1);
|
||||
|
||||
int number = rs.get<int>(2);
|
||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 3);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 3));
|
||||
int number = rs.get<int>(2);
|
||||
int modelNameLen = sqlite3_column_bytes(q.stmt(), 3);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 3));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 4);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(q.stmt(), 4));
|
||||
RsType type = RsType(rs.get<int>(5));
|
||||
int modelSuffixLen = sqlite3_column_bytes(q.stmt(), 4);
|
||||
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(q.stmt(), 4));
|
||||
RsType type = RsType(rs.get<int>(5));
|
||||
RsEngineSubType subType = RsEngineSubType(rs.get<int>(6));
|
||||
|
||||
item.rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
||||
number,
|
||||
modelSuffix, modelSuffixLen,
|
||||
type);
|
||||
item.rsName = rs_utils::formatNameRef(modelName, modelNameLen, number, modelSuffix,
|
||||
modelSuffixLen, type);
|
||||
|
||||
item.engineType = RsEngineSubType::Invalid;
|
||||
|
||||
item.time = rs.get<QTime>(7);
|
||||
item.jobId = rs.get<db_id>(8);
|
||||
item.jobCat = JobCategory(rs.get<int>(9));
|
||||
item.time = rs.get<QTime>(7);
|
||||
item.jobId = rs.get<db_id>(8);
|
||||
item.jobCat = JobCategory(rs.get<int>(9));
|
||||
|
||||
switch (type)
|
||||
{
|
||||
|
@ -274,7 +287,7 @@ void RSCoupleDialog::loadProxyModels(sqlite3pp::database& db, db_id jobId, db_id
|
|||
|
||||
void RSCoupleDialog::done(int ret)
|
||||
{
|
||||
//Save legend state
|
||||
// Save legend state
|
||||
AppSettings.setShowCouplingLegend(m_showLegend);
|
||||
|
||||
QDialog::done(ret);
|
||||
|
@ -294,35 +307,43 @@ void RSCoupleDialog::setLegendVisible(bool val)
|
|||
{
|
||||
m_showLegend = val;
|
||||
|
||||
if(legend->isVisible() && !m_showLegend)
|
||||
if (legend->isVisible() && !m_showLegend)
|
||||
{
|
||||
legend->hide();
|
||||
}
|
||||
else if(m_showLegend && !legend->isVisible())
|
||||
else if (m_showLegend && !legend->isVisible())
|
||||
{
|
||||
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);
|
||||
QLabel *label = new QLabel(tr("<style>\n"
|
||||
"table, td {"
|
||||
"border: 1px solid black;"
|
||||
"border-collapse:collapse;"
|
||||
"padding:5px;"
|
||||
" }"
|
||||
"</style>"
|
||||
"<table style=\"font-size:%1pt;padding:10pt\"><tr>"
|
||||
"<td><span style=\"background-color:#FFFFFF\">___</span> This item is free in current station.</td>"
|
||||
"<td><span style=\"background-color:#FF3d43\">___</span> The item isn't in this station.</td>"
|
||||
"</tr><tr>"
|
||||
"<td><span style=\"background-color:#00FFFF\">___</span> First use of this item.</td>"
|
||||
"<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));
|
||||
QLabel *label = new QLabel(
|
||||
tr("<style>\n"
|
||||
"table, td {"
|
||||
"border: 1px solid black;"
|
||||
"border-collapse:collapse;"
|
||||
"padding:5px;"
|
||||
" }"
|
||||
"</style>"
|
||||
"<table style=\"font-size:%1pt;padding:10pt\"><tr>"
|
||||
"<td><span style=\"background-color:#FFFFFF\">___</span> This item is free in "
|
||||
"current station.</td>"
|
||||
"<td><span style=\"background-color:#FF3d43\">___</span> The item isn't in this "
|
||||
"station.</td>"
|
||||
"</tr><tr>"
|
||||
"<td><span style=\"background-color:#00FFFF\">___</span> First use of this "
|
||||
"item.</td>"
|
||||
"<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->setWordWrap(true);
|
||||
legendLay->addWidget(label);
|
||||
|
|
|
@ -32,14 +32,15 @@ namespace sqlite3pp {
|
|||
class database;
|
||||
}
|
||||
|
||||
//FIXME: on-demand load and filter
|
||||
// FIXME: on-demand load and filter
|
||||
class RSCoupleDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
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:
|
||||
void done(int ret) override;
|
||||
|
|
|
@ -34,7 +34,7 @@ ShiftBusyDlg::ShiftBusyDlg(QWidget *parent) :
|
|||
{
|
||||
QVBoxLayout *lay = new QVBoxLayout(this);
|
||||
|
||||
m_label = new QLabel;
|
||||
m_label = new QLabel;
|
||||
lay->addWidget(m_label);
|
||||
|
||||
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>"
|
||||
"The selected shift is busy:<br>"
|
||||
"From: %3 To: %4")
|
||||
.arg(model->getShiftName(),
|
||||
model->getJobName(),
|
||||
model->getStart().toString("HH:mm"),
|
||||
model->getEnd().toString("HH:mm")));
|
||||
.arg(model->getShiftName(), model->getJobName(),
|
||||
model->getStart().toString("HH:mm"),
|
||||
model->getEnd().toString("HH:mm")));
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
explicit ShiftBusyDlg(QWidget *parent = nullptr);
|
||||
|
||||
void setModel(ShiftBusyModel *m);
|
||||
|
||||
private:
|
||||
QLabel *m_label;
|
||||
QTableView *view;
|
||||
|
|
|
@ -35,9 +35,10 @@ ShiftBusyModel::ShiftBusyModel(sqlite3pp::database &db, QObject *parent) :
|
|||
|
||||
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:
|
||||
return tr("Job");
|
||||
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)
|
||||
return QVariant();
|
||||
|
||||
const JobInfo& info = m_data.at(row);
|
||||
const JobInfo &info = m_data.at(row);
|
||||
|
||||
switch (role)
|
||||
{
|
||||
|
@ -94,13 +95,13 @@ void ShiftBusyModel::loadData(db_id shiftId, db_id jobId, const QTime &start, co
|
|||
m_data.clear();
|
||||
|
||||
m_shiftId = shiftId;
|
||||
m_jobId = jobId;
|
||||
m_start = start;
|
||||
m_end = end;
|
||||
m_jobId = jobId;
|
||||
m_start = start;
|
||||
m_end = end;
|
||||
|
||||
query q(mDb, "SELECT name FROM jobshifts WHERE id=?");
|
||||
q.bind(1, m_shiftId);
|
||||
if(q.step() != SQLITE_ROW)
|
||||
if (q.step() != SQLITE_ROW)
|
||||
{
|
||||
endResetModel();
|
||||
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(3, m_end);
|
||||
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);
|
||||
|
||||
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(3, m_end);
|
||||
|
||||
for(auto j : q)
|
||||
for (auto j : q)
|
||||
{
|
||||
JobInfo info;
|
||||
info.jobId = j.get<db_id>(0);
|
||||
info.jobId = j.get<db_id>(0);
|
||||
info.jobCat = JobCategory(j.get<int>(1));
|
||||
|
||||
if(info.jobId == m_jobId)
|
||||
if (info.jobId == m_jobId)
|
||||
{
|
||||
m_jobCat = info.jobCat;
|
||||
continue;
|
||||
}
|
||||
|
||||
info.start = j.get<QTime>(3);
|
||||
info.end = j.get<QTime>(4);
|
||||
info.end = j.get<QTime>(4);
|
||||
|
||||
m_data.append(info);
|
||||
}
|
||||
|
|
|
@ -30,14 +30,14 @@ namespace sqlite3pp {
|
|||
class database;
|
||||
}
|
||||
|
||||
//TODO: move to shifts subdir
|
||||
// TODO: move to shifts subdir
|
||||
class ShiftBusyModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum Columns {
|
||||
enum Columns
|
||||
{
|
||||
JobCol = 0,
|
||||
Start,
|
||||
End,
|
||||
|
@ -55,7 +55,8 @@ public:
|
|||
ShiftBusyModel(sqlite3pp::database &db, QObject *parent = nullptr);
|
||||
|
||||
// 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:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
@ -63,14 +64,26 @@ public:
|
|||
|
||||
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 getEnd() const { return m_end; }
|
||||
inline QTime getStart() const
|
||||
{
|
||||
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;
|
||||
|
||||
private:
|
||||
|
|
|
@ -41,11 +41,11 @@ StopDelegate::StopDelegate(sqlite3pp::database &db, QObject *parent) :
|
|||
void StopDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
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 StopItem item = model->getItemAt(index.row());
|
||||
const bool isTransit = item.type == StopType::Transit;
|
||||
const StopItem item = model->getItemAt(index.row());
|
||||
const bool isTransit = item.type == StopType::Transit;
|
||||
|
||||
query q(mDb, "SELECT name FROM stations WHERE id=?");
|
||||
q.bind(1, item.stationId);
|
||||
|
@ -56,7 +56,7 @@ void StopDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
|||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
//Draw bottom border
|
||||
// Draw bottom border
|
||||
painter->setPen(QPen(Qt::black, 1));
|
||||
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());
|
||||
|
||||
const double top = rect.top();
|
||||
const double bottom = rect.bottom();
|
||||
const double left = rect.left();
|
||||
const double width = rect.width();
|
||||
const double height = rect.height();
|
||||
const double top = rect.top();
|
||||
const double bottom = rect.bottom();
|
||||
const double left = rect.left();
|
||||
const double width = rect.width();
|
||||
const double height = rect.height();
|
||||
|
||||
const double stHeight = top + (isTransit ? 0.0 : height * 0.1);
|
||||
const double timeHeight = top + height * 0.4;
|
||||
const double lineHeight = top + height * 0.65;
|
||||
const double stHeight = top + (isTransit ? 0.0 : height * 0.1);
|
||||
const double timeHeight = top + height * 0.4;
|
||||
const double lineHeight = top + height * 0.65;
|
||||
|
||||
const double arrX = left + width * (isTransit ? 0.4 : 0.2);
|
||||
const double depX = left + width * 0.6;
|
||||
const double arrX = left + width * (isTransit ? 0.4 : 0.2);
|
||||
const double depX = left + width * 0.6;
|
||||
const double transitLineX = left + width * 0.2;
|
||||
|
||||
|
||||
if(item.addHere == 0)
|
||||
if (item.addHere == 0)
|
||||
{
|
||||
//Draw item
|
||||
//Station name
|
||||
painter->drawText(QRectF(left, stHeight, width, bottom - stHeight),
|
||||
station,
|
||||
// Draw item
|
||||
// Station name
|
||||
painter->drawText(QRectF(left, stHeight, width, bottom - stHeight), station,
|
||||
QTextOption(Qt::AlignHCenter));
|
||||
|
||||
if(item.type != StopType::First)
|
||||
if (item.type != StopType::First)
|
||||
{
|
||||
//Arrival
|
||||
// Arrival
|
||||
painter->drawText(QRectF(arrX, timeHeight, width, bottom - timeHeight),
|
||||
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),
|
||||
item.departure.toString("HH:mm"));
|
||||
}
|
||||
|
||||
//Check direction
|
||||
if(item.fromGate.gateConnId && item.toGate.gateConnId
|
||||
&& item.type != StopType::First && item.type != StopType::Last)
|
||||
// Check direction
|
||||
if (item.fromGate.gateConnId && item.toGate.gateConnId && item.type != StopType::First
|
||||
&& item.type != StopType::Last)
|
||||
{
|
||||
//Ignore First and Last stop (sometimes they have fake in/out gates set which might trigger this message)
|
||||
//Both entry and exit path are set, check direction
|
||||
if(item.fromGate.stationTrackSide == item.toGate.stationTrackSide)
|
||||
// Ignore First and Last stop (sometimes they have fake in/out gates set which might
|
||||
// trigger this message) Both entry and exit path are set, check direction
|
||||
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);
|
||||
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 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);
|
||||
}
|
||||
|
||||
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));
|
||||
painter->drawPixmap(lightningTopLeft, m_lightningPix);
|
||||
|
||||
if(!nextSegmentElectrified)
|
||||
if (!nextSegmentElectrified)
|
||||
{
|
||||
//Next railway is not electrified, cross the lightning
|
||||
//Then keep red pen to draw next segment name
|
||||
// Next railway is not electrified, cross the lightning
|
||||
// Then keep red pen to draw next segment name
|
||||
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.bind(1, item.nextSegment.segmentId);
|
||||
q.step();
|
||||
auto r = q.getRows();
|
||||
auto r = q.getRows();
|
||||
const QString segName = r.get<QString>(0);
|
||||
q.reset();
|
||||
|
||||
const double lineRightX = left + width * 0.8;
|
||||
painter->drawText(QRectF(transitLineX, lineHeight, lineRightX - left, bottom - lineHeight),
|
||||
tr("Seg: %1").arg(segName),
|
||||
QTextOption(Qt::AlignHCenter));
|
||||
painter->drawText(
|
||||
QRectF(transitLineX, lineHeight, lineRightX - left, bottom - lineHeight),
|
||||
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->drawText(QRectF(lineRightX, lineHeight, left + width - lineRightX, bottom - lineHeight),
|
||||
QString::number(item.toGate.gateTrackNum),
|
||||
QTextOption(Qt::AlignHCenter));
|
||||
painter->drawText(
|
||||
QRectF(lineRightX, lineHeight, left + width - lineRightX, bottom - lineHeight),
|
||||
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->setBrush(Qt::red);
|
||||
painter->drawLine(QLineF(transitLineX, rect.top(),
|
||||
transitLineX, rect.bottom()));
|
||||
painter->drawLine(QLineF(transitLineX, rect.top(), transitLineX, rect.bottom()));
|
||||
|
||||
painter->drawEllipse(QRectF(transitLineX - 12 / 2,
|
||||
rect.top() + rect.height() * 0.4,
|
||||
12, 12));
|
||||
painter->drawEllipse(
|
||||
QRectF(transitLineX - 12 / 2, rect.top() + rect.height() * 0.4, 12, 12));
|
||||
}
|
||||
|
||||
}
|
||||
else if (item.addHere == 1)
|
||||
{
|
||||
|
@ -200,30 +197,29 @@ void StopDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
|||
painter->restore();
|
||||
}
|
||||
|
||||
QSize StopDelegate::sizeHint(const QStyleOptionViewItem &/*option*/,
|
||||
QSize StopDelegate::sizeHint(const QStyleOptionViewItem & /*option*/,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
int w = 200;
|
||||
int h = NormalStopHeight;
|
||||
int w = 200;
|
||||
int h = NormalStopHeight;
|
||||
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);
|
||||
|
||||
const StopItem& item = model->getItemAt(index.row());
|
||||
if(item.type == StopType::Transit)
|
||||
const StopItem &item = model->getItemAt(index.row());
|
||||
if (item.type == StopType::Transit)
|
||||
h = TransitStopHeight;
|
||||
if(item.addHere != 0)
|
||||
if (item.addHere != 0)
|
||||
h = AddHereHeight;
|
||||
return QSize(w, h);
|
||||
}
|
||||
|
||||
QWidget *StopDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &/*option*/,
|
||||
QWidget *StopDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/,
|
||||
const QModelIndex &index) const
|
||||
|
||||
{
|
||||
StopModel *model = const_cast<StopModel*>(static_cast<const StopModel *>(index.model()));
|
||||
if(model->isAddHere(index))
|
||||
StopModel *model = const_cast<StopModel *>(static_cast<const StopModel *>(index.model()));
|
||||
if (model->isAddHere(index))
|
||||
{
|
||||
qDebug() << index << "is AddHere";
|
||||
return nullptr;
|
||||
|
@ -231,35 +227,34 @@ QWidget *StopDelegate::createEditor(QWidget *parent,
|
|||
|
||||
StopEditor *editor = new StopEditor(mDb, model, parent);
|
||||
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);
|
||||
|
||||
//See 'StopEditor::popupLinesCombo'
|
||||
// See 'StopEditor::popupLinesCombo'
|
||||
connect(this, &StopDelegate::popupEditorSegmentCombo, editor, &StopEditor::popupSegmentCombo);
|
||||
connect(editor, &StopEditor::nextSegmentChosen, this, &StopDelegate::onEditorSegmentChosen);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
void StopDelegate::setEditorData(QWidget *editor,
|
||||
const QModelIndex &index) const
|
||||
void StopDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
StopEditor *ed = static_cast<StopEditor*>(editor);
|
||||
if(ed->isEnabled()) //We already set data
|
||||
StopEditor *ed = static_cast<StopEditor *>(editor);
|
||||
if (ed->isEnabled()) // We already set data
|
||||
return;
|
||||
ed->setEnabled(true); //Mark it
|
||||
ed->setEnabled(true); // Mark it
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -272,7 +267,7 @@ void StopDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
|||
DEBUG_IMPORTANT_ENTRY;
|
||||
|
||||
qDebug() << "End editing: stop" << index.row();
|
||||
StopEditor *ed = static_cast<StopEditor*>(editor);
|
||||
StopEditor *ed = static_cast<StopEditor *>(editor);
|
||||
StopModel *stopModel = static_cast<StopModel *>(model);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void StopDelegate::onEditorSegmentChosen(StopEditor *editor)
|
||||
{
|
||||
if(editor->closeOnSegmentChosen())
|
||||
if (editor->closeOnSegmentChosen())
|
||||
{
|
||||
emit commitData(editor);
|
||||
emit closeEditor(editor, StopDelegate::EditNextItem);
|
||||
|
@ -296,10 +292,11 @@ void StopDelegate::onEditorSegmentChosen(StopEditor *editor)
|
|||
|
||||
void StopDelegate::refreshPixmaps()
|
||||
{
|
||||
const QString iconPath = QCoreApplication::instance()->applicationDirPath() + QStringLiteral("/icons");
|
||||
const QString iconPath =
|
||||
QCoreApplication::instance()->applicationDirPath() + QStringLiteral("/icons");
|
||||
|
||||
//Square pixmaps
|
||||
m_lightningPix = QPixmap(PixWidth, PixHeight);
|
||||
// Square pixmaps
|
||||
m_lightningPix = QPixmap(PixWidth, PixHeight);
|
||||
m_reverseDirPix = QPixmap(PixWidth, PixHeight);
|
||||
|
||||
m_lightningPix.fill(Qt::transparent);
|
||||
|
@ -309,26 +306,26 @@ void StopDelegate::refreshPixmaps()
|
|||
QPainter painter;
|
||||
QRectF iconRect;
|
||||
|
||||
//Cache Lightning
|
||||
// Cache Lightning
|
||||
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));
|
||||
|
||||
//Center on pixmap
|
||||
// Center on pixmap
|
||||
iconRect.moveTop((PixHeight - iconRect.height()) / 2);
|
||||
iconRect.moveLeft((PixWidth - iconRect.width()) / 2);
|
||||
painter.begin(&m_lightningPix);
|
||||
mSvg.render(&painter, iconRect);
|
||||
painter.end();
|
||||
|
||||
//Cache Reverse Direction
|
||||
// Cache Reverse Direction
|
||||
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));
|
||||
|
||||
//Center on pixmap
|
||||
// Center on pixmap
|
||||
iconRect.moveTop((PixHeight - iconRect.height()) / 2);
|
||||
iconRect.moveLeft((PixWidth - iconRect.width()) / 2);
|
||||
painter.begin(&m_reverseDirPix);
|
||||
|
|
|
@ -46,15 +46,15 @@ public:
|
|||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
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:
|
||||
/*!
|
||||
|
@ -87,12 +87,12 @@ private:
|
|||
QPixmap m_lightningPix;
|
||||
QPixmap m_reverseDirPix;
|
||||
|
||||
static constexpr int NormalStopHeight = 100;
|
||||
static constexpr int NormalStopHeight = 100;
|
||||
static constexpr int TransitStopHeight = 80;
|
||||
static constexpr int AddHereHeight = 30;
|
||||
static constexpr int AddHereHeight = 30;
|
||||
|
||||
static constexpr int PixWidth = 35;
|
||||
static constexpr int PixHeight = PixWidth;
|
||||
static constexpr int PixWidth = 35;
|
||||
static constexpr int PixHeight = PixWidth;
|
||||
};
|
||||
|
||||
#endif // STOPDELEGATE_H
|
||||
|
|
|
@ -33,43 +33,47 @@
|
|||
|
||||
#include <QMessageBox>
|
||||
|
||||
StopEditingHelper::StopEditingHelper(database &db, StopModel *m,
|
||||
QSpinBox *outTrackSpin, QTimeEdit *arr, QTimeEdit *dep,
|
||||
QWidget *editor) :
|
||||
StopEditingHelper::StopEditingHelper(database &db, StopModel *m, QSpinBox *outTrackSpin,
|
||||
QTimeEdit *arr, QTimeEdit *dep, QWidget *editor) :
|
||||
QObject(editor),
|
||||
mEditor(editor),
|
||||
model(m),
|
||||
mTimerOutTrack(0)
|
||||
{
|
||||
stationsMatchModel = new StationsMatchModel(db, this);
|
||||
stationTrackMatchModel = new StationTracksMatchModel(db, this);
|
||||
stationsMatchModel = new StationsMatchModel(db, this);
|
||||
stationTrackMatchModel = new StationTracksMatchModel(db, this);
|
||||
stationOutGateMatchModel = new StationGatesMatchModel(db, this);
|
||||
|
||||
mStationEdit = new CustomCompletionLineEdit(stationsMatchModel, mEditor);
|
||||
mStationEdit = new CustomCompletionLineEdit(stationsMatchModel, mEditor);
|
||||
mStationEdit->setPlaceholderText(tr("Station name"));
|
||||
mStationEdit->setToolTip(mStationEdit->placeholderText());
|
||||
connect(mStationEdit, &CustomCompletionLineEdit::completionDone, this, &StopEditingHelper::onStationSelected);
|
||||
connect(mStationEdit, &CustomCompletionLineEdit::completionDone, this,
|
||||
&StopEditingHelper::onStationSelected);
|
||||
|
||||
mStTrackEdit = new CustomCompletionLineEdit(stationTrackMatchModel, mEditor);
|
||||
mStTrackEdit->setPlaceholderText(tr("Track"));
|
||||
mStTrackEdit->setToolTip(mStTrackEdit->placeholderText());
|
||||
connect(mStTrackEdit, &CustomCompletionLineEdit::completionDone, this, &StopEditingHelper::onTrackSelected);
|
||||
connect(mStTrackEdit, &CustomCompletionLineEdit::completionDone, this,
|
||||
&StopEditingHelper::onTrackSelected);
|
||||
|
||||
mOutGateEdit = new CustomCompletionLineEdit(stationOutGateMatchModel, mEditor);
|
||||
mOutGateEdit->setPlaceholderText(tr("Next segment"));
|
||||
mOutGateEdit->setToolTip(mOutGateEdit->placeholderText());
|
||||
connect(mOutGateEdit, &CustomCompletionLineEdit::indexSelected, this, &StopEditingHelper::onOutGateSelected);
|
||||
connect(mOutGateEdit, &CustomCompletionLineEdit::indexSelected, this,
|
||||
&StopEditingHelper::onOutGateSelected);
|
||||
|
||||
mOutGateTrackSpin = outTrackSpin;
|
||||
mOutGateTrackSpin->setMaximum(0);
|
||||
mOutGateTrackSpin->setToolTip(tr("Out Gate track"));
|
||||
connect(mOutGateTrackSpin, qOverload<int>(&QSpinBox::valueChanged), this, &StopEditingHelper::startOutTrackTimer);
|
||||
connect(mOutGateTrackSpin, &QSpinBox::editingFinished, this, &StopEditingHelper::checkOutGateTrack);
|
||||
connect(mOutGateTrackSpin, qOverload<int>(&QSpinBox::valueChanged), this,
|
||||
&StopEditingHelper::startOutTrackTimer);
|
||||
connect(mOutGateTrackSpin, &QSpinBox::editingFinished, this,
|
||||
&StopEditingHelper::checkOutGateTrack);
|
||||
|
||||
arrEdit = arr;
|
||||
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"));
|
||||
|
||||
connect(arrEdit, &QTimeEdit::timeChanged, this, &StopEditingHelper::arrivalChanged);
|
||||
|
@ -83,69 +87,70 @@ StopEditingHelper::~StopEditingHelper()
|
|||
|
||||
void StopEditingHelper::setStop(const StopItem &item, const StopItem &prev)
|
||||
{
|
||||
curStop = item;
|
||||
curStop = item;
|
||||
prevStop = prev;
|
||||
|
||||
//Update match models
|
||||
// Update match models
|
||||
stationsMatchModel->setFilter(prevStop.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;
|
||||
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)
|
||||
//This is to prevent contemporary stops that will break ORDER BY arrival queries
|
||||
// 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
|
||||
minArr = prevStop.departure.addSecs(60);
|
||||
|
||||
//Normal stop: at least 1 minute stop
|
||||
//Transit, Last: departure = arrival
|
||||
// Normal stop: at least 1 minute stop
|
||||
// Transit, Last: departure = arrival
|
||||
minDep = curStop.arrival;
|
||||
if(curStop.type == StopType::Normal)
|
||||
if (curStop.type == StopType::Normal)
|
||||
minDep = minDep.addSecs(60);
|
||||
|
||||
if(curStop.arrival < minArr)
|
||||
if (curStop.arrival < minArr)
|
||||
curStop.arrival = minArr;
|
||||
|
||||
if(curStop.departure < minDep)
|
||||
if (curStop.departure < 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->setVisible(curStop.type != StopType::First);
|
||||
|
||||
QString arrTootlip = tr("Arrival"); //No message by default
|
||||
if(curStop.type == StopType::Normal)
|
||||
QString arrTootlip = tr("Arrival"); // No message by default
|
||||
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."));
|
||||
}
|
||||
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->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);
|
||||
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);
|
||||
|
||||
//Update UI fields
|
||||
// Update UI fields
|
||||
mStationEdit->setData(curStop.stationId);
|
||||
mStTrackEdit->setData(curStop.trackId);
|
||||
mOutGateEdit->setData(curStop.toGate.gateId);
|
||||
updateGateTrackSpin(curStop.toGate);
|
||||
|
||||
//Set Arrival and Departure
|
||||
// Set Arrival and Departure
|
||||
arrEdit->blockSignals(true);
|
||||
arrEdit->setMinimumTime(minArr);
|
||||
arrEdit->setTime(curStop.arrival);
|
||||
|
@ -159,39 +164,41 @@ void StopEditingHelper::setStop(const StopItem &item, const StopItem &prev)
|
|||
|
||||
void StopEditingHelper::popupSegmentCombo()
|
||||
{
|
||||
//Look for all possible segments
|
||||
// Look for all possible segments
|
||||
stationOutGateMatchModel->autoSuggest(QString());
|
||||
|
||||
const int count = stationOutGateMatchModel->rowCount();
|
||||
if(count > 1 && !stationOutGateMatchModel->isEmptyRow(0)
|
||||
if (count > 1 && !stationOutGateMatchModel->isEmptyRow(0)
|
||||
&& (stationOutGateMatchModel->isEmptyRow(1) || stationOutGateMatchModel->isEllipsesRow(1)))
|
||||
{
|
||||
//Only 1 segment available, use it
|
||||
db_id newSegId = stationOutGateMatchModel->getSegmentIdAtRow(0);
|
||||
// Only 1 segment available, use it
|
||||
db_id newSegId = stationOutGateMatchModel->getSegmentIdAtRow(0);
|
||||
|
||||
db_id segOutGateId = 0;
|
||||
db_id segOutGateId = 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();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//We have multiple segments, let the user choose
|
||||
// We have multiple segments, let the user choose
|
||||
mOutGateEdit->showPopup();
|
||||
}
|
||||
|
||||
QString StopEditingHelper::getGateString(db_id gateId, bool reversed)
|
||||
{
|
||||
QString str = QLatin1String("<b>");
|
||||
if(gateId)
|
||||
if (gateId)
|
||||
{
|
||||
str += stationOutGateMatchModel->getName(gateId);
|
||||
if(reversed)
|
||||
if (reversed)
|
||||
str += tr(" (reversed)");
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
str += tr("Not set!");
|
||||
}
|
||||
str.append(QLatin1String("</b>"));
|
||||
|
@ -200,7 +207,7 @@ QString StopEditingHelper::getGateString(db_id gateId, bool reversed)
|
|||
|
||||
void StopEditingHelper::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if(e->timerId() == mTimerOutTrack)
|
||||
if (e->timerId() == mTimerOutTrack)
|
||||
{
|
||||
checkOutGateTrack();
|
||||
return;
|
||||
|
@ -213,32 +220,33 @@ void StopEditingHelper::onStationSelected()
|
|||
{
|
||||
db_id newStId = 0;
|
||||
QString tmp;
|
||||
if(!mStationEdit->getData(newStId, tmp))
|
||||
if (!mStationEdit->getData(newStId, tmp))
|
||||
return;
|
||||
|
||||
if(newStId == curStop.stationId)
|
||||
if (newStId == curStop.stationId)
|
||||
return;
|
||||
|
||||
curStop.stationId = newStId;
|
||||
|
||||
//Update track
|
||||
// Update track
|
||||
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))
|
||||
curStop.trackId = 0; //Could not find a track
|
||||
if (!model->trySelectTrackForStop(curStop))
|
||||
curStop.trackId = 0; // Could not find a track
|
||||
|
||||
mStTrackEdit->setData(curStop.trackId);
|
||||
}
|
||||
|
||||
//Update prev segment
|
||||
prevStop.nextSegment = StopItem::Segment{}; //Reset, will be reloaded by model
|
||||
// Update prev segment
|
||||
prevStop.nextSegment = StopItem::Segment{}; // Reset, will be reloaded by model
|
||||
|
||||
//Update next segment
|
||||
stationOutGateMatchModel->setFilter(curStop.stationId, true, prevStop.nextSegment.segmentId, true);
|
||||
mOutGateEdit->setData(0); //Reset, user must choose again
|
||||
// Update next segment
|
||||
stationOutGateMatchModel->setFilter(curStop.stationId, true, prevStop.nextSegment.segmentId,
|
||||
true);
|
||||
mOutGateEdit->setData(0); // Reset, user must choose again
|
||||
|
||||
curStop.nextSegment = StopItem::Segment{};
|
||||
|
||||
|
@ -249,19 +257,19 @@ void StopEditingHelper::onTrackSelected()
|
|||
{
|
||||
db_id newTrackId = 0;
|
||||
QString str;
|
||||
if(!mStTrackEdit->getData(newTrackId, str))
|
||||
if (!mStTrackEdit->getData(newTrackId, str))
|
||||
return;
|
||||
str.clear();
|
||||
|
||||
//Check if track is connected to gates
|
||||
if(!model->trySetTrackConnections(curStop, newTrackId, &str))
|
||||
// Check if track is connected to gates
|
||||
if (!model->trySetTrackConnections(curStop, newTrackId, &str))
|
||||
{
|
||||
//Show error to the user
|
||||
// Show error to the user
|
||||
bool stillSucceded = (curStop.trackId == newTrackId);
|
||||
QMessageBox::warning(mEditor, stillSucceded ? tr("Gate Warning") : tr("Track Error"), str);
|
||||
|
||||
if(!stillSucceded)
|
||||
mStTrackEdit->setData(curStop.trackId); //Reset to previous track
|
||||
if (!stillSucceded)
|
||||
mStTrackEdit->setData(curStop.trackId); // Reset to previous track
|
||||
}
|
||||
|
||||
emit stationTrackChosen();
|
||||
|
@ -271,25 +279,26 @@ void StopEditingHelper::onOutGateSelected(const QModelIndex &idx)
|
|||
{
|
||||
db_id newGateId = 0;
|
||||
QString gateSegmentName;
|
||||
if(!mOutGateEdit->getData(newGateId, gateSegmentName))
|
||||
if (!mOutGateEdit->getData(newGateId, gateSegmentName))
|
||||
return;
|
||||
|
||||
const db_id newSegId = stationOutGateMatchModel->getSegmentIdAtRow(idx.row());
|
||||
const db_id oldGateId = curStop.toGate.gateId;
|
||||
db_id segOutGateId = 0;
|
||||
const db_id newSegId = stationOutGateMatchModel->getSegmentIdAtRow(idx.row());
|
||||
const db_id oldGateId = curStop.toGate.gateId;
|
||||
db_id segOutGateId = 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);
|
||||
|
||||
//Success, close editor
|
||||
// Success, close editor
|
||||
emit nextSegmentChosen();
|
||||
}
|
||||
else
|
||||
{
|
||||
//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));
|
||||
// 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));
|
||||
mOutGateEdit->setData(oldGateId);
|
||||
}
|
||||
}
|
||||
|
@ -298,38 +307,40 @@ void StopEditingHelper::checkOutGateTrack()
|
|||
{
|
||||
stopOutTrackTimer();
|
||||
|
||||
if(!curStop.nextSegment.segmentId)
|
||||
return; //First we need to have a segment
|
||||
if (!curStop.nextSegment.segmentId)
|
||||
return; // First we need to have a segment
|
||||
|
||||
int trackNum = mOutGateTrackSpin->value();
|
||||
curStop.toGate.gateTrackNum = trackNum; //Trigger checking of railway segment connections
|
||||
int trackNum = mOutGateTrackSpin->value();
|
||||
curStop.toGate.gateTrackNum = trackNum; // Trigger checking of railway segment connections
|
||||
|
||||
db_id segOutGateId = 0;
|
||||
db_id suggestedTrackId = 0;
|
||||
if(model->trySelectNextSegment(curStop, curStop.nextSegment.segmentId, trackNum, 0, segOutGateId, suggestedTrackId))
|
||||
db_id segOutGateId = 0;
|
||||
db_id suggestedTrackId = 0;
|
||||
if (model->trySelectNextSegment(curStop, curStop.nextSegment.segmentId, trackNum, 0,
|
||||
segOutGateId, suggestedTrackId))
|
||||
{
|
||||
//Update gate track
|
||||
// Update gate track
|
||||
updateGateTrackSpin(curStop.toGate);
|
||||
|
||||
if(curStop.toGate.gateTrackNum != trackNum)
|
||||
if (curStop.toGate.gateTrackNum != trackNum)
|
||||
{
|
||||
//It wasn't possible to set requested track
|
||||
QMessageBox::warning(mEditor, tr("Stop Error"),
|
||||
tr("Requested gate out track <b>%1</b> is not connected to segment <b>%2</b>.<br>"
|
||||
"Out track <b>%3</b> was chosen instead.<br>"
|
||||
"Look segment track connection from Stations Manager for more information"
|
||||
" on available tracks.")
|
||||
.arg(trackNum)
|
||||
.arg(mOutGateEdit->text())
|
||||
.arg(curStop.toGate.gateTrackNum));
|
||||
// It wasn't possible to set requested track
|
||||
QMessageBox::warning(
|
||||
mEditor, tr("Stop Error"),
|
||||
tr("Requested gate out track <b>%1</b> is not connected to segment <b>%2</b>.<br>"
|
||||
"Out track <b>%3</b> was chosen instead.<br>"
|
||||
"Look segment track connection from Stations Manager for more information"
|
||||
" on available tracks.")
|
||||
.arg(trackNum)
|
||||
.arg(mOutGateEdit->text())
|
||||
.arg(curStop.toGate.gateTrackNum));
|
||||
}
|
||||
|
||||
//Success, close editor
|
||||
// Success, close editor
|
||||
emit nextSegmentChosen();
|
||||
}
|
||||
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!"));
|
||||
}
|
||||
}
|
||||
|
@ -337,26 +348,26 @@ void StopEditingHelper::checkOutGateTrack()
|
|||
void StopEditingHelper::arrivalChanged(const QTime &arrival)
|
||||
{
|
||||
bool shiftPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||
QTime dep = depEdit->time();
|
||||
if(!shiftPressed)
|
||||
QTime dep = depEdit->time();
|
||||
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);
|
||||
dep = dep.addMSecs(diff);
|
||||
dep = dep.addMSecs(diff);
|
||||
}
|
||||
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->setMinimumTime(minDep); //Set minimum before setting value
|
||||
depEdit->setMinimumTime(minDep); // Set minimum before setting value
|
||||
depEdit->setTime(dep);
|
||||
depEdit->blockSignals(false);
|
||||
|
||||
//Reset diff to 0 for next call
|
||||
curStop.arrival = arrival;
|
||||
// Reset diff to 0 for next call
|
||||
curStop.arrival = arrival;
|
||||
curStop.departure = dep;
|
||||
}
|
||||
|
||||
|
@ -367,16 +378,16 @@ void StopEditingHelper::departureChanged(const QTime &dep)
|
|||
|
||||
void StopEditingHelper::startOutTrackTimer()
|
||||
{
|
||||
//Give user a small time to scroll values in out gate track QSpinBox
|
||||
//This will skip eventual non available tracks (not connected)
|
||||
//On timeout check track and reset to old value if not available
|
||||
// Give user a small time to scroll values in out gate track QSpinBox
|
||||
// This will skip eventual non available tracks (not connected)
|
||||
// On timeout check track and reset to old value if not available
|
||||
stopOutTrackTimer();
|
||||
mTimerOutTrack = startTimer(700);
|
||||
}
|
||||
|
||||
void StopEditingHelper::stopOutTrackTimer()
|
||||
{
|
||||
if(mTimerOutTrack)
|
||||
if (mTimerOutTrack)
|
||||
{
|
||||
killTimer(mTimerOutTrack);
|
||||
mTimerOutTrack = 0;
|
||||
|
@ -388,12 +399,12 @@ void StopEditingHelper::updateGateTrackSpin(const StopItem::Gate &toGate)
|
|||
stopOutTrackTimer();
|
||||
|
||||
int outTrackCount = 0;
|
||||
if(toGate.gateId)
|
||||
if (toGate.gateId)
|
||||
outTrackCount = stationOutGateMatchModel->getGateTrackCount(toGate.gateId);
|
||||
|
||||
//Prevent trigger valueChanged() signal
|
||||
// Prevent trigger valueChanged() signal
|
||||
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->blockSignals(false);
|
||||
}
|
||||
|
|
|
@ -43,23 +43,37 @@ class StopEditingHelper : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StopEditingHelper(sqlite3pp::database &db, StopModel *m,
|
||||
QSpinBox *outTrackSpin, QTimeEdit *arr, QTimeEdit *dep,
|
||||
QWidget *editor = nullptr);
|
||||
StopEditingHelper(sqlite3pp::database &db, StopModel *m, QSpinBox *outTrackSpin, QTimeEdit *arr,
|
||||
QTimeEdit *dep, QWidget *editor = nullptr);
|
||||
~StopEditingHelper();
|
||||
|
||||
void setStop(const StopItem& item, const StopItem& prev);
|
||||
void setStop(const StopItem &item, const StopItem &prev);
|
||||
|
||||
void popupSegmentCombo();
|
||||
|
||||
QString getGateString(db_id gateId, bool reversed);
|
||||
|
||||
inline CustomCompletionLineEdit *getStationEdit() const { return mStationEdit; }
|
||||
inline CustomCompletionLineEdit *getStTrackEdit() const { return mStTrackEdit; }
|
||||
inline CustomCompletionLineEdit *getOutGateEdit() const { return mOutGateEdit; }
|
||||
inline CustomCompletionLineEdit *getStationEdit() const
|
||||
{
|
||||
return mStationEdit;
|
||||
}
|
||||
inline CustomCompletionLineEdit *getStTrackEdit() const
|
||||
{
|
||||
return mStTrackEdit;
|
||||
}
|
||||
inline CustomCompletionLineEdit *getOutGateEdit() const
|
||||
{
|
||||
return mOutGateEdit;
|
||||
}
|
||||
|
||||
inline const StopItem& getCurItem() const { return curStop; }
|
||||
inline const StopItem& getPrevItem() const { return prevStop; }
|
||||
inline const StopItem &getCurItem() const
|
||||
{
|
||||
return curStop;
|
||||
}
|
||||
inline const StopItem &getPrevItem() const
|
||||
{
|
||||
return prevStop;
|
||||
}
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *e) override;
|
||||
|
@ -82,7 +96,7 @@ public slots:
|
|||
void stopOutTrackTimer();
|
||||
|
||||
private:
|
||||
void updateGateTrackSpin(const StopItem::Gate& toGate);
|
||||
void updateGateTrackSpin(const StopItem::Gate &toGate);
|
||||
|
||||
private:
|
||||
QWidget *mEditor;
|
||||
|
|
|
@ -27,19 +27,17 @@
|
|||
#include <QSpinBox>
|
||||
#include <QGridLayout>
|
||||
|
||||
|
||||
StopEditor::StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent) :
|
||||
QFrame(parent),
|
||||
m_closeOnSegmentChosen(false)
|
||||
{
|
||||
mOutGateTrackSpin = new QSpinBox;
|
||||
arrEdit = new QTimeEdit;
|
||||
depEdit = new QTimeEdit;
|
||||
arrEdit = new QTimeEdit;
|
||||
depEdit = new QTimeEdit;
|
||||
|
||||
helper = new StopEditingHelper(db, m,
|
||||
mOutGateTrackSpin, arrEdit, depEdit,
|
||||
this);
|
||||
connect(helper, &StopEditingHelper::nextSegmentChosen, this, &StopEditor::onHelperSegmentChoosen);
|
||||
helper = new StopEditingHelper(db, m, mOutGateTrackSpin, arrEdit, depEdit, this);
|
||||
connect(helper, &StopEditingHelper::nextSegmentChosen, this,
|
||||
&StopEditor::onHelperSegmentChoosen);
|
||||
|
||||
#ifdef PRINT_DBG_MSG
|
||||
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 *mOutGateEdit = helper->getOutGateEdit();
|
||||
|
||||
lay = new QGridLayout(this);
|
||||
lay = new QGridLayout(this);
|
||||
lay->addWidget(mStationEdit, 0, 0);
|
||||
lay->addWidget(arrEdit, 0, 1);
|
||||
lay->addWidget(depEdit, 0, 2);
|
||||
|
@ -63,7 +61,8 @@ StopEditor::StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent) :
|
|||
setTabOrder(arrEdit, depEdit);
|
||||
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()
|
||||
|
@ -76,7 +75,7 @@ void StopEditor::setStop(const StopItem &item, const StopItem &prev)
|
|||
{
|
||||
helper->setStop(item, prev);
|
||||
|
||||
if(item.stationId == 0)
|
||||
if (item.stationId == 0)
|
||||
setFocusProxy(helper->getStationEdit());
|
||||
}
|
||||
|
||||
|
@ -97,21 +96,21 @@ void StopEditor::setCloseOnSegmentChosen(bool value)
|
|||
|
||||
void StopEditor::popupSegmentCombo()
|
||||
{
|
||||
//This code is used when adding a new stop.
|
||||
//When user clicks on 'AddHere' a new stop is added
|
||||
//but before editing it, user must choose the railway segment
|
||||
//that the job will take from former Last Stop.
|
||||
// This code is used when adding a new stop.
|
||||
// When user clicks on 'AddHere' a new stop is added
|
||||
// but before editing it, user must choose the railway segment
|
||||
// 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')
|
||||
|
||||
//1 - We popup lines combo from former last stop
|
||||
//2 - When user chooses a line we close the editor (emit lineChosen())
|
||||
//3 - We edit edit new Last Stop (EditNextItem)
|
||||
// 1 - We popup lines combo from former last stop
|
||||
// 2 - When user chooses a line we close the editor (emit lineChosen())
|
||||
// 3 - We edit edit new Last Stop (EditNextItem)
|
||||
setCloseOnSegmentChosen(true);
|
||||
helper->popupSegmentCombo();
|
||||
}
|
||||
|
||||
void StopEditor::onHelperSegmentChoosen()
|
||||
{
|
||||
//Forward signal and pass self instance
|
||||
// Forward signal and pass self instance
|
||||
emit nextSegmentChosen(this);
|
||||
}
|
||||
|
|
|
@ -49,16 +49,19 @@ public:
|
|||
StopEditor(sqlite3pp::database &db, StopModel *m, QWidget *parent = nullptr);
|
||||
~StopEditor();
|
||||
|
||||
void setStop(const StopItem& item, const StopItem& prev);
|
||||
void setStop(const StopItem &item, const StopItem &prev);
|
||||
|
||||
const StopItem& getCurItem() const;
|
||||
const StopItem& getPrevItem() const;
|
||||
const StopItem &getCurItem() const;
|
||||
const StopItem &getPrevItem() const;
|
||||
|
||||
/*!
|
||||
* \brief closeOnSegmentChosen
|
||||
* \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);
|
||||
|
||||
signals:
|
||||
|
|
|
@ -21,78 +21,74 @@
|
|||
|
||||
JobCrossingErrorMap::JobCrossingErrorMap()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void JobCrossingErrorMap::removeJob(db_id jobId)
|
||||
{
|
||||
auto job = map.find(jobId);
|
||||
if(job == map.end())
|
||||
return; //Not contained in map
|
||||
if (job == map.end())
|
||||
return; // Not contained in map
|
||||
|
||||
//Remove all errors referencing to us
|
||||
for(const JobCrossingErrorData& err : qAsConst(job->errors))
|
||||
// Remove all errors referencing to us
|
||||
for (const JobCrossingErrorData &err : qAsConst(job->errors))
|
||||
{
|
||||
auto otherJob = map.find(err.otherJob.jobId);
|
||||
if(otherJob == map.end())
|
||||
continue; //Maybe already remove, skip
|
||||
if (otherJob == map.end())
|
||||
continue; // Maybe already remove, skip
|
||||
|
||||
//Remove all errors regarding job in otherJob
|
||||
std::remove_if(otherJob->errors.begin(),
|
||||
otherJob->errors.end(),
|
||||
[jobId](const JobCrossingErrorData& otherErr) -> bool
|
||||
{
|
||||
return otherErr.otherJob.jobId == jobId;
|
||||
});
|
||||
// Remove all errors regarding job in otherJob
|
||||
std::remove_if(otherJob->errors.begin(), otherJob->errors.end(),
|
||||
[jobId](const JobCrossingErrorData &otherErr) -> bool
|
||||
{ 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);
|
||||
}
|
||||
}
|
||||
|
||||
//Remove job
|
||||
// Remove job
|
||||
map.erase(job);
|
||||
}
|
||||
|
||||
void JobCrossingErrorMap::renameJob(db_id newJobId, db_id oldJobId)
|
||||
{
|
||||
auto job = map.find(oldJobId);
|
||||
if(job == map.end())
|
||||
return; //Not contained in map
|
||||
if (job == map.end())
|
||||
return; // Not contained in map
|
||||
|
||||
//Uodate all errors referencing to us
|
||||
for(const JobCrossingErrorData& err : qAsConst(job->errors))
|
||||
// Uodate all errors referencing to us
|
||||
for (const JobCrossingErrorData &err : qAsConst(job->errors))
|
||||
{
|
||||
auto otherJob = map.find(err.otherJob.jobId);
|
||||
if(otherJob == map.end())
|
||||
continue; //Maybe already remove, skip
|
||||
if (otherJob == map.end())
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Update job
|
||||
auto errList = map.take(oldJobId);
|
||||
// Update job
|
||||
auto errList = map.take(oldJobId);
|
||||
errList.job.jobId = newJobId;
|
||||
map.insert(newJobId, errList);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//Then add new errors if not empty (already duplicated)
|
||||
if(!list.errors.isEmpty())
|
||||
// Then add new errors if not empty (already duplicated)
|
||||
if (!list.errors.isEmpty())
|
||||
map.insert(list.job.jobId, list);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,16 +22,16 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include <QMap>
|
||||
#include <QTime>
|
||||
# include <QMap>
|
||||
# include <QTime>
|
||||
|
||||
#include "utils/types.h"
|
||||
# include "utils/types.h"
|
||||
|
||||
struct JobCrossingErrorData
|
||||
{
|
||||
db_id jobId = 0;
|
||||
db_id jobId = 0;
|
||||
|
||||
db_id stopId = 0;
|
||||
db_id stopId = 0;
|
||||
db_id stationId = 0;
|
||||
|
||||
JobStopEntry otherJob;
|
||||
|
@ -44,7 +44,8 @@ struct JobCrossingErrorData
|
|||
enum Type
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -56,8 +57,14 @@ struct JobCrossingErrorList
|
|||
JobEntry job;
|
||||
QVector<JobCrossingErrorData> errors;
|
||||
|
||||
inline int childCount() const { return errors.size(); }
|
||||
inline const JobCrossingErrorData *ptrForRow(int row) const { return &errors.at(row); }
|
||||
inline int childCount() const
|
||||
{
|
||||
return errors.size();
|
||||
}
|
||||
inline const JobCrossingErrorData *ptrForRow(int row) const
|
||||
{
|
||||
return &errors.at(row);
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -74,11 +81,14 @@ public:
|
|||
|
||||
JobCrossingErrorMap();
|
||||
|
||||
inline int topLevelCount() const { return map.size(); }
|
||||
inline int topLevelCount() const
|
||||
{
|
||||
return map.size();
|
||||
}
|
||||
|
||||
inline const JobCrossingErrorList *getTopLevelAtRow(int row) const
|
||||
{
|
||||
if(row >= topLevelCount())
|
||||
if (row >= topLevelCount())
|
||||
return nullptr;
|
||||
return &(map.constBegin() + row).value();
|
||||
}
|
||||
|
@ -86,7 +96,7 @@ public:
|
|||
inline const JobCrossingErrorList *getParent(JobCrossingErrorData *child) const
|
||||
{
|
||||
auto it = map.constFind(child->jobId);
|
||||
if(it == map.constEnd())
|
||||
if (it == map.constEnd())
|
||||
return nullptr;
|
||||
return &it.value();
|
||||
}
|
||||
|
@ -94,7 +104,7 @@ public:
|
|||
inline int getParentRow(JobCrossingErrorData *child) const
|
||||
{
|
||||
auto it = map.constFind(child->jobId);
|
||||
if(it == map.constEnd())
|
||||
if (it == map.constEnd())
|
||||
return -1;
|
||||
return std::distance(map.constBegin(), it);
|
||||
}
|
||||
|
@ -103,7 +113,7 @@ public:
|
|||
|
||||
void renameJob(db_id newJobId, db_id oldJobId);
|
||||
|
||||
void merge(const ErrorMap& results);
|
||||
void merge(const ErrorMap &results);
|
||||
|
||||
public:
|
||||
ErrorMap map;
|
||||
|
|
|
@ -19,22 +19,22 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include "jobcrossingchecker.h"
|
||||
# include "jobcrossingchecker.h"
|
||||
|
||||
#include "jobcrossingtask.h"
|
||||
#include "jobcrossingmodel.h"
|
||||
# include "jobcrossingtask.h"
|
||||
# include "jobcrossingmodel.h"
|
||||
|
||||
#include "app/session.h"
|
||||
#include "viewmanager/viewmanager.h"
|
||||
# include "app/session.h"
|
||||
# include "viewmanager/viewmanager.h"
|
||||
|
||||
#include "utils/owningqpointer.h"
|
||||
#include <QMenu>
|
||||
# include "utils/owningqpointer.h"
|
||||
# include <QMenu>
|
||||
|
||||
JobCrossingChecker::JobCrossingChecker(sqlite3pp::database &db, QObject *parent) :
|
||||
IBackgroundChecker(db, parent),
|
||||
mDb(db)
|
||||
{
|
||||
eventType = int(JobCrossingResultEvent::_Type);
|
||||
eventType = int(JobCrossingResultEvent::_Type);
|
||||
errorsModel = new JobCrossingModel(this);
|
||||
|
||||
connect(Session, &MeetingSession::jobChanged, this, &JobCrossingChecker::onJobChanged);
|
||||
|
@ -51,36 +51,37 @@ void JobCrossingChecker::clearModel()
|
|||
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);
|
||||
auto item = model->getItem(idx);
|
||||
if(!item)
|
||||
auto item = model->getItem(idx);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
OwningQPointer<QMenu> menu = new QMenu(panel);
|
||||
|
||||
QAction *showInJobEditor = new QAction(tr("Show in Job Editor"), menu);
|
||||
QAction *showInGraph = new QAction(tr("Show in graph"), menu);
|
||||
QAction *showInJobEditor = new QAction(tr("Show in Job Editor"), menu);
|
||||
QAction *showInGraph = new QAction(tr("Show in graph"), menu);
|
||||
|
||||
menu->addAction(showInJobEditor);
|
||||
menu->addAction(showInGraph);
|
||||
|
||||
QAction *act = menu->exec(pos);
|
||||
if(act == showInJobEditor)
|
||||
if (act == showInJobEditor)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void JobCrossingChecker::sessionLoadedHandler()
|
||||
{
|
||||
if(AppSettings.getCheckCrossingWhenOpeningDB())
|
||||
if (AppSettings.getCheckCrossingWhenOpeningDB())
|
||||
startWorker();
|
||||
}
|
||||
|
||||
|
@ -92,8 +93,8 @@ IQuittableTask *JobCrossingChecker::createMainWorker()
|
|||
void JobCrossingChecker::setErrors(QEvent *e, bool merge)
|
||||
{
|
||||
auto model = static_cast<JobCrossingModel *>(errorsModel);
|
||||
auto ev = static_cast<JobCrossingResultEvent *>(e);
|
||||
if(merge)
|
||||
auto ev = static_cast<JobCrossingResultEvent *>(e);
|
||||
if (merge)
|
||||
model->mergeErrors(ev->results);
|
||||
else
|
||||
model->setErrors(ev->results);
|
||||
|
@ -104,8 +105,8 @@ void JobCrossingChecker::onJobChanged(db_id newJobId, db_id oldJobId)
|
|||
auto model = static_cast<JobCrossingModel *>(errorsModel);
|
||||
model->renameJob(oldJobId, newJobId);
|
||||
|
||||
//After renaming check job
|
||||
if(AppSettings.getCheckCrossingOnJobEdit())
|
||||
// After renaming check job
|
||||
if (AppSettings.getCheckCrossingOnJobEdit())
|
||||
startWorker();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include "backgroundmanager/ibackgroundchecker.h"
|
||||
# include "backgroundmanager/ibackgroundchecker.h"
|
||||
|
||||
#include "utils/types.h"
|
||||
# include "utils/types.h"
|
||||
|
||||
class JobCrossingChecker : public IBackgroundChecker
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ public:
|
|||
|
||||
QString getName() const 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;
|
||||
|
||||
|
|
|
@ -21,25 +21,23 @@
|
|||
|
||||
#include "utils/jobcategorystrings.h"
|
||||
|
||||
static const char* error_texts[] = {
|
||||
nullptr,
|
||||
QT_TRANSLATE_NOOP("JobErrors", "Job crosses another Job on same track."),
|
||||
QT_TRANSLATE_NOOP("JobErrors", "Job passes another Job on same track.")
|
||||
};
|
||||
static const char *error_texts[] = {
|
||||
nullptr, QT_TRANSLATE_NOOP("JobErrors", "Job crosses another Job on same track."),
|
||||
QT_TRANSLATE_NOOP("JobErrors", "Job passes another Job on same track.")};
|
||||
|
||||
class 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
|
||||
{
|
||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
|
@ -63,11 +61,11 @@ QVariant JobCrossingModel::headerData(int section, Qt::Orientation orientation,
|
|||
|
||||
QVariant JobCrossingModel::data(const QModelIndex &idx, int role) const
|
||||
{
|
||||
if(!idx.isValid() || role != Qt::DisplayRole)
|
||||
if (!idx.isValid() || role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
const JobCrossingErrorData *item = getItem(idx);
|
||||
if(item)
|
||||
if (item)
|
||||
{
|
||||
switch (idx.column())
|
||||
{
|
||||
|
@ -87,8 +85,8 @@ QVariant JobCrossingModel::data(const QModelIndex &idx, int role) const
|
|||
}
|
||||
else
|
||||
{
|
||||
//Caption
|
||||
if(idx.row() >= m_data.topLevelCount() || idx.column() != 0)
|
||||
// Caption
|
||||
if (idx.row() >= m_data.topLevelCount() || idx.column() != 0)
|
||||
return QVariant();
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -22,14 +22,15 @@
|
|||
|
||||
#ifdef ENABLE_BACKGROUND_MANAGER
|
||||
|
||||
#include "utils/singledepthtreemodelhelper.h"
|
||||
# include "utils/singledepthtreemodelhelper.h"
|
||||
|
||||
#include "job_crossing_data.h"
|
||||
# include "job_crossing_data.h"
|
||||
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -48,7 +49,8 @@ public:
|
|||
JobCrossingModel(QObject *parent = nullptr);
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -62,7 +64,7 @@ public:
|
|||
|
||||
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
|
||||
|
|
|
@ -22,41 +22,42 @@
|
|||
#include <sqlite3pp/sqlite3pp.h>
|
||||
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.otherJob.stopId = job.get<db_id>(1);
|
||||
err.jobId = job.get<db_id>(2);
|
||||
outCat = JobCategory(job.get<int>(3));
|
||||
err.otherJob.jobId = job.get<db_id>(4);
|
||||
err.stopId = job.get<db_id>(0);
|
||||
err.otherJob.stopId = job.get<db_id>(1);
|
||||
err.jobId = job.get<db_id>(2);
|
||||
outCat = JobCategory(job.get<int>(3));
|
||||
err.otherJob.jobId = job.get<db_id>(4);
|
||||
err.otherJob.category = JobCategory(job.get<int>(5));
|
||||
err.departure = job.get<QTime>(6);
|
||||
err.arrival = job.get<QTime>(7);
|
||||
err.otherDep = job.get<QTime>(8);
|
||||
err.otherArr = job.get<QTime>(9);
|
||||
bool passing = job.get<int>(10) == 1;
|
||||
err.stationId = job.get<db_id>(11);
|
||||
err.stationName = job.get<QString>(12);
|
||||
err.departure = job.get<QTime>(6);
|
||||
err.arrival = job.get<QTime>(7);
|
||||
err.otherDep = job.get<QTime>(8);
|
||||
err.otherArr = job.get<QTime>(9);
|
||||
bool passing = job.get<int>(10) == 1;
|
||||
err.stationId = job.get<db_id>(11);
|
||||
err.stationName = job.get<QString>(12);
|
||||
|
||||
if(passing)
|
||||
if (passing)
|
||||
{
|
||||
//In passings:
|
||||
//job A starts before B but gets passed and ends after B
|
||||
//job B starts after A but ends before
|
||||
//B travel period is contained in A travel period
|
||||
// In passings:
|
||||
// job A starts before B but gets passed and ends after B
|
||||
// job B starts after A but ends before
|
||||
// B travel period is contained in A travel period
|
||||
|
||||
//We need stricter checking of time, one travel must be contained in the other
|
||||
if(err.departure < err.otherDep && err.arrival < err.otherArr)
|
||||
return false; //A travels before B, no passing
|
||||
if(err.departure > err.otherDep && err.arrival > err.otherArr)
|
||||
return false; //A travels after B, no passing
|
||||
// We need stricter checking of time, one travel must be contained in the other
|
||||
if (err.departure < err.otherDep && err.arrival < err.otherArr)
|
||||
return false; // A travels before B, no passing
|
||||
if (err.departure > err.otherDep && err.arrival > err.otherArr)
|
||||
return false; // A travels after B, no passing
|
||||
}
|
||||
|
||||
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(outCat, err.otherJob.category);
|
||||
qSwap(err.stopId, err.otherJob.stopId);
|
||||
|
@ -67,43 +68,45 @@ inline bool fillCrossingErrorData(query::rows& job, JobCrossingErrorData& err, b
|
|||
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),
|
||||
results(data),
|
||||
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),
|
||||
mDb(db),
|
||||
jobsToCheck(jobs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void JobCrossingTask::run()
|
||||
{
|
||||
//TODO: allow checking a single job
|
||||
// TODO: allow checking a single job
|
||||
|
||||
//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,"
|
||||
"s1.departure, MIN(s1_next.arrival),"
|
||||
"s2.departure, MIN(s2_next.arrival),"
|
||||
"g1.gate_id=g2.gate_id," //1 = passing, 0 = crossing (opposite direction)
|
||||
"s1.station_id, stations.name"
|
||||
" FROM stops s1"
|
||||
" JOIN stops s1_next ON s1_next.job_id=s1.job_id AND s1_next.arrival>s1.arrival"
|
||||
" JOIN stops s2 ON s2.next_segment_conn_id=s1.next_segment_conn_id AND s2.id<>s1.id"
|
||||
" JOIN stops s2_next ON s2_next.job_id=s2.job_id AND s2_next.arrival>s2.arrival"
|
||||
" JOIN jobs j1 ON j1.id=s1.job_id"
|
||||
" JOIN jobs j2 ON j2.id=s2.job_id"
|
||||
" JOIN station_gate_connections g1 ON g1.id=s1.out_gate_conn"
|
||||
" JOIN station_gate_connections g2 ON g2.id=s2.out_gate_conn"
|
||||
" JOIN stations ON stations.id=s1.station_id"
|
||||
" GROUP BY s1.id,s2.id"
|
||||
" HAVING s1.departure<=s2_next.arrival AND s1_next.arrival>=s2.departure");
|
||||
// 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,"
|
||||
"s1.departure, MIN(s1_next.arrival),"
|
||||
"s2.departure, MIN(s2_next.arrival),"
|
||||
"g1.gate_id=g2.gate_id," // 1 = passing, 0 = crossing (opposite direction)
|
||||
"s1.station_id, stations.name"
|
||||
" FROM stops s1"
|
||||
" JOIN stops s1_next ON s1_next.job_id=s1.job_id AND s1_next.arrival>s1.arrival"
|
||||
" JOIN stops s2 ON s2.next_segment_conn_id=s1.next_segment_conn_id AND s2.id<>s1.id"
|
||||
" JOIN stops s2_next ON s2_next.job_id=s2.job_id AND s2_next.arrival>s2.arrival"
|
||||
" JOIN jobs j1 ON j1.id=s1.job_id"
|
||||
" JOIN jobs j2 ON j2.id=s2.job_id"
|
||||
" JOIN station_gate_connections g1 ON g1.id=s1.out_gate_conn"
|
||||
" JOIN station_gate_connections g2 ON g2.id=s2.out_gate_conn"
|
||||
" JOIN stations ON stations.id=s1.station_id"
|
||||
" GROUP BY s1.id,s2.id"
|
||||
" HAVING s1.departure<=s2_next.arrival AND s1_next.arrival>=s2.departure");
|
||||
|
||||
QMap<db_id, JobCrossingErrorList> errorMap;
|
||||
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;
|
||||
JobCategory category = JobCategory::NCategories;
|
||||
|
||||
if(!fillCrossingErrorData(job, err, true, category))
|
||||
if (!fillCrossingErrorData(job, err, true, category))
|
||||
continue;
|
||||
|
||||
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;
|
||||
list.job.jobId = err.jobId;
|
||||
list.job.jobId = err.jobId;
|
||||
list.job.category = category;
|
||||
|
||||
it = errMap.insert(list.job.jobId, list);
|
||||
it = errMap.insert(list.job.jobId, list);
|
||||
}
|
||||
|
||||
it.value().errors.append(err);
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
namespace sqlite3pp {
|
||||
class database;
|
||||
class query;
|
||||
}
|
||||
} // namespace sqlite3pp
|
||||
|
||||
class JobCrossingTask;
|
||||
|
||||
|
@ -40,7 +40,8 @@ class JobCrossingResultEvent : public GenericTaskEvent
|
|||
public:
|
||||
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;
|
||||
bool mergeErrors;
|
||||
|
@ -49,11 +50,11 @@ public:
|
|||
class JobCrossingTask : public IQuittableTask
|
||||
{
|
||||
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 checkCrossAndPassSegments(JobCrossingErrorMap::ErrorMap& errMap, sqlite3pp::query &q);
|
||||
void checkCrossAndPassSegments(JobCrossingErrorMap::ErrorMap &errMap, sqlite3pp::query &q);
|
||||
|
||||
private:
|
||||
sqlite3pp::database &mDb;
|
||||
|
|
|
@ -45,15 +45,17 @@ JobsManager::JobsManager(QWidget *parent) :
|
|||
QVBoxLayout *l = new QVBoxLayout(this);
|
||||
setMinimumSize(750, 300);
|
||||
|
||||
QToolBar *toolBar = new QToolBar(this);
|
||||
QToolBar *toolBar = new QToolBar(this);
|
||||
QAction *actNewJob = toolBar->addAction(tr("New Job"), this, &JobsManager::onNewJob);
|
||||
actRemoveJob = toolBar->addAction(tr("Remove"), this, &JobsManager::onRemove);
|
||||
actNewJobSamePath = toolBar->addAction(tr("New Same Path"), this, &JobsManager::onNewJobSamePath);
|
||||
actRemoveJob = toolBar->addAction(tr("Remove"), this, &JobsManager::onRemove);
|
||||
actNewJobSamePath =
|
||||
toolBar->addAction(tr("New Same Path"), this, &JobsManager::onNewJobSamePath);
|
||||
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);
|
||||
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);
|
||||
|
||||
view = new QTableView;
|
||||
|
@ -61,7 +63,7 @@ JobsManager::JobsManager(QWidget *parent) :
|
|||
connect(view, &QTableView::doubleClicked, this, &JobsManager::editJobAtRow);
|
||||
l->addWidget(view);
|
||||
|
||||
//Custom sorting and filtering
|
||||
// Custom sorting and filtering
|
||||
FilterHeaderView *header = new FilterHeaderView(view);
|
||||
header->installOnTable(view);
|
||||
|
||||
|
@ -72,12 +74,13 @@ JobsManager::JobsManager(QWidget *parent) :
|
|||
l->addWidget(ps);
|
||||
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);
|
||||
|
||||
jobsModel->refreshData();
|
||||
|
||||
//Action Tooltips
|
||||
// Action Tooltips
|
||||
actNewJob->setToolTip(tr("Create new Job and open Job Editor"));
|
||||
actRemoveJob->setToolTip(tr("Delete selected Job"));
|
||||
actNewJobSamePath->setToolTip(tr("Create new Job with same path of selected one"));
|
||||
|
@ -89,10 +92,10 @@ JobsManager::JobsManager(QWidget *parent) :
|
|||
setWindowTitle("Jobs Manager");
|
||||
}
|
||||
|
||||
void JobsManager::editJobAtRow(const QModelIndex& idx)
|
||||
void JobsManager::editJobAtRow(const QModelIndex &idx)
|
||||
{
|
||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||
if(!jobId)
|
||||
if (!jobId)
|
||||
return;
|
||||
Session->getViewManager()->requestJobEditor(jobId);
|
||||
}
|
||||
|
@ -105,64 +108,65 @@ void JobsManager::onNewJob()
|
|||
void JobsManager::onRemove()
|
||||
{
|
||||
QModelIndex idx = view->currentIndex();
|
||||
if(!idx.isValid())
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||
JobCategory jobCat = jobsModel->getShiftAnCatAtRow(idx.row()).second;
|
||||
QString jobName = JobCategoryName::jobName(jobId, jobCat);
|
||||
QString jobName = JobCategoryName::jobName(jobId, jobCat);
|
||||
|
||||
int ret = QMessageBox::question(this,
|
||||
tr("Job deletion"),
|
||||
tr("Are you sure to delete job %1?").arg(jobName),
|
||||
QMessageBox::Yes | QMessageBox::Cancel);
|
||||
if(ret == QMessageBox::Yes)
|
||||
int ret = QMessageBox::question(this, tr("Job deletion"),
|
||||
tr("Are you sure to delete job %1?").arg(jobName),
|
||||
QMessageBox::Yes | QMessageBox::Cancel);
|
||||
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();
|
||||
//ERRORMSG: message box or statusbar
|
||||
qWarning() << "Error while deleting job:" << jobId << "from JobManager"
|
||||
<< Session->m_Db.error_msg();
|
||||
// ERRORMSG: message box or statusbar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JobsManager::onRemoveAllJobs()
|
||||
{
|
||||
int ret = QMessageBox::question(this, tr("Delete all jobs?"),
|
||||
tr("Are you really sure you want to delete all jobs from this session?"));
|
||||
if(ret == QMessageBox::Yes)
|
||||
int ret = QMessageBox::question(
|
||||
this, tr("Delete all jobs?"),
|
||||
tr("Are you really sure you want to delete all jobs from this session?"));
|
||||
if (ret == QMessageBox::Yes)
|
||||
JobsHelper::removeAllJobs(Session->m_Db);
|
||||
}
|
||||
|
||||
void JobsManager::onNewJobSamePath()
|
||||
{
|
||||
QModelIndex idx = view->currentIndex();
|
||||
if(!idx.isValid())
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||
if(!jobId)
|
||||
if (!jobId)
|
||||
return;
|
||||
JobCategory jobCat = jobsModel->getShiftAnCatAtRow(idx.row()).second;
|
||||
auto times = jobsModel->getOrigAndDestTimeAtRow(idx.row());
|
||||
JobCategory jobCat = jobsModel->getShiftAnCatAtRow(idx.row()).second;
|
||||
auto times = jobsModel->getOrigAndDestTimeAtRow(idx.row());
|
||||
|
||||
OwningQPointer<NewJobSamePathDlg> dlg = new NewJobSamePathDlg(this);
|
||||
dlg->setSourceJob(jobId, jobCat, times.first, times.second);
|
||||
|
||||
if(dlg->exec() != QDialog::Accepted || !dlg)
|
||||
if (dlg->exec() != QDialog::Accepted || !dlg)
|
||||
return;
|
||||
|
||||
const QTime newStart = dlg->getNewStartTime();
|
||||
const int secsOffset = times.first.secsTo(newStart);
|
||||
|
||||
db_id newJobId = 0;
|
||||
if(!JobsHelper::createNewJob(Session->m_Db, newJobId, jobCat))
|
||||
db_id newJobId = 0;
|
||||
if (!JobsHelper::createNewJob(Session->m_Db, newJobId, jobCat))
|
||||
return;
|
||||
|
||||
JobsHelper::copyStops(Session->m_Db, jobId, newJobId, secsOffset,
|
||||
dlg->shouldCopyRs(), dlg->shouldReversePath());
|
||||
JobsHelper::copyStops(Session->m_Db, jobId, newJobId, secsOffset, dlg->shouldCopyRs(),
|
||||
dlg->shouldReversePath());
|
||||
|
||||
//Let user edit newly created job
|
||||
// Let user edit newly created job
|
||||
Session->getViewManager()->requestJobEditor(newJobId);
|
||||
}
|
||||
|
||||
|
@ -174,16 +178,16 @@ void JobsManager::onEditJob()
|
|||
void JobsManager::onShowJobGraph()
|
||||
{
|
||||
QModelIndex idx = view->currentIndex();
|
||||
if(!idx.isValid())
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
db_id jobId = jobsModel->getIdAtRow(idx.row());
|
||||
if(!jobId)
|
||||
if (!jobId)
|
||||
return;
|
||||
|
||||
Session->getViewManager()->requestJobSelection(jobId, true, true);
|
||||
|
||||
//Minimize JobsManager to make graph visible
|
||||
// Minimize JobsManager to make graph visible
|
||||
showMinimized();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ JobListModel::JobListModel(sqlite3pp::database &db, QObject *parent) :
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -84,16 +84,16 @@ QVariant JobListModel::data(const QModelIndex &idx, int role) const
|
|||
if (!idx.isValid() || row >= curItemCount || idx.column() >= NCols)
|
||||
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);
|
||||
|
||||
//Temporarily return null
|
||||
// Temporarily return null
|
||||
return role == Qt::DisplayRole ? QVariant("...") : QVariant();
|
||||
}
|
||||
|
||||
const JobItem& item = cache.at(row - cacheFirstRow);
|
||||
const JobItem &item = cache.at(row - cacheFirstRow);
|
||||
|
||||
switch (role)
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ QVariant JobListModel::data(const QModelIndex &idx, int role) const
|
|||
}
|
||||
case Qt::TextAlignmentRole:
|
||||
{
|
||||
if(idx.column() == IdCol)
|
||||
if (idx.column() == IdCol)
|
||||
{
|
||||
return Qt::AlignVCenter + Qt::AlignRight;
|
||||
}
|
||||
|
@ -135,14 +135,14 @@ QVariant JobListModel::data(const QModelIndex &idx, int role) const
|
|||
|
||||
void JobListModel::setSortingColumn(int col)
|
||||
{
|
||||
if(sortColumn == col || col == OriginSt || col == DestinationSt || col >= NCols)
|
||||
if (sortColumn == col || col == OriginSt || col == DestinationSt || col >= NCols)
|
||||
return;
|
||||
|
||||
clearCache();
|
||||
sortColumn = col;
|
||||
sortColumn = col;
|
||||
|
||||
QModelIndex first = index(0, 0);
|
||||
QModelIndex last = index(curItemCount - 1, NCols - 1);
|
||||
QModelIndex last = index(curItemCount - 1, NCols - 1);
|
||||
emit dataChanged(first, last);
|
||||
}
|
||||
|
||||
|
@ -167,8 +167,8 @@ bool JobListModel::setFilterAtCol(int col, const QString &str)
|
|||
{
|
||||
case IdCol:
|
||||
{
|
||||
if(isNull)
|
||||
return false; //Cannot have NULL Job ID
|
||||
if (isNull)
|
||||
return false; // Cannot have NULL Job ID
|
||||
m_jobIdFilter = str;
|
||||
break;
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ bool JobListModel::setFilterAtCol(int col, const QString &str)
|
|||
|
||||
void JobListModel::onJobAddedOrRemoved()
|
||||
{
|
||||
refreshData(); //Recalc row count
|
||||
refreshData(); // Recalc row count
|
||||
}
|
||||
|
||||
qint64 JobListModel::recalcTotalItemCount()
|
||||
|
@ -203,7 +203,7 @@ qint64 JobListModel::recalcTotalItemCount()
|
|||
void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool fullData)
|
||||
{
|
||||
QByteArray sql;
|
||||
if(fullData)
|
||||
if (fullData)
|
||||
{
|
||||
sql = "SELECT jobs.id, jobs.category, jobs.shift_id, jobshifts.name,"
|
||||
"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";
|
||||
}
|
||||
|
||||
//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);
|
||||
if(fullData || (!shiftFilterIsNull && !m_shiftFilter.isEmpty()))
|
||||
if (fullData || (!shiftFilterIsNull && !m_shiftFilter.isEmpty()))
|
||||
sql += " LEFT JOIN jobshifts ON jobshifts.id=jobs.shift_id";
|
||||
|
||||
bool whereClauseAdded = false;
|
||||
|
||||
if(!m_jobIdFilter.isEmpty())
|
||||
if (!m_jobIdFilter.isEmpty())
|
||||
{
|
||||
sql.append(" WHERE jobs.id LIKE ?3");
|
||||
whereClauseAdded = true;
|
||||
}
|
||||
|
||||
if(!m_shiftFilter.isEmpty())
|
||||
if (!m_shiftFilter.isEmpty())
|
||||
{
|
||||
if(whereClauseAdded)
|
||||
if (whereClauseAdded)
|
||||
sql.append(" AND ");
|
||||
else
|
||||
sql.append(" WHERE ");
|
||||
|
||||
if(shiftFilterIsNull)
|
||||
if (shiftFilterIsNull)
|
||||
sql.append("jobs.shift_id IS NULL");
|
||||
else
|
||||
sql.append("jobshifts.name LIKE ?4");
|
||||
}
|
||||
|
||||
if(fullData)
|
||||
if (fullData)
|
||||
{
|
||||
//Group by Job
|
||||
// Group by Job
|
||||
sql.append(" GROUP BY jobs.id");
|
||||
|
||||
//Apply sorting
|
||||
// Apply sorting
|
||||
const char *sortColExpr = nullptr;
|
||||
switch (sortCol)
|
||||
{
|
||||
case IdCol:
|
||||
{
|
||||
sortColExpr = "jobs.id"; //Order by 1 column, no where clause
|
||||
sortColExpr = "jobs.id"; // Order by 1 column, no where clause
|
||||
break;
|
||||
}
|
||||
case Category:
|
||||
|
@ -282,23 +282,23 @@ void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool
|
|||
sql += sortColExpr;
|
||||
|
||||
sql += " LIMIT ?1";
|
||||
if(offset)
|
||||
if (offset)
|
||||
sql += " OFFSET ?2";
|
||||
}
|
||||
|
||||
q.prepare(sql);
|
||||
|
||||
if(fullData)
|
||||
if (fullData)
|
||||
{
|
||||
//Apply offset and batch size
|
||||
// Apply offset and batch size
|
||||
q.bind(1, BatchSize);
|
||||
if(offset)
|
||||
if (offset)
|
||||
q.bind(2, offset);
|
||||
}
|
||||
|
||||
//Apply filters
|
||||
// Apply filters
|
||||
QByteArray jobFilter;
|
||||
if(!m_jobIdFilter.isEmpty())
|
||||
if (!m_jobIdFilter.isEmpty())
|
||||
{
|
||||
jobFilter.reserve(m_jobIdFilter.size() + 2);
|
||||
jobFilter.append('%');
|
||||
|
@ -308,7 +308,7 @@ void JobListModel::buildQuery(sqlite3pp::query &q, int sortCol, int offset, bool
|
|||
}
|
||||
|
||||
QByteArray shiftFilter;
|
||||
if(!m_shiftFilter.isEmpty() && !shiftFilterIsNull)
|
||||
if (!m_shiftFilter.isEmpty() && !shiftFilterIsNull)
|
||||
{
|
||||
shiftFilter.reserve(m_shiftFilter.size() + 2);
|
||||
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);
|
||||
|
||||
|
@ -331,29 +331,29 @@ void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const Q
|
|||
|
||||
QVector<JobItem> vec(BatchSize);
|
||||
|
||||
//QString are implicitly shared, use QHash to temporary store them instead
|
||||
//of creating new ones for each JobItem
|
||||
// QString are implicitly shared, use QHash to temporary store them instead
|
||||
// of creating new ones for each JobItem
|
||||
QHash<db_id, QString> shiftHash;
|
||||
QHash<db_id, QString> stationHash;
|
||||
|
||||
auto it = q.begin();
|
||||
const auto end = q.end();
|
||||
auto it = q.begin();
|
||||
const auto end = q.end();
|
||||
|
||||
int i = 0;
|
||||
int i = 0;
|
||||
const int increment = 1;
|
||||
|
||||
for(; it != end; ++it)
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
auto r = *it;
|
||||
auto r = *it;
|
||||
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.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);
|
||||
if(shift == shiftHash.constEnd())
|
||||
if (shift == shiftHash.constEnd())
|
||||
{
|
||||
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.originStId = r.get<db_id>(5);
|
||||
item.destTime = r.get<QTime>(6);
|
||||
item.destStId = r.get<db_id>(7);
|
||||
item.destTime = r.get<QTime>(6);
|
||||
item.destStId = r.get<db_id>(7);
|
||||
|
||||
if(item.originStId)
|
||||
if (item.originStId)
|
||||
{
|
||||
auto st = stationHash.constFind(item.originStId);
|
||||
if(st == stationHash.constEnd())
|
||||
if (st == stationHash.constEnd())
|
||||
{
|
||||
q_stationName.bind(1, item.originStId);
|
||||
q_stationName.step();
|
||||
|
@ -378,10 +378,10 @@ void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const Q
|
|||
item.origStName = st.value();
|
||||
}
|
||||
|
||||
if(item.destStId)
|
||||
if (item.destStId)
|
||||
{
|
||||
auto st = stationHash.constFind(item.destStId);
|
||||
if(st == stationHash.constEnd())
|
||||
if (st == stationHash.constEnd())
|
||||
{
|
||||
q_stationName.bind(1, item.destStId);
|
||||
q_stationName.step();
|
||||
|
@ -394,7 +394,7 @@ void JobListModel::internalFetch(int first, int sortCol, int /*valRow*/, const Q
|
|||
i += increment;
|
||||
}
|
||||
|
||||
if(i < BatchSize)
|
||||
if (i < BatchSize)
|
||||
vec.remove(i, BatchSize - i);
|
||||
|
||||
postResult(vec, first);
|
||||
|
|
|
@ -48,9 +48,13 @@ class JobListModel : public IPagedItemModelImpl<JobListModel, JobListModelItem>
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum { BatchSize = 100 };
|
||||
enum
|
||||
{
|
||||
BatchSize = 100
|
||||
};
|
||||
|
||||
enum Columns {
|
||||
enum Columns
|
||||
{
|
||||
IdCol = 0,
|
||||
Category,
|
||||
ShiftCol,
|
||||
|
@ -69,7 +73,8 @@ public:
|
|||
// QAbstractTableModel
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -77,35 +82,35 @@ public:
|
|||
|
||||
virtual void setSortingColumn(int col) override;
|
||||
|
||||
//Filter
|
||||
// Filter
|
||||
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
|
||||
inline db_id getIdAtRow(int row) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
inline QPair<db_id, JobCategory> getShiftAnCatAtRow(int row) const
|
||||
{
|
||||
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};
|
||||
}
|
||||
|
||||
inline QPair<QTime, QTime> getOrigAndDestTimeAtRow(int row) const
|
||||
{
|
||||
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};
|
||||
}
|
||||
|
||||
|
|
|
@ -38,11 +38,11 @@ JobMatchModel::JobMatchModel(database &db, QObject *parent) :
|
|||
|
||||
int JobMatchModel::columnCount(const QModelIndex &p) const
|
||||
{
|
||||
if(p.isValid())
|
||||
if (p.isValid())
|
||||
return 0;
|
||||
|
||||
if(!m_stopStationId)
|
||||
return NCols - 1; //Hide stop arrival if no station filter is set
|
||||
if (!m_stopStationId)
|
||||
return NCols - 1; // Hide stop arrival if no station filter is set
|
||||
return NCols;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
|||
{
|
||||
case JobCategoryCol:
|
||||
{
|
||||
if(isEllipsesRow(idx.row()))
|
||||
if (isEllipsesRow(idx.row()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
|||
}
|
||||
case JobNumber:
|
||||
{
|
||||
if(isEllipsesRow(idx.row()))
|
||||
if (isEllipsesRow(idx.row()))
|
||||
{
|
||||
return ellipsesString;
|
||||
}
|
||||
|
@ -75,8 +75,8 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
|||
}
|
||||
case StopArrivalCol:
|
||||
{
|
||||
if(!m_stopStationId)
|
||||
break; //Do not show stop arrival if not filtering by station
|
||||
if (!m_stopStationId)
|
||||
break; // Do not show stop arrival if not filtering by station
|
||||
|
||||
return items[idx.row()].stopArrival;
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
|||
}
|
||||
case Qt::ForegroundRole:
|
||||
{
|
||||
if(isEllipsesRow(idx.row()))
|
||||
if (isEllipsesRow(idx.row()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
|
|||
void JobMatchModel::autoSuggest(const QString &text)
|
||||
{
|
||||
mQuery.clear();
|
||||
if(!text.isEmpty())
|
||||
if (!text.isEmpty())
|
||||
{
|
||||
mQuery.reserve(text.size() + 2);
|
||||
mQuery.append('%');
|
||||
|
@ -137,36 +137,36 @@ void JobMatchModel::autoSuggest(const QString &text)
|
|||
|
||||
void JobMatchModel::refreshData()
|
||||
{
|
||||
if(!mDb.db())
|
||||
if (!mDb.db())
|
||||
return;
|
||||
|
||||
beginResetModel();
|
||||
|
||||
char emptyQuery = '%';
|
||||
|
||||
if(mQuery.isEmpty())
|
||||
if (mQuery.isEmpty())
|
||||
sqlite3_bind_text(q_getMatches.stmt(), 1, &emptyQuery, 1, SQLITE_STATIC);
|
||||
else
|
||||
sqlite3_bind_text(q_getMatches.stmt(), 1, mQuery, mQuery.size(), SQLITE_STATIC);
|
||||
|
||||
if(m_exceptJobId)
|
||||
if (m_exceptJobId)
|
||||
q_getMatches.bind(2, m_exceptJobId);
|
||||
|
||||
if(m_stopStationId)
|
||||
if (m_stopStationId)
|
||||
{
|
||||
q_getMatches.bind(3, m_stopStationId);
|
||||
if(!m_maxStopArrival.isNull())
|
||||
if (!m_maxStopArrival.isNull())
|
||||
q_getMatches.bind(4, m_maxStopArrival);
|
||||
}
|
||||
|
||||
auto end = q_getMatches.end();
|
||||
auto it = q_getMatches.begin();
|
||||
int i = 0;
|
||||
for(; i < MaxMatchItems && it != end; i++)
|
||||
auto it = q_getMatches.begin();
|
||||
int i = 0;
|
||||
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));
|
||||
if(m_stopStationId)
|
||||
if (m_stopStationId)
|
||||
{
|
||||
items[i].stop.stopId = (*it).get<db_id>(2);
|
||||
items[i].stopArrival = (*it).get<QTime>(3);
|
||||
|
@ -176,13 +176,13 @@ void JobMatchModel::refreshData()
|
|||
}
|
||||
|
||||
size = i;
|
||||
if(hasEmptyRow)
|
||||
size++; //Items + Empty, add 1 row
|
||||
if (hasEmptyRow)
|
||||
size++; // Items + Empty, add 1 row
|
||||
|
||||
if(it != end)
|
||||
if (it != end)
|
||||
{
|
||||
//There would be still rows, show Ellipses
|
||||
size++; //Items + Empty + Ellispses
|
||||
// There would be still rows, show Ellipses
|
||||
size++; // Items + Empty + Ellispses
|
||||
}
|
||||
|
||||
q_getMatches.reset();
|
||||
|
@ -193,12 +193,12 @@ void JobMatchModel::refreshData()
|
|||
|
||||
QString JobMatchModel::getName(db_id jobId) const
|
||||
{
|
||||
if(!mDb.db())
|
||||
if (!mDb.db())
|
||||
return QString();
|
||||
|
||||
query q(mDb, "SELECT category FROM jobs WHERE id=?");
|
||||
q.bind(1, jobId);
|
||||
if(q.step() != SQLITE_ROW)
|
||||
if (q.step() != SQLITE_ROW)
|
||||
return QString();
|
||||
|
||||
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
|
||||
{
|
||||
if(m_defaultId == StopId)
|
||||
if (m_defaultId == StopId)
|
||||
return items[row].stop.stopId;
|
||||
return items[row].stop.jobId;
|
||||
}
|
||||
|
||||
QString JobMatchModel::getNameAtRow(int row) const
|
||||
{
|
||||
return JobCategoryName::jobName(items[row].stop.jobId,
|
||||
items[row].stop.category);
|
||||
return JobCategoryName::jobName(items[row].stop.jobId, items[row].stop.category);
|
||||
}
|
||||
|
||||
void JobMatchModel::setFilter(db_id exceptJobId, db_id stopsInStationId, const QTime &maxStopArr)
|
||||
{
|
||||
m_exceptJobId = exceptJobId;
|
||||
m_stopStationId = stopsInStationId;
|
||||
m_exceptJobId = exceptJobId;
|
||||
m_stopStationId = stopsInStationId;
|
||||
m_maxStopArrival = maxStopArr;
|
||||
|
||||
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"
|
||||
" FROM stops JOIN jobs ON jobs.id=stops.job_id"
|
||||
" WHERE stops.station_id=?3 AND";
|
||||
|
||||
if(!m_maxStopArrival.isNull())
|
||||
if (!m_maxStopArrival.isNull())
|
||||
sql += " stops.arrival < ?4 AND";
|
||||
}
|
||||
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";
|
||||
}
|
||||
|
||||
if(exceptJobId)
|
||||
if (exceptJobId)
|
||||
{
|
||||
//Filter out unwanted job ID
|
||||
// Filter out unwanted job ID
|
||||
sql += " jobs.id<>?2 AND";
|
||||
}
|
||||
|
||||
//Filter by name (job ID number)
|
||||
//FIXME: filter also by category with regexp
|
||||
// Filter by name (job ID number)
|
||||
// FIXME: filter also by category with regexp
|
||||
sql += " jobs.id LIKE ?1";
|
||||
|
||||
sql += " ORDER BY ";
|
||||
if(m_stopStationId)
|
||||
if (m_stopStationId)
|
||||
{
|
||||
sql += "stops.arrival, ";
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
#include <sqlite3pp/sqlite3pp.h>
|
||||
using namespace sqlite3pp;
|
||||
|
||||
//TODO: share common code with SearchResultModel
|
||||
//TODO: allow filter byy job category
|
||||
// TODO: share common code with SearchResultModel
|
||||
// TODO: allow filter byy job category
|
||||
|
||||
/*!
|
||||
* \brief Match model for Jobs
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||
|
||||
// ISqlFKMatchModel:
|
||||
void autoSuggest(const QString& text) override;
|
||||
void autoSuggest(const QString &text) override;
|
||||
virtual void refreshData() override;
|
||||
QString getName(db_id jobId) const override;
|
||||
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
QString getNameAtRow(int row) const override;
|
||||
|
||||
// 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);
|
||||
|
||||
|
|
|
@ -28,20 +28,20 @@
|
|||
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)");
|
||||
if(outJobId)
|
||||
if (outJobId)
|
||||
q_newJob.bind(1, outJobId);
|
||||
else
|
||||
q_newJob.bind(1); //Bind NULL
|
||||
q_newJob.bind(1); // Bind NULL
|
||||
q_newJob.bind(2, int(cat));
|
||||
|
||||
sqlite3_mutex *mutex = sqlite3_db_mutex(db.db());
|
||||
sqlite3_mutex_enter(mutex);
|
||||
int rc = q_newJob.execute();
|
||||
int rc = q_newJob.execute();
|
||||
db_id jobId = db.last_insert_rowid();
|
||||
sqlite3_mutex_leave(mutex);
|
||||
q_newJob.reset();
|
||||
|
||||
if(rc != SQLITE_OK)
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
qWarning() << rc << db.error_msg();
|
||||
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=?");
|
||||
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);
|
||||
q.reset();
|
||||
|
||||
if(shiftId != 0)
|
||||
if (shiftId != 0)
|
||||
{
|
||||
//Remove job from shift
|
||||
// Remove job from shift
|
||||
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;
|
||||
q.prepare("SELECT station_id FROM stops WHERE job_id=?"
|
||||
" UNION "
|
||||
"SELECT station_id FROM old_stops WHERE job_id=?");
|
||||
q.bind(1, jobId);
|
||||
for(auto st : q)
|
||||
for (auto st : q)
|
||||
{
|
||||
stationsToUpdate.insert(st.get<db_id>(0));
|
||||
}
|
||||
|
||||
//Get Rollingstock used by job
|
||||
// Get Rollingstock used by job
|
||||
QSet<db_id> rsToUpdate;
|
||||
q.prepare("SELECT coupling.rs_id FROM stops JOIN coupling ON coupling.stop_id=stops.id"
|
||||
" WHERE stops.job_id=?"
|
||||
" 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=?");
|
||||
q.bind(1, jobId);
|
||||
for(auto rs : q)
|
||||
for (auto rs : q)
|
||||
{
|
||||
rsToUpdate.insert(rs.get<db_id>(0));
|
||||
}
|
||||
|
||||
//Remove job
|
||||
// Remove job
|
||||
db.execute("BEGIN TRANSACTION");
|
||||
|
||||
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();
|
||||
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.bind(1, jobId);
|
||||
ret = q.step();
|
||||
q.reset();
|
||||
}
|
||||
|
||||
if(ret == SQLITE_OK || ret == SQLITE_DONE)
|
||||
if (ret == SQLITE_OK || ret == SQLITE_DONE)
|
||||
{
|
||||
q.prepare("DELETE FROM jobs WHERE id=?");
|
||||
q.bind(1, jobId);
|
||||
|
@ -122,23 +123,24 @@ bool JobsHelper::removeJob(sqlite3pp::database &db, db_id jobId)
|
|||
q.reset();
|
||||
}
|
||||
|
||||
if(ret == SQLITE_OK || ret == SQLITE_DONE)
|
||||
if (ret == SQLITE_OK || ret == SQLITE_DONE)
|
||||
{
|
||||
db.execute("COMMIT");
|
||||
}
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
|
||||
emit Session->jobRemoved(jobId);
|
||||
|
||||
//Refresh graphs and station views
|
||||
// Refresh graphs and station views
|
||||
emit Session->stationJobsPlanChanged(stationsToUpdate);
|
||||
|
||||
//Refresh Rollingstock views
|
||||
// Refresh Rollingstock views
|
||||
emit Session->rollingStockPlanChanged(rsToUpdate);
|
||||
|
||||
return true;
|
||||
|
@ -146,21 +148,21 @@ bool JobsHelper::removeJob(sqlite3pp::database &db, db_id jobId)
|
|||
|
||||
bool JobsHelper::removeAllJobs(sqlite3pp::database &db)
|
||||
{
|
||||
//Old
|
||||
// Old
|
||||
sqlite3pp::command cmd(db, "DELETE FROM old_coupling");
|
||||
cmd.execute();
|
||||
|
||||
cmd.prepare("DELETE FROM old_stops");
|
||||
cmd.execute();
|
||||
|
||||
//Current
|
||||
// Current
|
||||
cmd.prepare("DELETE FROM coupling");
|
||||
cmd.execute();
|
||||
|
||||
cmd.prepare("DELETE FROM stops");
|
||||
cmd.execute();
|
||||
|
||||
//Delete jobs
|
||||
// Delete jobs
|
||||
cmd.prepare("DELETE FROM jobs");
|
||||
cmd.execute();
|
||||
|
||||
|
@ -169,13 +171,14 @@ bool JobsHelper::removeAllJobs(sqlite3pp::database &db)
|
|||
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);
|
||||
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,"
|
||||
"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;
|
||||
|
||||
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=?");
|
||||
q.bind(1, fromJobId);
|
||||
q.step();
|
||||
|
@ -205,54 +208,54 @@ bool JobsHelper::copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJob
|
|||
end = q.getRows().get<QTime>(0);
|
||||
}
|
||||
|
||||
//Store last next segment when reversing path
|
||||
// Store last next segment when reversing path
|
||||
db_id lastNextSegmentConn = 0;
|
||||
|
||||
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 stationId = stop.get<db_id>(1);
|
||||
QTime arrival = stop.get<QTime>(2);
|
||||
QTime departure = stop.get<QTime>(3);
|
||||
int type = stop.get<int>(4);
|
||||
db_id stationId = stop.get<db_id>(1);
|
||||
QTime arrival = stop.get<QTime>(2);
|
||||
QTime departure = stop.get<QTime>(3);
|
||||
int type = stop.get<int>(4);
|
||||
|
||||
//Avoid memory copy
|
||||
// Avoid memory copy
|
||||
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 out_gate_conn = stop.get<db_id>(7);
|
||||
db_id next_seg_conn = stop.get<db_id>(8);
|
||||
db_id in_gate_conn = stop.get<db_id>(6);
|
||||
db_id out_gate_conn = stop.get<db_id>(7);
|
||||
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 origDep = departure;
|
||||
|
||||
//Arrival and departure get swapped
|
||||
arrival = calcReversedTime(start, end, origDep);
|
||||
// Arrival and departure get swapped
|
||||
arrival = calcReversedTime(start, end, origDep);
|
||||
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);
|
||||
|
||||
//Swap gate connections
|
||||
// Swap gate connections
|
||||
qSwap(in_gate_conn, out_gate_conn);
|
||||
|
||||
//First stop, set in_gate = out_gate so track matches
|
||||
//TODO: this shouldn't be needed but seems to not cause harm
|
||||
if(!in_gate_conn)
|
||||
// First stop, set in_gate = out_gate so track matches
|
||||
// TODO: this shouldn't be needed but seems to not cause harm
|
||||
if (!in_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(!next_seg_conn)
|
||||
// If we do not go past this station (Last stop) then we do not set out gate
|
||||
if (!next_seg_conn)
|
||||
out_gate_conn = 0;
|
||||
}
|
||||
|
||||
//Apply time shift
|
||||
arrival = arrival.addSecs(secsOffset);
|
||||
// Apply time shift
|
||||
arrival = arrival.addSecs(secsOffset);
|
||||
departure = departure.addSecs(secsOffset);
|
||||
|
||||
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(4, departure);
|
||||
q_setStop.bind(5, type);
|
||||
//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);
|
||||
// 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);
|
||||
q_setStop.bindOrNull(7, in_gate_conn);
|
||||
q_setStop.bindOrNull(8, out_gate_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
|
||||
<< db.error_msg();
|
||||
continue; //Skip stop
|
||||
qWarning() << "JobsHelper::copyStops() error setting stop" << origStopId
|
||||
<< "To:" << toJobId << secsOffset << db.error_msg();
|
||||
continue; // Skip stop
|
||||
}
|
||||
db_id newStopId = db.last_insert_rowid();
|
||||
q_setStop.reset();
|
||||
|
||||
if(copyRsOps)
|
||||
if (copyRsOps)
|
||||
{
|
||||
q_getRsOp.bind(1, origStopId);
|
||||
for(auto rs : q_getRsOp)
|
||||
for (auto rs : q_getRsOp)
|
||||
{
|
||||
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)
|
||||
if(op == RsOp::Coupled)
|
||||
// Reverse operations (Couple -> Uncouple and viceversa)
|
||||
if (op == RsOp::Coupled)
|
||||
op = RsOp::Uncoupled;
|
||||
else if(op == RsOp::Uncoupled)
|
||||
else if (op == RsOp::Uncoupled)
|
||||
op = RsOp::Coupled;
|
||||
}
|
||||
|
||||
|
@ -297,20 +301,20 @@ bool JobsHelper::copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJob
|
|||
q_setRsOp.execute();
|
||||
q_setRsOp.reset();
|
||||
|
||||
//Store rollingstock ID to update it later
|
||||
// Store rollingstock ID to update it later
|
||||
rsToUpdate.insert(rsId);
|
||||
}
|
||||
q_getRsOp.reset();
|
||||
}
|
||||
|
||||
//Store station to update it later
|
||||
// Store station to update it later
|
||||
stationsToUpdate.insert(stationId);
|
||||
}
|
||||
|
||||
//Refresh graphs and station views
|
||||
// Refresh graphs and station views
|
||||
emit Session->stationJobsPlanChanged(stationsToUpdate);
|
||||
|
||||
//Refresh Rollingstock views
|
||||
// Refresh Rollingstock views
|
||||
emit Session->rollingStockPlanChanged(rsToUpdate);
|
||||
|
||||
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 g2 ON g2.id=c2.gate_id"
|
||||
" WHERE stops.id=?");
|
||||
if(ret != SQLITE_OK)
|
||||
if (ret != SQLITE_OK)
|
||||
qWarning() << "JobStopDirectionHelper cannot prepare query";
|
||||
}
|
||||
|
||||
|
@ -346,27 +350,27 @@ JobStopDirectionHelper::~JobStopDirectionHelper()
|
|||
utils::Side JobStopDirectionHelper::getStopOutSide(db_id 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;
|
||||
}
|
||||
|
||||
utils::Side in_side = utils::Side::NSides;
|
||||
utils::Side in_side = utils::Side::NSides;
|
||||
utils::Side out_side = utils::Side::NSides;
|
||||
|
||||
auto r = m_query->getRows();
|
||||
if(r.column_type(0) != SQLITE_NULL)
|
||||
auto r = m_query->getRows();
|
||||
if (r.column_type(0) != SQLITE_NULL)
|
||||
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));
|
||||
|
||||
//Prefer out side
|
||||
if(out_side != utils::Side::NSides)
|
||||
// Prefer out side
|
||||
if (out_side != utils::Side::NSides)
|
||||
return out_side;
|
||||
|
||||
//We only have in side, invert it
|
||||
if(in_side == utils::Side::NSides)
|
||||
// We only have in side, invert it
|
||||
if (in_side == utils::Side::NSides)
|
||||
return in_side;
|
||||
|
||||
return in_side == utils::Side::East ? utils::Side::West : utils::Side::East;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
namespace sqlite3pp {
|
||||
class database;
|
||||
class query;
|
||||
}
|
||||
} // namespace sqlite3pp
|
||||
|
||||
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 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 removeAllJobs(sqlite3pp::database &db);
|
||||
|
||||
static bool copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJobId,
|
||||
int secsOffset, bool copyRsOps, bool reversePath);
|
||||
static bool copyStops(sqlite3pp::database &db, db_id fromJobId, db_id toJobId, int secsOffset,
|
||||
bool copyRsOps, bool reversePath);
|
||||
|
||||
static bool checkShiftsExist(sqlite3pp::database &db);
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ NewJobSamePathDlg::NewJobSamePathDlg(QWidget *parent) :
|
|||
QDialog(parent)
|
||||
{
|
||||
QVBoxLayout *lay = new QVBoxLayout(this);
|
||||
label = new QLabel;
|
||||
label = new QLabel;
|
||||
label->setTextFormat(Qt::RichText);
|
||||
lay->addWidget(label);
|
||||
|
||||
|
@ -41,11 +41,11 @@ NewJobSamePathDlg::NewJobSamePathDlg(QWidget *parent) :
|
|||
lay->addWidget(startTimeEdit);
|
||||
|
||||
copyRsCheck = new QCheckBox(tr("Copy Rollingstock items"));
|
||||
copyRsCheck->setChecked(true); //Enabled by default
|
||||
copyRsCheck->setChecked(true); // Enabled by default
|
||||
lay->addWidget(copyRsCheck);
|
||||
|
||||
reversePathCheck = new QCheckBox(tr("Reverse path"));
|
||||
reversePathCheck->setChecked(false); //Disabled by default
|
||||
reversePathCheck->setChecked(false); // Disabled by default
|
||||
lay->addWidget(reversePathCheck);
|
||||
|
||||
QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
|
@ -60,21 +60,21 @@ NewJobSamePathDlg::NewJobSamePathDlg(QWidget *parent) :
|
|||
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;
|
||||
sourceStart = start;
|
||||
sourceEnd = end;
|
||||
sourceStart = start;
|
||||
sourceEnd = end;
|
||||
|
||||
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>"
|
||||
"Please select below when the new job should start.")
|
||||
.arg(JobCategoryName::jobName(sourceJobId, sourceJobCat),
|
||||
sourceStart.toString("HH:mm"),
|
||||
sourceEnd.toString("HH:mm")));
|
||||
.arg(JobCategoryName::jobName(sourceJobId, sourceJobCat),
|
||||
sourceStart.toString("HH:mm"), sourceEnd.toString("HH:mm")));
|
||||
|
||||
//Prevent calling checkTimeIsValid()
|
||||
// Prevent calling checkTimeIsValid()
|
||||
QSignalBlocker blk(startTimeEdit);
|
||||
startTimeEdit->setTime(sourceStart);
|
||||
}
|
||||
|
@ -96,21 +96,21 @@ bool NewJobSamePathDlg::shouldReversePath() const
|
|||
|
||||
void NewJobSamePathDlg::checkTimeIsValid()
|
||||
{
|
||||
const QTime lastValidTime = QTime(23, 59);
|
||||
const QTime lastValidTime = QTime(23, 59);
|
||||
const int travelDurationMsecs = sourceStart.msecsTo(sourceEnd);
|
||||
|
||||
QTime newStart = startTimeEdit->time();
|
||||
int msecsToMidnight = newStart.msecsTo(lastValidTime);
|
||||
if(travelDurationMsecs > msecsToMidnight)
|
||||
QTime newStart = startTimeEdit->time();
|
||||
int msecsToMidnight = newStart.msecsTo(lastValidTime);
|
||||
if (travelDurationMsecs > msecsToMidnight)
|
||||
{
|
||||
//New job would end after midnigth
|
||||
// New job would end after midnigth
|
||||
QMessageBox::warning(this, tr("Invalid Start Time"),
|
||||
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);
|
||||
|
||||
//Prevent recursion
|
||||
// Prevent recursion
|
||||
QSignalBlocker blk(startTimeEdit);
|
||||
startTimeEdit->setTime(newStart);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ class NewJobSamePathDlg : public QDialog
|
|||
public:
|
||||
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;
|
||||
bool shouldCopyRs() const;
|
||||
|
@ -50,7 +50,7 @@ private:
|
|||
QCheckBox *copyRsCheck;
|
||||
QCheckBox *reversePathCheck;
|
||||
|
||||
db_id sourceJobId = 0;
|
||||
db_id sourceJobId = 0;
|
||||
JobCategory sourceJobCat = JobCategory::NCategories;
|
||||
QTime sourceStart;
|
||||
QTime sourceEnd;
|
||||
|
|
|
@ -29,66 +29,62 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
void writeJobSummary(QXmlStreamWriter& xml,
|
||||
const QString& from, const QString& dep,
|
||||
const QString& to, const QString& arr,
|
||||
int axes)
|
||||
void writeJobSummary(QXmlStreamWriter &xml, 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.writeAttribute("table:name", "job_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.writeEmptyElement("table:table-column"); //B
|
||||
xml.writeEmptyElement("table:table-column"); // 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.writeEmptyElement("table:table-column"); //D
|
||||
xml.writeEmptyElement("table:table-column"); // D
|
||||
xml.writeAttribute("table:style-name", "job_5f_summary.D");
|
||||
|
||||
//Row
|
||||
// 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", "P3", from);
|
||||
writeCell(xml, "job_5f_summary_cell", "P2", Odt::text(Odt::jobSummaryDep));
|
||||
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");
|
||||
|
||||
//Cells
|
||||
// Cells
|
||||
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", "P2", Odt::text(Odt::jobSummaryArr));
|
||||
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");
|
||||
|
||||
//Cells
|
||||
// Cells
|
||||
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", "P2", 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) :
|
||||
mDb(db),
|
||||
q_getJobStops(mDb, "SELECT stops.id,"
|
||||
|
@ -128,7 +124,8 @@ JobWriter::JobWriter(database &db) :
|
|||
"stops.arrival,stops.departure"
|
||||
" FROM stops"
|
||||
" 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,"
|
||||
"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)
|
||||
{
|
||||
//job_summary columns
|
||||
// job_summary columns
|
||||
writeColumnStyle(xml, "job_5f_summary.A", "1.60cm");
|
||||
writeColumnStyle(xml, "job_5f_summary.B", "8.30cm");
|
||||
writeColumnStyle(xml, "job_5f_summary.C", "2.90cm");
|
||||
writeColumnStyle(xml, "job_5f_summary.D", "4.20cm");
|
||||
|
||||
//job_stops columns
|
||||
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.C", "2.10cm"); //Departure (IT: Partenza)
|
||||
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.F", "2.30cm"); //Crossings
|
||||
writeColumnStyle(xml, "job_5f_stops.G", "2.30cm"); //Passings
|
||||
writeColumnStyle(xml, "job_5f_stops.H", "3.20cm"); //Description (IT: Note)
|
||||
// job_stops columns
|
||||
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.C", "2.10cm"); // Departure (IT: Partenza)
|
||||
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.F", "2.30cm"); // Crossings
|
||||
writeColumnStyle(xml, "job_5f_stops.G", "2.30cm"); // Passings
|
||||
writeColumnStyle(xml, "job_5f_stops.H", "3.20cm"); // Description (IT: Note)
|
||||
|
||||
/* Style: job_5f_stops.A1
|
||||
*
|
||||
|
@ -181,8 +178,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-right", "none");
|
||||
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_stops.H1
|
||||
*
|
||||
|
@ -206,8 +203,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:padding-bottom", "0.15cm");
|
||||
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_stops.A2
|
||||
*
|
||||
|
@ -230,8 +227,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-top", "none");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_stops.H2
|
||||
*
|
||||
|
@ -254,10 +251,10 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-top", "none");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
//job_5f_asset columns
|
||||
// job_5f_asset columns
|
||||
writeColumnStyle(xml, "job_5f_asset.A", "3.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-top", "0.05pt solid #000000");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_asset.B1
|
||||
*
|
||||
|
@ -302,8 +299,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:padding", "0.049cm");
|
||||
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_asset.A2
|
||||
*
|
||||
|
@ -326,8 +323,8 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-top", "none");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_asset.B2
|
||||
*
|
||||
|
@ -350,11 +347,11 @@ void JobWriter::writeJobAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-top", "none");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
}
|
||||
|
||||
void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
||||
void JobWriter::writeJobStyles(QXmlStreamWriter &xml)
|
||||
{
|
||||
/* Style: job_5f_summary
|
||||
*
|
||||
|
@ -374,8 +371,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeAttribute("style:shadow", "none");
|
||||
xml.writeAttribute("table:align", "left");
|
||||
xml.writeAttribute("style:width", "8.0cm");
|
||||
xml.writeEndElement(); //style:table-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_summary_cell
|
||||
*
|
||||
|
@ -393,8 +390,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeStartElement("style:table-cell-properties");
|
||||
xml.writeAttribute("fo:border", "none");
|
||||
xml.writeAttribute("fo:padding", "0.097cm");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_stops
|
||||
*
|
||||
|
@ -414,19 +411,19 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeAttribute("table:align", "left");
|
||||
xml.writeAttribute("style:width", "16.0cm");
|
||||
|
||||
xml.writeEndElement(); //style:table-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: job_5f_asset
|
||||
*
|
||||
* Type: table
|
||||
* Display name: job_asset
|
||||
* Align: left
|
||||
* Width: 16.0cm
|
||||
*
|
||||
* Usage:
|
||||
* - job_stops table: displays job rollingstock asset summary
|
||||
*/
|
||||
*
|
||||
* Type: table
|
||||
* Display name: job_asset
|
||||
* Align: left
|
||||
* Width: 16.0cm
|
||||
*
|
||||
* Usage:
|
||||
* - job_stops table: displays job rollingstock asset summary
|
||||
*/
|
||||
xml.writeStartElement("style:style");
|
||||
xml.writeAttribute("style:family", "table");
|
||||
xml.writeAttribute("style:name", "job_5f_asset");
|
||||
|
@ -435,8 +432,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeAttribute("table:align", "left");
|
||||
xml.writeAttribute("style:width", "16.0cm");
|
||||
|
||||
xml.writeEndElement(); //style:table-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style P2
|
||||
* type: paragraph
|
||||
|
@ -454,14 +451,14 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "start");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
xml.writeAttribute("fo:font-size", "16pt");
|
||||
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
|
||||
* type: paragraph
|
||||
|
@ -481,13 +478,13 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "start");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
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
|
||||
* type: paragraph
|
||||
|
@ -498,7 +495,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
* Like P4 but not bold
|
||||
*
|
||||
* 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.writeAttribute("style:family", "paragraph");
|
||||
|
@ -507,13 +505,13 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "center");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
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
|
||||
* type: paragraph
|
||||
|
@ -526,7 +524,8 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
* (P4 + Italic, not bold)
|
||||
*
|
||||
* 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.writeAttribute("style:family", "paragraph");
|
||||
|
@ -535,18 +534,17 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "center");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
xml.writeAttribute("fo:font-size", "12pt");
|
||||
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
|
||||
//TODO: quando useremo 'Page master style' vedere se vanno in conflitto
|
||||
// stile interruzione di pagina
|
||||
// TODO: quando useremo 'Page master style' vedere se vanno in conflitto
|
||||
xml.writeStartElement("style:style");
|
||||
xml.writeAttribute("style:family", "paragraph");
|
||||
xml.writeAttribute("style:name", "interruzione");
|
||||
|
@ -554,16 +552,16 @@ void JobWriter::writeJobStyles(QXmlStreamWriter& xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "start");
|
||||
xml.writeAttribute("fo:break-after", "page");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
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"
|
||||
" FROM rs_list"
|
||||
|
@ -572,33 +570,34 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
|||
|
||||
QList<QPair<QString, QList<db_id>>> stopsRS;
|
||||
|
||||
//Title
|
||||
// Title
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", "P1");
|
||||
xml.writeCharacters(JobCategoryName::jobNameSpaced(jobId, jobCat));
|
||||
xml.writeEndElement();
|
||||
|
||||
//Vertical space
|
||||
// Vertical space
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", "P1");
|
||||
xml.writeEndElement();
|
||||
|
||||
db_id firstStopId = 0;
|
||||
db_id lastStopId = 0;
|
||||
db_id lastStopId = 0;
|
||||
|
||||
QTime start, end;
|
||||
QString fromStation, toStation;
|
||||
int axesCount = 0;
|
||||
|
||||
//Job summary
|
||||
// Job summary
|
||||
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);
|
||||
fromStation = r.get<QString>(1);
|
||||
start = r.get<QTime>(2);
|
||||
start = r.get<QTime>(2);
|
||||
|
||||
q_initialJobAxes.bind(1, firstStopId);
|
||||
q_initialJobAxes.step();
|
||||
|
@ -608,21 +607,19 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
|||
q_getFirstStop.reset();
|
||||
|
||||
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);
|
||||
toStation = r.get<QString>(1);
|
||||
end = r.get<QTime>(2);
|
||||
toStation = r.get<QString>(1);
|
||||
end = r.get<QTime>(2);
|
||||
}
|
||||
q_getLastStop.reset();
|
||||
|
||||
if(firstStopId && lastStopId)
|
||||
if (firstStopId && lastStopId)
|
||||
{
|
||||
writeJobSummary(xml,
|
||||
fromStation, start.toString("HH:mm"),
|
||||
toStation, end.toString("HH:mm"),
|
||||
writeJobSummary(xml, fromStation, start.toString("HH:mm"), toStation, end.toString("HH:mm"),
|
||||
axesCount);
|
||||
}
|
||||
else
|
||||
|
@ -633,41 +630,41 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
|||
writeJobSummary(xml, err, err, err, err, 0);
|
||||
}
|
||||
|
||||
//Vertical space
|
||||
// Vertical space
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", "P1");
|
||||
xml.writeEndElement();
|
||||
|
||||
//Table 'job_stops'
|
||||
// Table 'job_stops'
|
||||
xml.writeStartElement("table:table");
|
||||
xml.writeAttribute("table:name", "job_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.writeEmptyElement("table:table-column"); //Arrival
|
||||
xml.writeEmptyElement("table:table-column"); // Arrival
|
||||
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.writeEmptyElement("table:table-column"); //Platform (Platf)
|
||||
xml.writeEmptyElement("table:table-column"); // Platform (Platf)
|
||||
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.writeEmptyElement("table:table-column"); //Crossings
|
||||
xml.writeEmptyElement("table:table-column"); // Crossings
|
||||
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.writeEmptyElement("table:table-column"); //Description
|
||||
xml.writeEmptyElement("table:table-column"); // Description
|
||||
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-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::jobStopCross));
|
||||
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(); //header section
|
||||
xml.writeEndElement(); // end of row
|
||||
xml.writeEndElement(); // header section
|
||||
|
||||
QList<db_id> rsAsset;
|
||||
|
||||
const QString P5_style = "P5";
|
||||
|
||||
//Fill stops table
|
||||
// Fill stops table
|
||||
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 stationId = stop.get<db_id>(1);
|
||||
db_id stopId = stop.get<db_id>(0);
|
||||
db_id stationId = stop.get<db_id>(1);
|
||||
QString stationName = stop.get<QString>(2);
|
||||
QTime arr = stop.get<QTime>(3);
|
||||
QTime dep = stop.get<QTime>(4);
|
||||
const int stopType = stop.get<int>(5);
|
||||
QString descr = stop.get<QString>(6);
|
||||
QTime arr = stop.get<QTime>(3);
|
||||
QTime dep = stop.get<QTime>(4);
|
||||
const int stopType = stop.get<int>(5);
|
||||
QString descr = stop.get<QString>(6);
|
||||
|
||||
QString trackName = stop.get<QString>(7);
|
||||
if(trackName.isEmpty())
|
||||
trackName = stop.get<QString>(8); //Use out gate to get track name
|
||||
QString trackName = stop.get<QString>(7);
|
||||
if (trackName.isEmpty())
|
||||
trackName = stop.get<QString>(8); // Use out gate to get track name
|
||||
|
||||
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);
|
||||
if(!descr.isEmpty())
|
||||
descr2.append('\n'); //Separate from manually set description
|
||||
if (!descr.isEmpty())
|
||||
descr2.append('\n'); // Separate from manually set description
|
||||
descr2.append(descr);
|
||||
descr = descr2;
|
||||
}
|
||||
|
@ -721,58 +719,59 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
|||
|
||||
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);
|
||||
|
||||
//Arrival
|
||||
writeCell(xml, "job_5f_stops.A2", styleName, stopId == firstStopId ? QString() : arr.toString("HH:mm"));
|
||||
// Arrival
|
||||
writeCell(xml, "job_5f_stops.A2", styleName,
|
||||
stopId == firstStopId ? QString() : arr.toString("HH:mm"));
|
||||
|
||||
//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)
|
||||
//then show only arrival
|
||||
writeCell(xml, "job_5f_stops.A2", styleName, (stopId == lastStopId || (isTransit && arr == dep)) ? QString() : dep.toString("HH:mm"));
|
||||
// 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) then show only arrival
|
||||
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);
|
||||
|
||||
//Rollingstock
|
||||
// Rollingstock
|
||||
sqlite3_stmt *stmt = q_getStopCouplings.stmt();
|
||||
writeCellListStart(xml, "job_5f_stops.A2", P5_style);
|
||||
|
||||
//Coupled rollingstock
|
||||
// Coupled rollingstock
|
||||
bool firstCoupRow = true;
|
||||
q_getStopCouplings.bind(1, stopId);
|
||||
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);
|
||||
rsAsset.append(rsId);
|
||||
|
||||
int number = coup.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
||||
int number = coup.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 3));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 3));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||
|
||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
||||
number,
|
||||
modelSuffix, modelSuffixLen,
|
||||
type);
|
||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||
modelSuffix, modelSuffixLen, type);
|
||||
|
||||
if(firstCoupRow)
|
||||
if (firstCoupRow)
|
||||
{
|
||||
firstCoupRow = false;
|
||||
//Use bold font
|
||||
// Use bold font
|
||||
xml.writeStartElement("text:span");
|
||||
xml.writeAttribute("text:style-name", "T1");
|
||||
xml.writeCharacters(Odt::text(Odt::CoupledAbbr));
|
||||
xml.writeEndElement(); //test:span
|
||||
xml.writeEndElement(); // test:span
|
||||
}
|
||||
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
|
@ -780,38 +779,36 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
|||
}
|
||||
q_getStopCouplings.reset();
|
||||
|
||||
//Unoupled rollingstock
|
||||
// Unoupled rollingstock
|
||||
bool firstUncoupRow = true;
|
||||
q_getStopCouplings.bind(1, stopId);
|
||||
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);
|
||||
rsAsset.removeAll(rsId);
|
||||
|
||||
int number = coup.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
||||
int number = coup.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 3));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 3));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||
|
||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
||||
number,
|
||||
modelSuffix, modelSuffixLen,
|
||||
type);
|
||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||
modelSuffix, modelSuffixLen, type);
|
||||
|
||||
if(firstUncoupRow)
|
||||
if (firstUncoupRow)
|
||||
{
|
||||
if(!firstCoupRow) //Not first row, there were coupled rs
|
||||
xml.writeEmptyElement("text:line-break"); //Separate from coupled
|
||||
if (!firstCoupRow) // Not first row, there were coupled rs
|
||||
xml.writeEmptyElement("text:line-break"); // Separate from coupled
|
||||
firstUncoupRow = false;
|
||||
//Use bold font
|
||||
// Use bold font
|
||||
xml.writeStartElement("text:span");
|
||||
xml.writeAttribute("text:style-name", "T1");
|
||||
xml.writeCharacters(Odt::text(Odt::UncoupledAbbr));
|
||||
xml.writeEndElement(); //test:span
|
||||
xml.writeEndElement(); // test:span
|
||||
}
|
||||
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
|
@ -822,7 +819,7 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
|||
|
||||
stopsRS.append({stationName, rsAsset});
|
||||
|
||||
//Crossings / Passings
|
||||
// Crossings / Passings
|
||||
|
||||
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(4, jobId);
|
||||
|
||||
//Incroci
|
||||
// Incroci
|
||||
firstCoupRow = true;
|
||||
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 otherJobId = pass.get<db_id>(1);
|
||||
db_id otherStopId = pass.get<db_id>(0);
|
||||
db_id otherJobId = pass.get<db_id>(1);
|
||||
JobCategory otherJobCat = JobCategory(pass.get<int>(2));
|
||||
|
||||
//QTime otherArr = pass.get<QTime>(3);
|
||||
//QTime otherDep = pass.get<QTime>(4);
|
||||
// QTime otherArr = pass.get<QTime>(3);
|
||||
// QTime otherDep = pass.get<QTime>(4);
|
||||
|
||||
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
||||
|
||||
if(myDir == otherDir)
|
||||
if (myDir == otherDir)
|
||||
passings.append({otherJobId, otherJobCat});
|
||||
else
|
||||
{
|
||||
if(firstCoupRow)
|
||||
if (firstCoupRow)
|
||||
firstCoupRow = false;
|
||||
else
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
|
@ -863,12 +860,12 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
|||
q_selectPassings.reset();
|
||||
writeCellListEnd(xml);
|
||||
|
||||
//Passings
|
||||
// Passings
|
||||
firstCoupRow = true;
|
||||
writeCellListStart(xml, "job_5f_stops.A2", P5_style);
|
||||
for(auto entry : passings)
|
||||
for (auto entry : passings)
|
||||
{
|
||||
if(firstCoupRow)
|
||||
if (firstCoupRow)
|
||||
firstCoupRow = false;
|
||||
else
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
|
@ -876,107 +873,105 @@ void JobWriter::writeJob(QXmlStreamWriter& xml, db_id jobId, JobCategory jobCat)
|
|||
}
|
||||
writeCellListEnd(xml);
|
||||
|
||||
//Description
|
||||
// Description
|
||||
writeCellListStart(xml, "job_5f_stops.H2", P5_style);
|
||||
if(!descr.isEmpty())
|
||||
if (!descr.isEmpty())
|
||||
{
|
||||
//Split in lines
|
||||
// Split in lines
|
||||
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);
|
||||
xml.writeCharacters(line.simplified());
|
||||
if(idx < 0)
|
||||
break; //Last line
|
||||
if (idx < 0)
|
||||
break; // Last line
|
||||
lastIdx = idx + 1;
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
}
|
||||
}
|
||||
writeCellListEnd(xml);
|
||||
|
||||
xml.writeEndElement(); //end of row
|
||||
xml.writeEndElement(); // end of row
|
||||
}
|
||||
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.writeAttribute("text:style-name", "P1");
|
||||
xml.writeEndElement();
|
||||
|
||||
//Table 'job_asset'
|
||||
// Table 'job_asset'
|
||||
xml.writeStartElement("table:table");
|
||||
xml.writeAttribute("table:name", "job_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.writeEmptyElement("table:table-column"); //Assetto
|
||||
xml.writeEmptyElement("table:table-column"); // Assetto
|
||||
xml.writeAttribute("table:style-name", "job_5f_asset.B");
|
||||
|
||||
//Duplicate second-last asset to last stop because last stop would be always empty
|
||||
if(stopsRS.size() >= 2)
|
||||
// Duplicate second-last asset to last stop because last stop would be always empty
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Error!
|
||||
// Error!
|
||||
qWarning() << __FUNCTION__ << "At least 2 stops required!";
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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.bind(1, s.second.at(i));
|
||||
int ret = q_getRSInfo.step();
|
||||
if(ret != SQLITE_ROW)
|
||||
if (ret != SQLITE_ROW)
|
||||
{
|
||||
//Error: RS does not exist!
|
||||
// Error: RS does not exist!
|
||||
continue;
|
||||
}
|
||||
|
||||
sqlite3_stmt *stmt = q_getRSInfo.stmt();
|
||||
int number = sqlite3_column_int(stmt, 0);
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 1);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 1));
|
||||
sqlite3_stmt *stmt = q_getRSInfo.stmt();
|
||||
int number = sqlite3_column_int(stmt, 0);
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 1);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 1));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 3));
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 3));
|
||||
|
||||
const QString name = rs_utils::formatNameRef(modelName, modelNameLen,
|
||||
number,
|
||||
modelSuffix, modelSuffixLen,
|
||||
type);
|
||||
const QString name = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||
modelSuffix, modelSuffixLen, type);
|
||||
|
||||
xml.writeCharacters(name);
|
||||
if(i < s.second.size() - 1)
|
||||
if (i < s.second.size() - 1)
|
||||
xml.writeCharacters(" + ");
|
||||
}
|
||||
writeCellListEnd(xml);
|
||||
|
||||
xml.writeEndElement(); //end of row
|
||||
xml.writeEndElement(); // end of row
|
||||
|
||||
if(firstRow)
|
||||
if (firstRow)
|
||||
firstRow = false;
|
||||
}
|
||||
|
||||
xml.writeEndElement();
|
||||
|
||||
//Interruzione pagina TODO: see style 'interruzione'
|
||||
// Interruzione pagina TODO: see style 'interruzione'
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", "interruzione");
|
||||
xml.writeEndElement();
|
||||
|
|
|
@ -30,9 +30,9 @@ class QXmlStreamWriter;
|
|||
class JobWriter
|
||||
{
|
||||
public:
|
||||
JobWriter(database& db);
|
||||
JobWriter(database &db);
|
||||
|
||||
static void writeJobAutomaticStyles(QXmlStreamWriter& xml);
|
||||
static void writeJobAutomaticStyles(QXmlStreamWriter &xml);
|
||||
static void writeJobStyles(QXmlStreamWriter &xml);
|
||||
|
||||
void writeJob(QXmlStreamWriter &xml, db_id jobId, JobCategory jobCat);
|
||||
|
|
|
@ -25,54 +25,58 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
#include "info.h" //Fot App constants
|
||||
#include "info.h" //Fot App constants
|
||||
#include "app/session.h" //For settings
|
||||
#include "db_metadata/metadatamanager.h"
|
||||
|
||||
#include "odtutils.h"
|
||||
|
||||
//content.xml
|
||||
// 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 QLatin1String stylesFileName = QLatin1String(stylesFileStr, sizeof (stylesFileStr) - 1);
|
||||
static constexpr QLatin1String stylesFileName =
|
||||
QLatin1String(stylesFileStr, sizeof(stylesFileStr) - 1);
|
||||
|
||||
//meta.xml
|
||||
static constexpr char metaFileStr[] = "meta.xml";
|
||||
static constexpr QLatin1String metaFileName = QLatin1String(metaFileStr, sizeof (metaFileStr) - 1);
|
||||
// meta.xml
|
||||
static constexpr char metaFileStr[] = "meta.xml";
|
||||
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 QLatin1String manifestFileName = QLatin1String(manifestFileNameStr, sizeof (manifestFileNameStr) - 1);
|
||||
static constexpr QLatin1String manifestFileName =
|
||||
QLatin1String(manifestFileNameStr, sizeof(manifestFileNameStr) - 1);
|
||||
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 QLatin1String manifestFilePath = QLatin1String(manifestFilePathStr, sizeof (manifestFilePathStr) - 1);
|
||||
static constexpr QLatin1String manifestFilePath =
|
||||
QLatin1String(manifestFilePathStr, sizeof(manifestFilePathStr) - 1);
|
||||
|
||||
OdtDocument::OdtDocument()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool OdtDocument::initDocument()
|
||||
{
|
||||
if(!dir.isValid())
|
||||
if (!dir.isValid())
|
||||
return false;
|
||||
|
||||
content.setFileName(dir.filePath(contentFileName));
|
||||
if(!content.open(QFile::WriteOnly | QFile::Truncate))
|
||||
if (!content.open(QFile::WriteOnly | QFile::Truncate))
|
||||
return false;
|
||||
|
||||
styles.setFileName(dir.filePath(stylesFileName));
|
||||
if(!styles.open(QFile::WriteOnly | QFile::Truncate))
|
||||
if (!styles.open(QFile::WriteOnly | QFile::Truncate))
|
||||
return false;
|
||||
|
||||
contentXml.setDevice(&content);
|
||||
stylesXml.setDevice(&styles);
|
||||
|
||||
//Init content.xml
|
||||
// Init content.xml
|
||||
writeStartDoc(contentXml);
|
||||
contentXml.writeStartElement("office:document-content");
|
||||
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.writeAttribute("office:version", "1.2");
|
||||
|
||||
//Init styles.xml
|
||||
// Init styles.xml
|
||||
writeStartDoc(stylesXml);
|
||||
stylesXml.writeStartElement("office:document-styles");
|
||||
stylesXml.writeNamespace("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "office");
|
||||
|
@ -100,31 +104,32 @@ bool OdtDocument::initDocument()
|
|||
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: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);
|
||||
|
||||
if (zipper == nullptr)
|
||||
{
|
||||
zip_error_t ziperror;
|
||||
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);
|
||||
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";
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//Add META-INF/manifest.xml
|
||||
// Add META-INF/manifest.xml
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//Add styles.xml
|
||||
// Add styles.xml
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//Add content.xml
|
||||
// Add content.xml
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//Add meta.xml
|
||||
// Add meta.xml
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//Add possible images
|
||||
QString imgBasePath = dir.filePath("Pictures") + QLatin1String("/%1");
|
||||
// Add possible images
|
||||
QString imgBasePath = dir.filePath("Pictures") + QLatin1String("/%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);
|
||||
if (source == nullptr)
|
||||
|
@ -207,14 +212,15 @@ bool OdtDocument::saveTo(const QString& fileName)
|
|||
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);
|
||||
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);
|
||||
}
|
||||
|
@ -236,11 +242,11 @@ void OdtDocument::endDocument()
|
|||
|
||||
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());
|
||||
if(!pictures.mkdir("Pictures"))
|
||||
if (!pictures.mkdir("Pictures"))
|
||||
qWarning() << "OdtDocument: cannot create Pictures folder";
|
||||
}
|
||||
imageList.append({name, mediaType});
|
||||
|
@ -251,12 +257,12 @@ void OdtDocument::writeStartDoc(QXmlStreamWriter &xml)
|
|||
{
|
||||
xml.setAutoFormatting(true);
|
||||
xml.setAutoFormattingIndent(-1);
|
||||
//xml.writeStartDocument(QStringLiteral("1.0"), true);
|
||||
// xml.writeStartDocument(QStringLiteral("1.0"), true);
|
||||
xml.writeStartDocument(QStringLiteral("1.0"));
|
||||
}
|
||||
|
||||
void OdtDocument::writeFileEntry(QXmlStreamWriter& xml,
|
||||
const QString& fullPath, const QString& mediaType)
|
||||
void OdtDocument::writeFileEntry(QXmlStreamWriter &xml, const QString &fullPath,
|
||||
const QString &mediaType)
|
||||
{
|
||||
xml.writeStartElement("manifest:file-entry");
|
||||
xml.writeAttribute("manifest:full-path", fullPath);
|
||||
|
@ -264,12 +270,12 @@ void OdtDocument::writeFileEntry(QXmlStreamWriter& xml,
|
|||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
void OdtDocument::saveManifest(const QString& path)
|
||||
void OdtDocument::saveManifest(const QString &path)
|
||||
{
|
||||
const QString xmlMime = QLatin1String("text/xml");
|
||||
|
||||
QDir manifestDir(path + metaInfDirPath);
|
||||
if(!manifestDir.exists())
|
||||
if (!manifestDir.exists())
|
||||
manifestDir.mkpath(".");
|
||||
|
||||
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.writeAttribute("manifest:version", "1.2");
|
||||
|
||||
//Root
|
||||
// Root
|
||||
writeFileEntry(xml, "/", "application/vnd.oasis.opendocument.text");
|
||||
|
||||
//styles.xml
|
||||
// styles.xml
|
||||
writeFileEntry(xml, stylesFileName, xmlMime);
|
||||
|
||||
//content.xml
|
||||
// content.xml
|
||||
writeFileEntry(xml, contentFileName, xmlMime);
|
||||
|
||||
//meta.xml
|
||||
// meta.xml
|
||||
writeFileEntry(xml, metaFileName, xmlMime);
|
||||
|
||||
//Add possible images
|
||||
for(const auto& img : qAsConst(imageList))
|
||||
// Add possible images
|
||||
for (const auto &img : qAsConst(imageList))
|
||||
{
|
||||
writeFileEntry(xml, "Pictures/" + img.first, img.second);
|
||||
}
|
||||
|
||||
xml.writeEndElement(); //manifest:manifest
|
||||
xml.writeEndElement(); // manifest:manifest
|
||||
|
||||
xml.writeEndDocument();
|
||||
}
|
||||
|
||||
void OdtDocument::saveMeta(const QString& path)
|
||||
void OdtDocument::saveMeta(const QString &path)
|
||||
{
|
||||
QDir metaDir(path);
|
||||
|
||||
|
@ -323,122 +329,122 @@ void OdtDocument::saveMeta(const QString& path)
|
|||
|
||||
xml.writeStartElement("office:meta");
|
||||
|
||||
MetaDataManager *meta = Session->getMetaDataManager();
|
||||
MetaDataManager *meta = Session->getMetaDataManager();
|
||||
const bool storeLocationAndDate = AppSettings.getSheetStoreLocationDateInMeta();
|
||||
|
||||
//Title
|
||||
if(!documentTitle.isEmpty())
|
||||
// Title
|
||||
if (!documentTitle.isEmpty())
|
||||
{
|
||||
xml.writeStartElement("dc:title");
|
||||
xml.writeCharacters(documentTitle);
|
||||
xml.writeEndElement(); //dc:title
|
||||
xml.writeEndElement(); // dc:title
|
||||
}
|
||||
|
||||
//Subject
|
||||
// Subject
|
||||
xml.writeStartElement("dc:subject");
|
||||
xml.writeCharacters(AppDisplayName);
|
||||
xml.writeCharacters(" Session Meeting"); //Do not translate, so it's standard for everyone
|
||||
xml.writeEndElement(); //dc:subject
|
||||
xml.writeCharacters(" Session Meeting"); // Do not translate, so it's standard for everyone
|
||||
xml.writeEndElement(); // dc:subject
|
||||
|
||||
//Description
|
||||
// Description
|
||||
QString meetingLocation;
|
||||
if(storeLocationAndDate)
|
||||
if (storeLocationAndDate)
|
||||
{
|
||||
meta->getString(meetingLocation, MetaDataKey::MeetingLocation);
|
||||
|
||||
QDate start, end;
|
||||
qint64 tmp = 0;
|
||||
if(meta->getInt64(tmp, MetaDataKey::MeetingStartDate) == MetaDataKey::ValueFound)
|
||||
if (meta->getInt64(tmp, MetaDataKey::MeetingStartDate) == MetaDataKey::ValueFound)
|
||||
start = QDate::fromJulianDay(tmp);
|
||||
if(meta->getInt64(tmp, MetaDataKey::MeetingEndDate) == MetaDataKey::ValueFound)
|
||||
if (meta->getInt64(tmp, MetaDataKey::MeetingEndDate) == MetaDataKey::ValueFound)
|
||||
end = QDate::fromJulianDay(tmp);
|
||||
if(!end.isValid() || end < start)
|
||||
if (!end.isValid() || end < start)
|
||||
end = start;
|
||||
|
||||
if(!meetingLocation.isEmpty() && start.isValid())
|
||||
if (!meetingLocation.isEmpty() && start.isValid())
|
||||
{
|
||||
//Store description only if metadata is valid
|
||||
//Example: Meeting in CORNUDA from 07/11/2020 to 09/11/2020
|
||||
// Store description only if metadata is valid
|
||||
// Example: Meeting in CORNUDA from 07/11/2020 to 09/11/2020
|
||||
|
||||
QString description;
|
||||
if(start != end)
|
||||
if (start != end)
|
||||
{
|
||||
description = Odt::text(Odt::meetingFromTo)
|
||||
.arg(meetingLocation,
|
||||
start.toString("dd/MM/yyyy"),
|
||||
end.toString("dd/MM/yyyy"));
|
||||
description =
|
||||
Odt::text(Odt::meetingFromTo)
|
||||
.arg(meetingLocation, start.toString("dd/MM/yyyy"), end.toString("dd/MM/yyyy"));
|
||||
}
|
||||
else
|
||||
{
|
||||
description = Odt::text(Odt::meetingOnDate)
|
||||
.arg(meetingLocation,
|
||||
start.toString("dd/MM/yyyy"));
|
||||
description =
|
||||
Odt::text(Odt::meetingOnDate).arg(meetingLocation, start.toString("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
xml.writeStartElement("dc:description");
|
||||
xml.writeCharacters(description);
|
||||
xml.writeEndElement(); //dc:description
|
||||
xml.writeEndElement(); // dc:description
|
||||
}
|
||||
}
|
||||
|
||||
//Language
|
||||
// Language
|
||||
xml.writeStartElement("dc:language");
|
||||
xml.writeCharacters(Session->getSheetExportLocale().bcp47Name());
|
||||
xml.writeEndElement(); //dc:language
|
||||
xml.writeEndElement(); // dc:language
|
||||
|
||||
//Generator
|
||||
// Generator
|
||||
xml.writeStartElement("meta:generator");
|
||||
xml.writeCharacters(AppProduct);
|
||||
xml.writeCharacters("/");
|
||||
xml.writeCharacters(AppVersion);
|
||||
xml.writeCharacters("-");
|
||||
xml.writeCharacters(AppBuildDate);
|
||||
xml.writeEndElement(); //meta:generator
|
||||
xml.writeEndElement(); // meta:generator
|
||||
|
||||
//Initial creator
|
||||
// Initial creator
|
||||
xml.writeStartElement("meta:initial-creator");
|
||||
xml.writeCharacters(AppDisplayName);
|
||||
xml.writeEndElement(); //meta:initial-creator
|
||||
xml.writeEndElement(); // meta:initial-creator
|
||||
|
||||
//Creation date
|
||||
// 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)
|
||||
// so do not use Qt::ISODate otherwise there is the risk of adding time zone offset to string
|
||||
// NOTE: date must be in ISO 8601 format but without time zone offset (LibreOffice doesn't
|
||||
// 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.writeEndElement(); //meta:creation-date
|
||||
xml.writeEndElement(); // meta:creation-date
|
||||
|
||||
//Keywords
|
||||
// Keywords
|
||||
xml.writeStartElement("meta:keyword");
|
||||
xml.writeCharacters(AppDisplayName);
|
||||
xml.writeEndElement(); //meta:keyword
|
||||
xml.writeEndElement(); // meta:keyword
|
||||
|
||||
xml.writeStartElement("meta:keyword");
|
||||
xml.writeCharacters(AppProduct);
|
||||
xml.writeEndElement(); //meta:keyword
|
||||
xml.writeEndElement(); // meta:keyword
|
||||
|
||||
xml.writeStartElement("meta:keyword");
|
||||
xml.writeCharacters(AppCompany);
|
||||
xml.writeEndElement(); //meta:keyword
|
||||
xml.writeEndElement(); // meta:keyword
|
||||
|
||||
xml.writeStartElement("meta:keyword");
|
||||
xml.writeCharacters(Odt::text(Odt::meeting));
|
||||
xml.writeEndElement(); //meta:keyword
|
||||
xml.writeEndElement(); // meta:keyword
|
||||
|
||||
//Untranslated version
|
||||
// Untranslated version
|
||||
xml.writeStartElement("meta:keyword");
|
||||
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.writeCharacters(meetingLocation);
|
||||
xml.writeEndElement(); //meta:keyword
|
||||
xml.writeEndElement(); // meta:keyword
|
||||
}
|
||||
|
||||
//End
|
||||
xml.writeEndElement(); //office:meta
|
||||
xml.writeEndElement(); //office:document-meta
|
||||
// End
|
||||
xml.writeEndElement(); // office:meta
|
||||
xml.writeEndElement(); // office:document-meta
|
||||
|
||||
xml.writeEndDocument();
|
||||
}
|
||||
|
|
|
@ -35,10 +35,13 @@ public:
|
|||
void startBody();
|
||||
void endDocument();
|
||||
|
||||
//Returns a 'path + file name' where you must save the image
|
||||
QString addImage(const QString& name, const QString& mediaType);
|
||||
// Returns a 'path + file name' where you must save the image
|
||||
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:
|
||||
QTemporaryDir dir;
|
||||
|
@ -57,7 +60,7 @@ private:
|
|||
|
||||
private:
|
||||
QString documentTitle;
|
||||
//pair: fileName, mediaType
|
||||
// pair: fileName, mediaType
|
||||
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.writeAttribute("style:column-width", width);
|
||||
xml.writeEndElement(); //style:table-column-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-column-properties
|
||||
xml.writeEndElement(); // style
|
||||
}
|
||||
|
||||
/* writeCell
|
||||
*
|
||||
* 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.writeAttribute("office:value-type", "string");
|
||||
xml.writeAttribute("table:style-name", cellStyle);
|
||||
|
||||
//text:p
|
||||
// text:p
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", paragraphStyle);
|
||||
xml.writeCharacters(text);
|
||||
xml.writeEndElement(); //text:p
|
||||
xml.writeEndElement(); // text:p
|
||||
|
||||
xml.writeEndElement(); //table-cell
|
||||
xml.writeEndElement(); // table-cell
|
||||
}
|
||||
|
||||
/* writeCellListStart
|
||||
|
@ -66,14 +68,15 @@ void writeCell(QXmlStreamWriter &xml, const QString &cellStyle, const QString &p
|
|||
* Then you have full control on cell contents
|
||||
* 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.writeAttribute("office:value-type", "string");
|
||||
xml.writeAttribute("table:style-name", cellStyle);
|
||||
|
||||
//text:p
|
||||
// text:p
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", paragraphStyle);
|
||||
}
|
||||
|
@ -84,8 +87,8 @@ void writeCellListStart(QXmlStreamWriter &xml, const QString &cellStyle, const Q
|
|||
*/
|
||||
void writeCellListEnd(QXmlStreamWriter &xml)
|
||||
{
|
||||
xml.writeEndElement(); //text:p
|
||||
xml.writeEndElement(); //table-cell
|
||||
xml.writeEndElement(); // text:p
|
||||
xml.writeEndElement(); // table-cell
|
||||
}
|
||||
|
||||
void writeStandardStyle(QXmlStreamWriter &xml)
|
||||
|
@ -96,7 +99,7 @@ void writeStandardStyle(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("style:family", "paragraph");
|
||||
xml.writeAttribute("style:class", "text");
|
||||
|
||||
xml.writeEndElement(); //style:style
|
||||
xml.writeEndElement(); // style:style
|
||||
}
|
||||
|
||||
void writeGraphicsStyle(QXmlStreamWriter &xml)
|
||||
|
@ -113,9 +116,9 @@ void writeGraphicsStyle(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("style:vertical-rel", "paragraph");
|
||||
xml.writeAttribute("style:horizontal-pos", "center");
|
||||
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)
|
||||
|
@ -154,14 +157,14 @@ void writeCommonStyles(QXmlStreamWriter &xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "center");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
xml.writeAttribute("fo:font-size", "18pt");
|
||||
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
|
||||
* type: paragraph style
|
||||
|
@ -199,14 +202,14 @@ void writeCommonStyles(QXmlStreamWriter &xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "center");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
xml.writeAttribute("fo:font-size", "12pt");
|
||||
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
|
||||
* type: text style
|
||||
|
@ -225,14 +228,14 @@ void writeCommonStyles(QXmlStreamWriter &xml)
|
|||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
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)
|
||||
{
|
||||
//Base style for MP1 style used in header/footer
|
||||
// Base style for MP1 style used in header/footer
|
||||
xml.writeStartElement("style:style");
|
||||
|
||||
xml.writeAttribute("style:family", "paragraph");
|
||||
|
@ -250,33 +253,33 @@ void writeFooterStyle(QXmlStreamWriter &xml)
|
|||
xml.writeStartElement("style:tab-stop");
|
||||
xml.writeAttribute("style:position", "8.5cm");
|
||||
xml.writeAttribute("style:type", "center");
|
||||
xml.writeEndElement(); //style:tab-stop
|
||||
xml.writeEndElement(); // style:tab-stop
|
||||
|
||||
xml.writeStartElement("style:tab-stop");
|
||||
xml.writeAttribute("style:position", "17cm");
|
||||
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)
|
||||
{
|
||||
//Footer style
|
||||
// Footer style
|
||||
xml.writeStartElement("style:style");
|
||||
xml.writeAttribute("style:name", "MP1");
|
||||
xml.writeAttribute("style:family", "paragraph");
|
||||
xml.writeAttribute("style:parent-style-name", "Footer");
|
||||
xml.writeStartElement("style:text-properties");
|
||||
xml.writeAttribute("style:font-name", "Liberation Sans");
|
||||
xml.writeEndElement(); //style:text-properties
|
||||
xml.writeEndElement(); //style:style
|
||||
xml.writeEndElement(); // style:text-properties
|
||||
xml.writeEndElement(); // style:style
|
||||
|
||||
//Page Layout
|
||||
// Page Layout
|
||||
xml.writeStartElement("style:page-layout");
|
||||
|
||||
xml.writeAttribute("style:name", "Mpm1");
|
||||
|
@ -286,25 +289,25 @@ void writePageLayout(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:margin-bottom", "2cm");
|
||||
xml.writeAttribute("fo:margin-left", "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.writeEndElement(); //style:header-style
|
||||
xml.writeEndElement(); // style:header-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.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("text:p");
|
||||
|
@ -313,10 +316,10 @@ void writeHeaderFooter(QXmlStreamWriter &xml, const QString& headerText, const Q
|
|||
xml.writeCharacters(headerText);
|
||||
|
||||
xml.writeStartElement("text:tab");
|
||||
xml.writeEndElement(); //text:tab
|
||||
xml.writeEndElement(); // text:tab
|
||||
|
||||
xml.writeStartElement("text:tab");
|
||||
xml.writeEndElement(); //text:tab
|
||||
xml.writeEndElement(); // text:tab
|
||||
|
||||
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.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("text:p");
|
||||
|
@ -340,21 +343,21 @@ void writeHeaderFooter(QXmlStreamWriter &xml, const QString& headerText, const Q
|
|||
|
||||
xml.writeStartElement("text:page-number");
|
||||
xml.writeAttribute("text:select-page", "current");
|
||||
xml.writeEndElement(); //text:page-number
|
||||
xml.writeEndElement(); // text:page-number
|
||||
|
||||
xml.writeStartElement("text:tab");
|
||||
xml.writeEndElement(); //text:tab
|
||||
xml.writeEndElement(); // text:tab
|
||||
|
||||
xml.writeStartElement("text:tab");
|
||||
xml.writeEndElement(); //text:tab
|
||||
xml.writeEndElement(); // text:tab
|
||||
|
||||
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("text:p");
|
||||
|
@ -362,19 +365,19 @@ void writeHeaderFooter(QXmlStreamWriter &xml, const QString& headerText, const Q
|
|||
|
||||
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)
|
||||
{
|
||||
const QString variablePitch = QStringLiteral("variable");
|
||||
const QString variablePitch = QStringLiteral("variable");
|
||||
const QString liberationSerif = QStringLiteral("Liberation Serif");
|
||||
const QString liberationSans = QStringLiteral("Liberation Sans");
|
||||
const QString liberationMono = QStringLiteral("Liberation Mono");
|
||||
const QString liberationSans = QStringLiteral("Liberation Sans");
|
||||
const QString liberationMono = QStringLiteral("Liberation Mono");
|
||||
|
||||
writeFontFace(xml, liberationSerif, liberationSerif, "roman", variablePitch);
|
||||
writeFontFace(xml, liberationSans, liberationSans, "swiss", variablePitch);
|
||||
|
@ -386,18 +389,18 @@ QString Odt::text(const Text &t)
|
|||
QTranslator *translator = Session->getSheetExportTranslator();
|
||||
|
||||
QString result;
|
||||
if(translator)
|
||||
if (translator)
|
||||
{
|
||||
//Prefer selected language
|
||||
// Prefer selected language
|
||||
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);
|
||||
}
|
||||
|
||||
if(result.isNull()) //Fallback to application language
|
||||
if (result.isNull()) // Fallback to application language
|
||||
result = tr(t.sourceText, t.disambiguation);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -24,16 +24,14 @@
|
|||
|
||||
#include <QCoreApplication>
|
||||
|
||||
//small util
|
||||
void writeColumnStyle(QXmlStreamWriter& xml, const QString& name, const QString& width);
|
||||
// small util
|
||||
void writeColumnStyle(QXmlStreamWriter &xml, const QString &name, const QString &width);
|
||||
|
||||
void writeCell(QXmlStreamWriter &xml,
|
||||
const QString& cellStyle,
|
||||
const QString& paragraphStyle,
|
||||
const QString& text);
|
||||
void writeCell(QXmlStreamWriter &xml, const QString &cellStyle, const QString ¶graphStyle,
|
||||
const QString &text);
|
||||
|
||||
|
||||
void writeCellListStart(QXmlStreamWriter &xml, const QString &cellStyle, const QString ¶graphStyle);
|
||||
void writeCellListStart(QXmlStreamWriter &xml, const QString &cellStyle,
|
||||
const QString ¶graphStyle);
|
||||
void writeCellListEnd(QXmlStreamWriter &xml);
|
||||
|
||||
void writeStandardStyle(QXmlStreamWriter &xml);
|
||||
|
@ -46,37 +44,34 @@ void writeFooterStyle(QXmlStreamWriter &xml);
|
|||
|
||||
void writePageLayout(QXmlStreamWriter &xml);
|
||||
|
||||
void writeHeaderFooter(QXmlStreamWriter &xml,
|
||||
const QString& headerText,
|
||||
const QString& footerText);
|
||||
void writeHeaderFooter(QXmlStreamWriter &xml, const QString &headerText, const QString &footerText);
|
||||
|
||||
inline void writeFontFace(QXmlStreamWriter &xml,
|
||||
const QString& name, const QString& family,
|
||||
const QString& genericFamily, const QString& pitch)
|
||||
inline void writeFontFace(QXmlStreamWriter &xml, const QString &name, const QString &family,
|
||||
const QString &genericFamily, const QString &pitch)
|
||||
{
|
||||
xml.writeStartElement("style:font-face");
|
||||
xml.writeAttribute("style:name", name);
|
||||
if(!family.isEmpty())
|
||||
if (!family.isEmpty())
|
||||
{
|
||||
QString familyQuoted;
|
||||
familyQuoted.reserve(family.size() + 2);
|
||||
bool needsQuotes = family.contains(' '); //If family name contains blanks
|
||||
if(needsQuotes) //Enclose in single quotes
|
||||
bool needsQuotes = family.contains(' '); // If family name contains blanks
|
||||
if (needsQuotes) // Enclose in single quotes
|
||||
familyQuoted.append('\'');
|
||||
familyQuoted.append(family);
|
||||
if(needsQuotes)
|
||||
if (needsQuotes)
|
||||
familyQuoted.append('\'');
|
||||
xml.writeAttribute("svg:font-family", familyQuoted);
|
||||
}
|
||||
if(!genericFamily.isEmpty())
|
||||
if (!genericFamily.isEmpty())
|
||||
{
|
||||
xml.writeAttribute("svg:font-family-generic", genericFamily);
|
||||
}
|
||||
if(!pitch.isEmpty())
|
||||
if (!pitch.isEmpty())
|
||||
{
|
||||
xml.writeAttribute("svg:font-pitch", pitch);
|
||||
}
|
||||
xml.writeEndElement(); //style:font-face
|
||||
xml.writeEndElement(); // style:font-face
|
||||
}
|
||||
|
||||
void writeLiberationFontFaces(QXmlStreamWriter &xml);
|
||||
|
@ -91,72 +86,90 @@ public:
|
|||
const char *disambiguation;
|
||||
};
|
||||
|
||||
static QString text(const Text& t);
|
||||
static QString text(const Text &t);
|
||||
|
||||
public:
|
||||
//Header/Footer
|
||||
static constexpr Text headerPage = QT_TRANSLATE_NOOP3("Odt", "Page ",
|
||||
"Header page, leave space at end, page number will be added");
|
||||
// Header/Footer
|
||||
static constexpr Text headerPage = QT_TRANSLATE_NOOP3(
|
||||
"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 meetingFromTo = QT_TRANSLATE_NOOP3("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",
|
||||
"Document description, where, when");
|
||||
static constexpr Text meetingFromToShort = QT_TRANSLATE_NOOP3("Odt", "From %1 to %2",
|
||||
"Shift cover, meeting from date, to date");
|
||||
static constexpr Text meetingFromTo = QT_TRANSLATE_NOOP3(
|
||||
"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", "Document description, where, when");
|
||||
static constexpr Text meetingFromToShort =
|
||||
QT_TRANSLATE_NOOP3("Odt", "From %1 to %2", "Shift cover, meeting from date, to date");
|
||||
|
||||
//Rollingstock
|
||||
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");
|
||||
// Rollingstock
|
||||
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 genericRSOwner = QT_TRANSLATE_NOOP3("Odt", "Owner", "Rollingstock Owner");
|
||||
|
||||
static constexpr Text rsSessionTitle = QT_TRANSLATE_NOOP3("Odt", "Rollingstock by %1 at %2 of session",
|
||||
"Rollingstock Session title, 1 is Owner/Station and 2 is start/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");
|
||||
static constexpr Text rsSessionTitle =
|
||||
QT_TRANSLATE_NOOP3("Odt", "Rollingstock by %1 at %2 of session",
|
||||
"Rollingstock Session title, 1 is Owner/Station and 2 is start/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
|
||||
static constexpr Text jobSummaryFrom = QT_TRANSLATE_NOOP3("Odt", "From:", "Job summary");
|
||||
static constexpr Text jobSummaryTo = QT_TRANSLATE_NOOP3("Odt", "To:", "Job summary");
|
||||
// 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 jobSummaryDep = QT_TRANSLATE_NOOP3("Odt", "Departure:", "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 jobSummaryArr = QT_TRANSLATE_NOOP3("Odt", "Arrival:", "Job summary");
|
||||
static constexpr Text jobSummaryAxes = QT_TRANSLATE_NOOP3("Odt", "Axes:", "Job summary");
|
||||
|
||||
//Job Stops Header
|
||||
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 stationDocTitle = 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");
|
||||
// Job Stops Header
|
||||
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 stationDocTitle =
|
||||
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 departure = QT_TRANSLATE_NOOP3("Odt", "Departure", "Job stop table");
|
||||
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 arrival = QT_TRANSLATE_NOOP3("Odt", "Arrival", "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 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 stationToCol = QT_TRANSLATE_NOOP3("Odt", "To", "Station stop table, To next station column");
|
||||
static constexpr Text stationFromCol =
|
||||
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 jobStopIsTransit = QT_TRANSLATE_NOOP3("Odt", "Transit", "Job stop table, notes column");
|
||||
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 jobStopPlatf =
|
||||
QT_TRANSLATE_NOOP3("Odt", "Platf", "Job stop table, platform abbreviated");
|
||||
static constexpr Text jobStopIsTransit =
|
||||
QT_TRANSLATE_NOOP3("Odt", "Transit", "Job stop table, notes column");
|
||||
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 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 jobStopPassingsShort = QT_TRANSLATE_NOOP3("Odt", "Passes", "Job stop passings abbreviated column");
|
||||
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 jobStopCrossShort =
|
||||
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");
|
||||
|
||||
//Job stops
|
||||
static constexpr Text jobReverseDirection = QT_TRANSLATE_NOOP3("Odt", "Reverse direction", "Job stop table");
|
||||
// Job stops
|
||||
static constexpr Text jobReverseDirection =
|
||||
QT_TRANSLATE_NOOP3("Odt", "Reverse direction", "Job stop table");
|
||||
|
||||
//Shift
|
||||
static constexpr Text shiftCoverTitle = 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");
|
||||
// Shift
|
||||
static constexpr Text shiftCoverTitle =
|
||||
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
|
||||
|
|
|
@ -33,43 +33,39 @@ SessionRSWriter::SessionRSWriter(database &db, SessionRSMode mode, SessionRSOrde
|
|||
m_mode(mode),
|
||||
m_order(order)
|
||||
{
|
||||
//TODO: fetch departure instead of arrival for start session
|
||||
const auto sql = QStringLiteral("SELECT %1,"
|
||||
" %2, %3, %4,"
|
||||
" rs_list.id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type,"
|
||||
" t1.name,t2.name,"
|
||||
" stops.job_id, jobs.category, coupling.operation"
|
||||
" FROM rs_list"
|
||||
" JOIN coupling ON coupling.rs_id=rs_list.id"
|
||||
" JOIN stops ON stops.id=coupling.stop_id"
|
||||
" JOIN jobs ON jobs.id=stops.job_id"
|
||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" LEFT JOIN station_gate_connections g1 ON g1.id=stops.in_gate_conn"
|
||||
" LEFT JOIN station_gate_connections g2 ON g2.id=stops.out_gate_conn"
|
||||
" LEFT JOIN station_tracks t1 ON t1.id=g1.track_id"
|
||||
" LEFT JOIN station_tracks t2 ON t2.id=g2.track_id"
|
||||
" JOIN %5"
|
||||
" GROUP BY rs_list.id"
|
||||
" ORDER BY %6, stops.arrival, stops.job_id, rs_list.model_id");
|
||||
// TODO: fetch departure instead of arrival for start session
|
||||
const auto sql = QStringLiteral(
|
||||
"SELECT %1,"
|
||||
" %2, %3, %4,"
|
||||
" rs_list.id, rs_list.number, rs_models.name, rs_models.suffix, rs_models.type,"
|
||||
" t1.name,t2.name,"
|
||||
" stops.job_id, jobs.category, coupling.operation"
|
||||
" FROM rs_list"
|
||||
" JOIN coupling ON coupling.rs_id=rs_list.id"
|
||||
" JOIN stops ON stops.id=coupling.stop_id"
|
||||
" JOIN jobs ON jobs.id=stops.job_id"
|
||||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" LEFT JOIN station_gate_connections g1 ON g1.id=stops.in_gate_conn"
|
||||
" LEFT JOIN station_gate_connections g2 ON g2.id=stops.out_gate_conn"
|
||||
" LEFT JOIN station_tracks t1 ON t1.id=g1.track_id"
|
||||
" LEFT JOIN station_tracks t2 ON t2.id=g2.track_id"
|
||||
" JOIN %5"
|
||||
" 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)");
|
||||
if(m_order == SessionRSOrder::ByStation)
|
||||
QString temp = sql.arg(m_mode == SessionRSMode::StartOfSession ? "MIN(stops.arrival)"
|
||||
: "MAX(stops.departure)");
|
||||
if (m_order == SessionRSOrder::ByStation)
|
||||
{
|
||||
temp = temp.arg("rs_list.owner_id",
|
||||
"rs_owners.name",
|
||||
"stops.station_id",
|
||||
"rs_owners ON rs_owners.id=rs_list.owner_id",
|
||||
"stops.station_id");
|
||||
temp = temp.arg("rs_list.owner_id", "rs_owners.name", "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=?");
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = temp.arg("stops.station_id",
|
||||
"stations.name",
|
||||
"rs_list.owner_id",
|
||||
"stations ON stations.id=stops.station_id",
|
||||
"rs_list.owner_id");
|
||||
temp = temp.arg("stops.station_id", "stations.name", "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=?");
|
||||
}
|
||||
|
@ -91,7 +87,8 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
|||
* Like P4 but not bold, and Sans Serif
|
||||
*
|
||||
* 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.writeAttribute("style:family", "paragraph");
|
||||
|
@ -100,27 +97,26 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "center");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
xml.writeAttribute("style:font-name", "Liberation Sans");
|
||||
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
|
||||
*
|
||||
* Type: table
|
||||
* Display name: rollingstock
|
||||
* Align: left
|
||||
* Width: 16.0cm
|
||||
*
|
||||
* Usage:
|
||||
* - SessionRSWriter: main table for Rollingstock Owners/Stations
|
||||
*/
|
||||
*
|
||||
* Type: table
|
||||
* Display name: rollingstock
|
||||
* Align: left
|
||||
* Width: 16.0cm
|
||||
*
|
||||
* Usage:
|
||||
* - SessionRSWriter: main table for Rollingstock Owners/Stations
|
||||
*/
|
||||
xml.writeStartElement("style:style");
|
||||
xml.writeAttribute("style:family", "table");
|
||||
xml.writeAttribute("style:name", "rs_5f_table");
|
||||
|
@ -129,15 +125,15 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("style:shadow", "none");
|
||||
xml.writeAttribute("table:align", "left");
|
||||
xml.writeAttribute("style:width", "16.0cm");
|
||||
xml.writeEndElement(); //style:table-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
//rs_table columns
|
||||
writeColumnStyle(xml, "rs_5f_table.A", "3.00cm"); //RS Name
|
||||
writeColumnStyle(xml, "rs_5f_table.B", "4.45cm"); //Job
|
||||
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.E", "4.00cm"); //Station or Owner
|
||||
// rs_table columns
|
||||
writeColumnStyle(xml, "rs_5f_table.A", "3.00cm"); // RS Name
|
||||
writeColumnStyle(xml, "rs_5f_table.B", "4.45cm"); // Job
|
||||
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.E", "4.00cm"); // Station or Owner
|
||||
|
||||
/* Style: rs_5f_table.A1
|
||||
*
|
||||
|
@ -158,8 +154,8 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-right", "none");
|
||||
xml.writeAttribute("fo:border-top", "0.05pt solid #000000");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: rs_5f_table.E1
|
||||
*
|
||||
|
@ -177,8 +173,8 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
|||
xml.writeStartElement("style:table-cell-properties");
|
||||
xml.writeAttribute("fo:padding", "0.049cm");
|
||||
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: rs_5f_table.A2
|
||||
*
|
||||
|
@ -199,8 +195,8 @@ void SessionRSWriter::writeStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-right", "none");
|
||||
xml.writeAttribute("fo:border-top", "none");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* 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-top", "none");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
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;
|
||||
tableName.replace(' ', '_'); //Replace spaces with underscores
|
||||
tableName.replace(' ', '_'); // Replace spaces with underscores
|
||||
tableName.append("_table");
|
||||
|
||||
xml.writeStartElement("table:table");
|
||||
xml.writeAttribute("table:name", tableName);
|
||||
xml.writeAttribute("table:style-name", "rs_5f_table");
|
||||
|
||||
//Columns
|
||||
xml.writeEmptyElement("table:table-column"); //A - RS Name
|
||||
// Columns
|
||||
xml.writeEmptyElement("table:table-column"); // A - RS Name
|
||||
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.writeEmptyElement("table:table-column"); //C - Platf
|
||||
xml.writeEmptyElement("table:table-column"); // C - Platf
|
||||
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.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");
|
||||
|
||||
//Row 1 (Heading)
|
||||
// Row 1 (Heading)
|
||||
xml.writeStartElement("table:table-header-rows");
|
||||
xml.writeStartElement("table:table-row");
|
||||
|
||||
const QString P4_style = QStringLiteral("P4");
|
||||
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::jobNr));
|
||||
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.E1", P4_style, Odt::text(m_order == SessionRSOrder::ByStation ? Odt::genericRSOwner : Odt::station));
|
||||
writeCell(xml, "rs_5f_table.A1", P4_style,
|
||||
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(); //header section
|
||||
xml.writeEndElement(); // end of row
|
||||
xml.writeEndElement(); // header section
|
||||
|
||||
//Fill the table
|
||||
for(; it != q_getSessionRS.end(); ++it)
|
||||
// Fill the table
|
||||
for (; it != q_getSessionRS.end(); ++it)
|
||||
{
|
||||
auto rs = *it;
|
||||
QTime time = rs.get<QTime>(0); //Departure or arrival
|
||||
auto rs = *it;
|
||||
QTime time = rs.get<QTime>(0); // Departure or arrival
|
||||
|
||||
//db_id stationOrOwnerId = rs.get<db_id>(1);
|
||||
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 stationOrOwnerId = rs.get<db_id>(1);
|
||||
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 rsId = rs.get<db_id>(4);
|
||||
int number = rs.get<int>(5);
|
||||
sqlite3_stmt *stmt = q_getSessionRS.stmt();
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 6);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 6));
|
||||
// db_id rsId = rs.get<db_id>(4);
|
||||
int number = rs.get<int>(5);
|
||||
sqlite3_stmt *stmt = q_getSessionRS.stmt();
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 6);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 6));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 7);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 7));
|
||||
RsType type = RsType(rs.get<int>(8));
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 7);
|
||||
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 7));
|
||||
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);
|
||||
if(platform.isEmpty())
|
||||
platform = rs.get<QString>(10); //Use out gate to get track name
|
||||
if (platform.isEmpty())
|
||||
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));
|
||||
|
||||
if(parentId != lastParentId)
|
||||
if (parentId != lastParentId)
|
||||
{
|
||||
xml.writeEndElement(); //table:table
|
||||
xml.writeEndElement(); // table:table
|
||||
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, 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.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)
|
||||
{
|
||||
it = q_getSessionRS.begin();
|
||||
if(it == q_getSessionRS.end())
|
||||
if (it == q_getSessionRS.end())
|
||||
return;
|
||||
|
||||
lastParentId = (*it).get<db_id>(3);
|
||||
|
@ -334,7 +333,7 @@ void SessionRSWriter::writeContent(QXmlStreamWriter &xml)
|
|||
QString name = q_getParentName.getRows().get<QString>(0);
|
||||
q_getParentName.reset();
|
||||
|
||||
//Write Station or Rollingstock Owner name
|
||||
// Write Station or Rollingstock Owner name
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", "P1");
|
||||
xml.writeCharacters(name);
|
||||
|
@ -342,7 +341,7 @@ void SessionRSWriter::writeContent(QXmlStreamWriter &xml)
|
|||
|
||||
lastParentId = writeTable(xml, name);
|
||||
|
||||
//Add some space
|
||||
// Add some space
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", "P1");
|
||||
xml.writeEndElement();
|
||||
|
@ -351,8 +350,10 @@ void SessionRSWriter::writeContent(QXmlStreamWriter &xml)
|
|||
|
||||
QString SessionRSWriter::generateTitle() const
|
||||
{
|
||||
QString title = Odt::text(Odt::rsSessionTitle).arg(
|
||||
Odt::text(m_order == SessionRSOrder::ByStation ? Odt::genericRSOwner : Odt::station),
|
||||
Odt::text(m_mode == SessionRSMode::StartOfSession ? Odt::rsSessionStart : Odt::rsSessionEnd));
|
||||
QString title =
|
||||
Odt::text(Odt::rsSessionTitle)
|
||||
.arg(Odt::text(m_order == SessionRSOrder::ByStation ? Odt::genericRSOwner : Odt::station),
|
||||
Odt::text(m_mode == SessionRSMode::StartOfSession ? Odt::rsSessionStart
|
||||
: Odt::rsSessionEnd));
|
||||
return title;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
@ -30,46 +30,48 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
//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
|
||||
void StationWriter::insertStop(QXmlStreamWriter &xml, const Stop& stop, bool first, bool transit)
|
||||
// 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
|
||||
void StationWriter::insertStop(QXmlStreamWriter &xml, const Stop &stop, bool first, bool transit)
|
||||
{
|
||||
const QString P3_style = "P3";
|
||||
|
||||
//Row
|
||||
// Row
|
||||
xml.writeStartElement("table:table-row");
|
||||
|
||||
//Cells, hide Arrival the second time
|
||||
if(first)
|
||||
// Cells, hide Arrival the second time
|
||||
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"));
|
||||
|
||||
//Departure, if transit don't repeat it
|
||||
writeCell(xml, "stationtable.A2", P3_style, transit ? "-/-" : stop.departure.toString("HH:mm"));
|
||||
// Departure, if transit don't repeat it
|
||||
writeCell(xml, "stationtable.A2", P3_style,
|
||||
transit ? "-/-" : stop.departure.toString("HH:mm"));
|
||||
}
|
||||
else
|
||||
{
|
||||
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", P3_style, QString()); // Don't repeat Arrival
|
||||
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, 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, stop.nextSt);
|
||||
|
||||
if(!first)
|
||||
if (!first)
|
||||
{
|
||||
//Fill with empty cells, needed to keep the order
|
||||
writeCell(xml, "stationtable.A2", P3_style, QString()); //Rollingstock
|
||||
writeCell(xml, "stationtable.A2", P3_style, QString()); //Crossings
|
||||
writeCell(xml, "stationtable.A2", P3_style, QString()); //Passings
|
||||
// Fill with empty cells, needed to keep the order
|
||||
writeCell(xml, "stationtable.A2", P3_style, QString()); // Rollingstock
|
||||
writeCell(xml, "stationtable.A2", P3_style, QString()); // Crossings
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +99,8 @@ StationWriter::StationWriter(database &db) :
|
|||
q_selectPassings(mDb, "SELECT stops.id,stops.job_id,jobs.category"
|
||||
" FROM stops"
|
||||
" 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,"
|
||||
"rs_list.number,rs_models.name,rs_models.suffix,rs_models.type"
|
||||
" FROM coupling"
|
||||
|
@ -105,22 +108,21 @@ StationWriter::StationWriter(database &db) :
|
|||
" JOIN rs_models ON rs_models.id=rs_list.model_id"
|
||||
" 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)
|
||||
{
|
||||
/* Style: stationtable
|
||||
*
|
||||
* Type: table
|
||||
* Display name: Station Table
|
||||
* Align: center
|
||||
* Width: 20.0cm
|
||||
*
|
||||
* Usage:
|
||||
* - StationWriter: station sheet main table showing jobs that stop in this station
|
||||
*/
|
||||
*
|
||||
* Type: table
|
||||
* Display name: Station Table
|
||||
* Align: center
|
||||
* Width: 20.0cm
|
||||
*
|
||||
* Usage:
|
||||
* - StationWriter: station sheet main table showing jobs that stop in this station
|
||||
*/
|
||||
xml.writeStartElement("style:style");
|
||||
xml.writeAttribute("style:family", "table");
|
||||
xml.writeAttribute("style:name", "stationtable");
|
||||
|
@ -129,20 +131,20 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("style:shadow", "none");
|
||||
xml.writeAttribute("table:align", "center");
|
||||
xml.writeAttribute("style:width", "20.0cm");
|
||||
xml.writeEndElement(); //style:table-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
//stationtable columns
|
||||
writeColumnStyle(xml, "stationtable.A", "1.74cm"); //1 Arrival
|
||||
writeColumnStyle(xml, "stationtable.B", "1.80cm"); //2 Departure
|
||||
writeColumnStyle(xml, "stationtable.C", "1.93cm"); //3 Job N
|
||||
writeColumnStyle(xml, "stationtable.D", "1.00cm"); //4 Platform (Platf)
|
||||
writeColumnStyle(xml, "stationtable.E", "3.09cm"); //5 From (Previous Station)
|
||||
writeColumnStyle(xml, "stationtable.F", "3.11cm"); //6 To (Next Station)
|
||||
writeColumnStyle(xml, "stationtable.G", "3.00cm"); //7 Rollingstock
|
||||
writeColumnStyle(xml, "stationtable.H", "2.10cm"); //8 Crossings
|
||||
writeColumnStyle(xml, "stationtable.I", "2.10cm"); //9 Passings
|
||||
writeColumnStyle(xml, "stationtable.L", "2.21cm"); //10 Description
|
||||
// stationtable columns
|
||||
writeColumnStyle(xml, "stationtable.A", "1.74cm"); // 1 Arrival
|
||||
writeColumnStyle(xml, "stationtable.B", "1.80cm"); // 2 Departure
|
||||
writeColumnStyle(xml, "stationtable.C", "1.93cm"); // 3 Job N
|
||||
writeColumnStyle(xml, "stationtable.D", "1.00cm"); // 4 Platform (Platf)
|
||||
writeColumnStyle(xml, "stationtable.E", "3.09cm"); // 5 From (Previous Station)
|
||||
writeColumnStyle(xml, "stationtable.F", "3.11cm"); // 6 To (Next Station)
|
||||
writeColumnStyle(xml, "stationtable.G", "3.00cm"); // 7 Rollingstock
|
||||
writeColumnStyle(xml, "stationtable.H", "2.10cm"); // 8 Crossings
|
||||
writeColumnStyle(xml, "stationtable.I", "2.10cm"); // 9 Passings
|
||||
writeColumnStyle(xml, "stationtable.L", "2.21cm"); // 10 Description
|
||||
|
||||
/* 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-bottom", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: stationtable.L1
|
||||
*
|
||||
|
@ -186,8 +188,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border", "0.05pt solid #000000");
|
||||
xml.writeAttribute("fo:padding", "0.097cm");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: stationtable.A2
|
||||
*
|
||||
|
@ -210,8 +212,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-top", "none");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style: stationtable.L2
|
||||
*
|
||||
|
@ -234,8 +236,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeAttribute("fo:border-top", "none");
|
||||
xml.writeAttribute("fo:border-bottom", "0.05pt solid #000000");
|
||||
xml.writeAttribute("style:vertical-align", "middle");
|
||||
xml.writeEndElement(); //style:table-cell-properties
|
||||
xml.writeEndElement(); //style
|
||||
xml.writeEndElement(); // style:table-cell-properties
|
||||
xml.writeEndElement(); // style
|
||||
|
||||
/* Style P2
|
||||
* type: paragraph
|
||||
|
@ -253,14 +255,14 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "center");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
xml.writeAttribute("fo:font-size", "13pt");
|
||||
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
|
||||
* type: paragraph
|
||||
|
@ -277,15 +279,15 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "center");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
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
|
||||
* type: paragraph
|
||||
* text-align: center
|
||||
|
@ -294,7 +296,8 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
|||
* font-style: italic
|
||||
*
|
||||
* 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.writeAttribute("style:family", "paragraph");
|
||||
|
@ -303,20 +306,20 @@ void StationWriter::writeStationAutomaticStyles(QXmlStreamWriter &xml)
|
|||
xml.writeStartElement("style:paragraph-properties");
|
||||
xml.writeAttribute("fo:text-align", "center");
|
||||
xml.writeAttribute("style:justify-single-word", "false");
|
||||
xml.writeEndElement(); //style:paragraph-properties
|
||||
xml.writeEndElement(); // style:paragraph-properties
|
||||
|
||||
xml.writeStartElement("style:text-properties");
|
||||
xml.writeAttribute("fo:font-size", "12pt");
|
||||
xml.writeAttribute("fo:font-weight", "bold");
|
||||
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)
|
||||
{
|
||||
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=?");
|
||||
|
||||
|
@ -328,71 +331,71 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
|||
QString stationName;
|
||||
QString shortName;
|
||||
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);
|
||||
shortName = r.get<QString>(1);
|
||||
shortName = r.get<QString>(1);
|
||||
}
|
||||
q_getStName.reset();
|
||||
if(stNameOut)
|
||||
if (stNameOut)
|
||||
*stNameOut = stationName;
|
||||
|
||||
QString stationNameStr = stationName;
|
||||
if(!shortName.isEmpty())
|
||||
if (!shortName.isEmpty())
|
||||
{
|
||||
stationNameStr.append(QLatin1String(" ("));
|
||||
stationNameStr.append(shortName);
|
||||
stationNameStr.append(')');
|
||||
}
|
||||
|
||||
//Title
|
||||
// Title
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", "P1");
|
||||
xml.writeCharacters(Odt::text(Odt::stationPageTitle).arg(stationNameStr));
|
||||
xml.writeEndElement();
|
||||
|
||||
//Vertical space
|
||||
// Vertical space
|
||||
xml.writeStartElement("text:p");
|
||||
xml.writeAttribute("text:style-name", "P1");
|
||||
xml.writeEndElement();
|
||||
|
||||
//stationtable
|
||||
// stationtable
|
||||
xml.writeStartElement("table:table");
|
||||
//xml.writeAttribute("table:name", "stationtable");
|
||||
// xml.writeAttribute("table: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.writeEmptyElement("table:table-column"); //Departure
|
||||
xml.writeEmptyElement("table:table-column"); // Departure
|
||||
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.writeEmptyElement("table:table-column"); //Platform (Bin)
|
||||
xml.writeEmptyElement("table:table-column"); // Platform (Bin)
|
||||
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.writeEmptyElement("table:table-column"); //Goes To
|
||||
xml.writeEmptyElement("table:table-column"); // Goes To
|
||||
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.writeEmptyElement("table:table-column"); //Crossings
|
||||
xml.writeEmptyElement("table:table-column"); // Crossings
|
||||
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.writeEmptyElement("table:table-column"); //Notes
|
||||
xml.writeEmptyElement("table:table-column"); // Notes
|
||||
xml.writeAttribute("table:style-name", "stationtable.L");
|
||||
|
||||
//Row 1 (Heading)
|
||||
// Row 1 (Heading)
|
||||
xml.writeStartElement("table:table-header-rows");
|
||||
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::jobStopCrossShort));
|
||||
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(); //header section
|
||||
xml.writeEndElement(); // end of row
|
||||
xml.writeEndElement(); // header section
|
||||
|
||||
//Stops
|
||||
// Stops
|
||||
q_getJobsByStation.bind(1, stationId);
|
||||
for(auto r : q_getJobsByStation)
|
||||
for (auto r : q_getJobsByStation)
|
||||
{
|
||||
db_id stopId = r.get<db_id>(0);
|
||||
Stop stop;
|
||||
stop.jobId = r.get<db_id>(1);
|
||||
stop.jobCat = JobCategory(r.get<int>(2));
|
||||
stop.arrival = r.get<QTime>(3);
|
||||
stop.departure = r.get<QTime>(4);
|
||||
stop.jobId = r.get<db_id>(1);
|
||||
stop.jobCat = JobCategory(r.get<int>(2));
|
||||
stop.arrival = r.get<QTime>(3);
|
||||
stop.departure = r.get<QTime>(4);
|
||||
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);
|
||||
if(stop.platform.isEmpty())
|
||||
stop.platform = r.get<QString>(8); //Use out gate to get track name
|
||||
stop.platform = r.get<QString>(7);
|
||||
if (stop.platform.isEmpty())
|
||||
stop.platform = r.get<QString>(8); // Use out gate to get track name
|
||||
|
||||
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);
|
||||
if(!stop.description.isEmpty())
|
||||
descr2.append('\n'); //Separate from manually set description
|
||||
if (!stop.description.isEmpty())
|
||||
descr2.append('\n'); // Separate from manually set description
|
||||
descr2.append(stop.description);
|
||||
stop.description = descr2;
|
||||
}
|
||||
|
||||
const bool isTransit = stopType == 1;
|
||||
|
||||
//BIG TODO: if this is First or Last stop of this job
|
||||
//then it shouldn't be duplicated in 2 rows
|
||||
// BIG TODO: if this is First or Last stop of this job
|
||||
// then it shouldn't be duplicated in 2 rows
|
||||
|
||||
//Comes from station
|
||||
// Comes from station
|
||||
q_getPrevStop.bind(1, stop.jobId);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
@ -460,14 +464,14 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
|||
}
|
||||
q_getPrevStop.reset();
|
||||
|
||||
//Goes to station
|
||||
// Goes to station
|
||||
q_getNextStop.bind(1, stop.jobId);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
@ -475,62 +479,60 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
|||
}
|
||||
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->departure >= stop.arrival)
|
||||
// If 's' departs after 'stop' arrives then skip 's' for now
|
||||
if (s->departure >= stop.arrival)
|
||||
{
|
||||
++s;
|
||||
continue;
|
||||
}
|
||||
|
||||
//'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);
|
||||
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);
|
||||
}
|
||||
|
||||
//Fill with basic data
|
||||
// Fill with basic data
|
||||
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();
|
||||
writeCellListStart(xml, "stationtable.A2", "P3");
|
||||
|
||||
//Coupled rollingstock
|
||||
// Coupled rollingstock
|
||||
bool firstCoupRow = true;
|
||||
q_getStopCouplings.bind(1, stopId);
|
||||
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 modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
||||
int number = coup.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 3));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 3));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||
|
||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
||||
number,
|
||||
modelSuffix, modelSuffixLen,
|
||||
type);
|
||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||
modelSuffix, modelSuffixLen, type);
|
||||
|
||||
if(firstCoupRow)
|
||||
if (firstCoupRow)
|
||||
{
|
||||
firstCoupRow = false;
|
||||
//Use bold font
|
||||
// Use bold font
|
||||
xml.writeStartElement("text:span");
|
||||
xml.writeAttribute("text:style-name", "T1");
|
||||
xml.writeCharacters(Odt::text(Odt::CoupledAbbr));
|
||||
xml.writeEndElement(); //test:span
|
||||
xml.writeEndElement(); // test:span
|
||||
}
|
||||
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
|
@ -538,38 +540,36 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
|||
}
|
||||
q_getStopCouplings.reset();
|
||||
|
||||
//Unoupled rollingstock
|
||||
// Unoupled rollingstock
|
||||
bool firstUncoupRow = true;
|
||||
q_getStopCouplings.bind(1, stopId);
|
||||
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 modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelName = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 2));
|
||||
int number = coup.get<int>(1);
|
||||
int modelNameLen = sqlite3_column_bytes(stmt, 2);
|
||||
const char *modelName = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 2));
|
||||
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||
const char *modelSuffix = reinterpret_cast<char const*>(sqlite3_column_text(stmt, 3));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||
int modelSuffixLen = sqlite3_column_bytes(stmt, 3);
|
||||
const char *modelSuffix = reinterpret_cast<char const *>(sqlite3_column_text(stmt, 3));
|
||||
RsType type = RsType(sqlite3_column_int(stmt, 4));
|
||||
|
||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen,
|
||||
number,
|
||||
modelSuffix, modelSuffixLen,
|
||||
type);
|
||||
const QString rsName = rs_utils::formatNameRef(modelName, modelNameLen, number,
|
||||
modelSuffix, modelSuffixLen, type);
|
||||
|
||||
if(firstUncoupRow)
|
||||
if (firstUncoupRow)
|
||||
{
|
||||
if(!firstCoupRow) //Not first row, there were coupled rs
|
||||
xml.writeEmptyElement("text:line-break"); //Separate from coupled
|
||||
if (!firstCoupRow) // Not first row, there were coupled rs
|
||||
xml.writeEmptyElement("text:line-break"); // Separate from coupled
|
||||
firstUncoupRow = false;
|
||||
|
||||
//Use bold font
|
||||
// Use bold font
|
||||
xml.writeStartElement("text:span");
|
||||
xml.writeAttribute("text:style-name", "T1");
|
||||
xml.writeCharacters(Odt::text(Odt::UncoupledAbbr));
|
||||
xml.writeEndElement(); //test:span
|
||||
xml.writeEndElement(); // test:span
|
||||
}
|
||||
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
|
@ -578,7 +578,7 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
|||
q_getStopCouplings.reset();
|
||||
writeCellListEnd(xml);
|
||||
|
||||
//Crossings, Passings
|
||||
// Crossings, Passings
|
||||
QVector<JobEntry> passings;
|
||||
JobStopDirectionHelper dirHelper(mDb);
|
||||
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);
|
||||
firstCoupRow = true;
|
||||
|
||||
//Incroci
|
||||
// Incroci
|
||||
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 otherJobId = pass.get<db_id>(1);
|
||||
db_id otherStopId = pass.get<db_id>(0);
|
||||
db_id otherJobId = pass.get<db_id>(1);
|
||||
JobCategory otherJobCat = JobCategory(pass.get<int>(2));
|
||||
|
||||
//QTime otherArr = pass.get<QTime>(3);
|
||||
//QTime otherDep = pass.get<QTime>(4);
|
||||
// QTime otherArr = pass.get<QTime>(3);
|
||||
// QTime otherDep = pass.get<QTime>(4);
|
||||
|
||||
utils::Side otherDir = dirHelper.getStopOutSide(otherStopId);
|
||||
|
||||
if(myDirection == otherDir)
|
||||
if (myDirection == otherDir)
|
||||
passings.append({otherJobId, otherJobCat});
|
||||
else
|
||||
{
|
||||
if(firstCoupRow)
|
||||
if (firstCoupRow)
|
||||
firstCoupRow = false;
|
||||
else
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
|
@ -616,12 +616,12 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
|||
q_selectPassings.reset();
|
||||
writeCellListEnd(xml);
|
||||
|
||||
//Passings
|
||||
// Passings
|
||||
firstCoupRow = true;
|
||||
writeCellListStart(xml, "stationtable.A2", "P3");
|
||||
for(auto entry : passings)
|
||||
for (auto entry : passings)
|
||||
{
|
||||
if(firstCoupRow)
|
||||
if (firstCoupRow)
|
||||
firstCoupRow = false;
|
||||
else
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
|
@ -629,66 +629,66 @@ void StationWriter::writeStation(QXmlStreamWriter &xml, db_id stationId, QString
|
|||
}
|
||||
writeCellListEnd(xml);
|
||||
|
||||
//Description, Notes
|
||||
// Description, Notes
|
||||
writeCellListStart(xml, "stationtable.L2", "P3");
|
||||
bool needsLineBreak = false;
|
||||
if(isTransit)
|
||||
if (isTransit)
|
||||
{
|
||||
xml.writeCharacters(Odt::text(Odt::jobStopIsTransit));
|
||||
needsLineBreak = true;
|
||||
}
|
||||
if(stop.prevSt.isEmpty())
|
||||
if (stop.prevSt.isEmpty())
|
||||
{
|
||||
if(needsLineBreak)
|
||||
if (needsLineBreak)
|
||||
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.writeAttribute("text:style-name", "T1");
|
||||
xml.writeCharacters(Odt::text(Odt::jobStopIsFirst));
|
||||
xml.writeEndElement(); //test:span
|
||||
xml.writeEndElement(); // test:span
|
||||
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");
|
||||
|
||||
//Split in lines
|
||||
// Split in lines
|
||||
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);
|
||||
xml.writeCharacters(line.simplified());
|
||||
if(idx < 0)
|
||||
break; //Last line
|
||||
if (idx < 0)
|
||||
break; // Last line
|
||||
lastIdx = idx + 1;
|
||||
xml.writeEmptyElement("text:line-break");
|
||||
}
|
||||
}
|
||||
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)
|
||||
//insert two rows: one for arrival and another
|
||||
//that reminds the station master (capostazione)
|
||||
//the departure of that train
|
||||
//In order to achieve this we put the stop in a list
|
||||
//and write it again before another arrival (see above)
|
||||
// If it is a normal stop (not a transit and not first stop or last stop)
|
||||
// insert two rows: one for arrival and another
|
||||
// that reminds the station master (capostazione)
|
||||
// the departure of that train
|
||||
// In order to achieve this we put the stop in a list
|
||||
// and write it again before another arrival (see above)
|
||||
stops.insert(stop.departure, stop);
|
||||
}
|
||||
}
|
||||
q_getJobsByStation.reset();
|
||||
|
||||
for(const Stop& s : stops)
|
||||
for (const Stop &s : stops)
|
||||
{
|
||||
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
|
||||
{
|
||||
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);
|
||||
|
||||
|
@ -54,7 +54,7 @@ private:
|
|||
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:
|
||||
database &mDb;
|
||||
|
|
|
@ -30,7 +30,6 @@ JobSheetExport::JobSheetExport(db_id jobId, JobCategory cat) :
|
|||
m_jobId(jobId),
|
||||
m_jobCat(cat)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void JobSheetExport::write()
|
||||
|
@ -38,27 +37,27 @@ void JobSheetExport::write()
|
|||
qDebug() << "TEMP:" << odt.dir.path();
|
||||
odt.initDocument();
|
||||
|
||||
//styles.xml font declarations
|
||||
// styles.xml font declarations
|
||||
odt.stylesXml.writeStartElement("office:font-face-decls");
|
||||
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");
|
||||
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");
|
||||
JobWriter::writeJobAutomaticStyles(odt.contentXml);
|
||||
|
||||
//Styles
|
||||
// Styles
|
||||
odt.stylesXml.writeStartElement("office:styles");
|
||||
writeCommonStyles(odt.stylesXml);
|
||||
JobWriter::writeJobStyles(odt.stylesXml);
|
||||
odt.stylesXml.writeEndElement();
|
||||
|
||||
//Body
|
||||
// Body
|
||||
odt.startBody();
|
||||
|
||||
JobWriter w(Session->m_Db);
|
||||
|
|
|
@ -24,14 +24,13 @@
|
|||
|
||||
#include "utils/types.h"
|
||||
|
||||
|
||||
class JobSheetExport
|
||||
{
|
||||
public:
|
||||
JobSheetExport(db_id jobId, JobCategory cat);
|
||||
|
||||
void write();
|
||||
void save(const QString& fileName);
|
||||
void save(const QString &fileName);
|
||||
|
||||
private:
|
||||
OdtDocument odt;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue