JobMatchModel: new match model for jobs

Allows filtering by station
This commit is contained in:
Filippo Gentile 2023-01-10 19:23:49 +01:00
parent 49c7f60c94
commit 02f4938396
3 changed files with 337 additions and 0 deletions

View File

@ -3,6 +3,9 @@ set(MR_TIMETABLE_PLANNER_SOURCES
jobs/jobsmanager/model/joblistmodel.h
jobs/jobsmanager/model/joblistmodel.cpp
jobs/jobsmanager/model/jobmatchmodel.h
jobs/jobsmanager/model/jobmatchmodel.cpp
jobs/jobsmanager/model/jobshelper.h
jobs/jobsmanager/model/jobshelper.cpp
PARENT_SCOPE

View File

@ -0,0 +1,249 @@
#include "jobmatchmodel.h"
#include "utils/jobcategorystrings.h"
#include "app/session.h"
JobMatchModel::JobMatchModel(database &db, QObject *parent) :
ISqlFKMatchModel(parent),
mDb(db),
q_getMatches(mDb),
m_exceptJobId(0),
m_stopStationId(0),
m_maxStopArrival(),
m_defaultId(JobId)
{
m_font.setPointSize(13);
setHasEmptyRow(false);
}
int JobMatchModel::columnCount(const QModelIndex &p) const
{
if(p.isValid())
return 0;
if(!m_stopStationId)
return NCols - 1; //Hide stop arrival if no station filter is set
return NCols;
}
QVariant JobMatchModel::data(const QModelIndex &idx, int role) const
{
if (!idx.isValid() || idx.row() >= size)
return QVariant();
switch (role)
{
case Qt::DisplayRole:
{
switch (idx.column())
{
case JobCategoryCol:
{
if(isEllipsesRow(idx.row()))
{
break;
}
return JobCategoryName::shortName(items[idx.row()].stop.category);
}
case JobNumber:
{
if(isEllipsesRow(idx.row()))
{
return ellipsesString;
}
return items[idx.row()].stop.jobId;
}
case StopArrivalCol:
{
if(!m_stopStationId)
break; //Do not show stop arrival if not filtering by station
return items[idx.row()].stopArrival;
}
}
break;
}
case Qt::ForegroundRole:
{
if(isEllipsesRow(idx.row()))
{
break;
}
switch (idx.column())
{
case JobCategoryCol:
{
return Session->colorForCat(items[idx.row()].stop.category);
}
case JobNumber:
case StopArrivalCol:
return QColor(Qt::black);
}
break;
}
case Qt::FontRole:
{
switch (idx.column())
{
case JobCategoryCol:
{
QFont f = m_font;
f.setWeight(QFont::Bold);
return f;
}
case JobNumber:
case StopArrivalCol:
return m_font;
}
}
}
return QVariant();
}
void JobMatchModel::autoSuggest(const QString &text)
{
mQuery.clear();
if(!text.isEmpty())
{
mQuery.reserve(text.size() + 2);
mQuery.append('%');
mQuery.append(text.toUtf8());
mQuery.append('%');
}
refreshData();
}
void JobMatchModel::refreshData()
{
if(!mDb.db())
return;
beginResetModel();
char emptyQuery = '%';
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)
q_getMatches.bind(2, m_exceptJobId);
if(m_stopStationId)
{
q_getMatches.bind(3, m_stopStationId);
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++)
{
items[i].stop.jobId = (*it).get<db_id>(0);
items[i].stop.category = JobCategory((*it).get<int>(1));
if(m_stopStationId)
{
items[i].stop.stopId = (*it).get<db_id>(2);
items[i].stopArrival = (*it).get<QTime>(3);
}
++it;
}
size = i;
if(hasEmptyRow)
size++; //Items + Empty, add 1 row
if(it != end)
{
//There would be still rows, show Ellipses
size++; //Items + Empty + Ellispses
}
q_getMatches.reset();
endResetModel();
emit resultsReady(false);
}
QString JobMatchModel::getName(db_id jobId) const
{
if(!mDb.db())
return QString();
query q(mDb, "SELECT category FROM jobs WHERE id=?");
q.bind(1, jobId);
if(q.step() != SQLITE_ROW)
return QString();
JobCategory jobCat = JobCategory(q.getRows().get<int>(0));
return JobCategoryName::jobName(jobId, jobCat);
}
db_id JobMatchModel::getIdAtRow(int row) const
{
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);
}
void JobMatchModel::setFilter(db_id exceptJobId, db_id stopsInStationId, const QTime &maxStopArr)
{
m_exceptJobId = exceptJobId;
m_stopStationId = stopsInStationId;
m_maxStopArrival = maxStopArr;
QByteArray sql;
if(m_stopStationId)
{
//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())
sql += " stops.arrival < ?4 AND";
}
else
{
sql = "SELECT jobs.id, jobs.category FROM jobs WHERE";
}
if(exceptJobId)
{
//Filter out unwanted job ID
sql += " jobs.id<>?2 AND";
}
//Filter by name (job ID number)
//FIXME: filter also by category with regexp
sql += " jobs.id LIKE ?1";
sql += " ORDER BY ";
if(m_stopStationId)
{
sql += "stops.arrival, ";
}
sql += "jobs.category, jobs.id";
sql += " LIMIT " QT_STRINGIFY(MaxMatchItems + 1);
q_getMatches.prepare(sql);
}
void JobMatchModel::setDefaultId(DefaultId defaultId)
{
m_defaultId = defaultId;
}

View File

@ -0,0 +1,85 @@
#ifndef JOBMATCHMODEL_H
#define JOBMATCHMODEL_H
#include <QFont>
#include "utils/delegates/sql/isqlfkmatchmodel.h"
#include "utils/types.h"
#include <sqlite3pp/sqlite3pp.h>
using namespace sqlite3pp;
//TODO: share common code with SearchResultModel
//TODO: allow filter byy job category
/*!
* \brief Match model for Jobs
*
* Support filtering out 1 job (i.e. get 'others')
* or get only jobs which stop in a specific station.
* When specifying a station, you can also set a maximum time for arrival.
* All jobs arriving later are excluded.
* Otherwhise the arrival parameter is ignored if no station is set.
*/
class JobMatchModel : public ISqlFKMatchModel
{
Q_OBJECT
public:
enum Column
{
JobCategoryCol = 0,
JobNumber,
StopArrivalCol,
NCols
};
enum DefaultId : bool
{
JobId = 0,
StopId
};
JobMatchModel(database &db, QObject *parent = nullptr);
// Basic functionality:
int columnCount(const QModelIndex &p = QModelIndex()) const override;
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
// ISqlFKMatchModel:
void autoSuggest(const QString& text) override;
virtual void refreshData() override;
QString getName(db_id jobId) const override;
db_id getIdAtRow(int row) const override;
QString getNameAtRow(int row) const override;
// JobMatchModel:
void setFilter(db_id exceptJobId, db_id stopsInStationId, const QTime& maxStopArr);
void setDefaultId(DefaultId defaultId);
private:
struct JobItem
{
JobStopEntry stop;
QTime stopArrival;
};
JobItem items[MaxMatchItems];
database &mDb;
query q_getMatches;
db_id m_exceptJobId;
db_id m_stopStationId;
QTime m_maxStopArrival;
DefaultId m_defaultId;
QByteArray mQuery;
QFont m_font;
};
#endif // JOBMATCHMODEL_H