Beispiel #1
0
QVariantMap ReceiptsPlugin::readCardTablesData(int card_id)
{
	qfLogFuncFrame() << card_id;
	QVariantMap ret;
	CardReader::ReadCard read_card = cardReaderPlugin()->readCard(card_id);
	{
		qfu::TreeTable tt;
		tt.appendColumn("position", QVariant::Int);
		tt.appendColumn("code", QVariant::Int);
		tt.appendColumn("punchTimeMs", QVariant::Int);
		tt.appendColumn("stpTimeMs", QVariant::Int);
		tt.appendColumn("lapTimeMs", QVariant::Int);
 		QMapIterator<QString, QVariant> it(read_card);
		while(it.hasNext()) {
			it.next();
			if(it.key() != QLatin1String("punches"))
				tt.setValue(it.key(), it.value());
		}
		int position = 0;
		int start_time_ms = read_card.startTime();
		if(start_time_ms == 0xeeee)
			start_time_ms = read_card.checkTime();
		start_time_ms *= 1000;
		int prev_stp_time_ms = 0;
		for(auto v : read_card.punches()) {
			CardReader::ReadPunch punch(v.toMap());
			int punch_time_ms = punch.time() * 1000 + punch.msec();
			int stp_time_ms = quickevent::og::TimeMs::msecIntervalAM(start_time_ms, punch_time_ms);
			qfu::TreeTableRow ttr = tt.appendRow();
			++position;
			int code = punch.code();
			ttr.setValue("position", position);
			ttr.setValue("code", code);
			ttr.setValue("punchTimeMs", punch_time_ms);
			ttr.setValue("stpTimeMs", stp_time_ms);
			ttr.setValue("lapTimeMs", stp_time_ms - prev_stp_time_ms);
			prev_stp_time_ms = stp_time_ms;
		}
		{
			qf::core::sql::QueryBuilder qb;
			qb.select2("config", "ckey, cvalue, ctype")
					.from("config")
					.where("ckey LIKE 'event.%'");
			qf::core::sql::Query q;
			q.exec(qb.toString());
			while(q.next()) {
				QVariant v = qf::core::Utils::retypeStringValue(q.value("cvalue").toString(), q.value("ctype").toString());
				tt.setValue(q.value("ckey").toString(), v);
			}
		}
		tt.setValue("stageCount", eventPlugin()->stageCount());
		tt.setValue("currentStageId", eventPlugin()->currentStageId());
		qfDebug() << "card:\n" << tt.toString();
		ret["card"] = tt.toVariant();
	}
	return ret;
}
Beispiel #2
0
bool ResultsExporter::exportResults()
{
	ResultsExporterSettings ss = settings();
	if(!QDir().mkpath(ss.exportDir())) {
		qfError() << "Cannot create export dir:" << ss.exportDir();
		return false;
	}
	qfInfo() << "ResultsExporter export dir:" << ss.exportDir();
	if(ss.outputFormat() == static_cast<int>(ResultsExporterSettings::OutputFormat::CSOS)) {
		int current_stage = eventPlugin()->currentStageId();
		QString fn = ss.exportDir() + "/results-csos.txt";
		runsPlugin()->exportResultsCsosStage(current_stage, fn);
		return true;
	}
	if(ss.outputFormat() == static_cast<int>(ResultsExporterSettings::OutputFormat::IofXml3)) {
		int current_stage = eventPlugin()->currentStageId();
		QString fn = ss.exportDir() + "/results-csos.txt";
		runsPlugin()->exportResultsIofXml30Stage(current_stage, fn);
		return true;
	}
	else if(ss.outputFormat() == static_cast<int>(ResultsExporterSettings::OutputFormat::HtmlMulti)) {
		quickevent::core::exporters::StageResultsHtmlExporter exp;
		exp.setOutDir(ss.exportDir());
		exp.generateHtml();

		QString cmd = ss.whenFinishedRunCmd();
		if(!cmd.isEmpty()) {
			qfInfo() << "Starting process:" << cmd;
			QProcess *proc = new QProcess();
			connect(proc, &QProcess::readyReadStandardOutput, [proc]() {
				QByteArray ba = proc->readAllStandardOutput();
				qfInfo().noquote() << "PROC stdout:" << ba;
			});
			connect(proc, &QProcess::readyReadStandardError, [proc]() {
				QByteArray ba = proc->readAllStandardError();
				qfWarning().noquote() << "PROC stderr:" << ba;
			});
			connect(proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [proc](int exit_code, QProcess::ExitStatus exit_status) {
				if(exit_status == QProcess::ExitStatus::CrashExit)
					qfError() << "PROC crashed";
				else
					qfInfo() << "PROC finished with exit code:" << exit_code;
				proc->deleteLater();
			});

			proc->start(cmd);
		}
		return true;
	}
	qfError() << "Unsupported output format:" << ss.outputFormat();
	return false;
}
Beispiel #3
0
void ReceiptsWidget::settleDownInPartWidget(ReceiptsPartWidget *part_widget)
{
	connect(part_widget, SIGNAL(resetPartRequest()), this, SLOT(reset()));
	connect(part_widget, SIGNAL(reloadPartRequest()), this, SLOT(reset()));

	connect(eventPlugin(), &Event::EventPlugin::dbEventNotify, this, &ReceiptsWidget::onDbEventNotify, Qt::QueuedConnection);
}
Beispiel #4
0
bool ClassDocument::saveData()
{
	RecordEditMode old_mode = mode();
	bool ret = Super::saveData();
	//Log.info("CompetitorDocument", saveData_qml, "ret:", ret, "old_mode", old_mode, "vs", DataDocument.ModeInsert, old_mode == DataDocument.ModeInsert);
	if(ret) {
		if(old_mode == DataDocument::ModeInsert) {
			// insert classdefs
			int class_id = dataId().toInt();
			//int si_id = value("competitors.siId").toInt();

			auto *event_plugin = eventPlugin();
			QF_ASSERT(event_plugin != nullptr, "invalid Event plugin type", return false);

			int stage_count = event_plugin->stageCount();
			qf::core::sql::Query q(model()->connectionName());
			q.prepare("INSERT INTO classdefs (classId, stageId) VALUES (:classId, :stageId)");
			for(int i=0; i<stage_count; i++) {
				q.bindValue(":classId", class_id);
				q.bindValue(":stageId", i + 1);
				if(!q.exec()) {
					qfError() << q.lastError().text();
					break;
				}
			}
		}
	}
Beispiel #5
0
void ReceiptsWidget::settleDownInPartWidget(ReceiptsPartWidget *part_widget)
{
	connect(part_widget, SIGNAL(resetPartRequest()), this, SLOT(reset()));
	connect(part_widget, SIGNAL(reloadPartRequest()), this, SLOT(reset()));

	connect(eventPlugin(), SIGNAL(dbEventNotify(QString,QVariant)), this, SLOT(onDbEventNotify(QString,QVariant)), Qt::QueuedConnection);
}
Beispiel #6
0
void ReceiptsWidget::reset()
{
	if(!eventPlugin()->isEventOpen()) {
		m_cardsModel->clearRows();
		return;
	}
	reload();
}
Beispiel #7
0
void ReceiptsWidget::reset()
{
	if(eventPlugin()->eventName().isEmpty()) {
		m_cardsModel->clearRows();
		return;
	}
	reload();
}
Beispiel #8
0
void RelaysPlugin::onInstalled()
{
	qff::MainWindow *fwk = qff::MainWindow::frameWork();
	m_partWidget = new ThisPartWidget();
	fwk->addPartWidget(m_partWidget, manifest()->featureId());

	connect(eventPlugin(), &Event::EventPlugin::dbEventNotify, this, &RelaysPlugin::onDbEventNotify);

	emit nativeInstalled();
}
Beispiel #9
0
qf::core::utils::TreeTable RelaysPlugin::nlegsResultsTable(int leg_count, int places, bool exclude_not_finish)
{
	qf::core::utils::TreeTable tt;
	tt.setValue("event", eventPlugin()->eventConfig()->value("event"));
	tt.setValue("stageStart", eventPlugin()->stageStartDateTime(1));
	tt.appendColumn("className", QVariant::String);
	qfs::QueryBuilder qb;
	qb.select2("classes", "id, name")
			.from("classes")
			.orderBy("classes.name");
	qfs::Query q;
	q.execThrow(qb.toString());
	while(q.next()) {
		qf::core::utils::TreeTableRow rr = tt.appendRow();
		rr.setValue("className", q.value("classes.name"));
		qf::core::utils::TreeTable tt2 = nlegsResultsTable(q.value("classes.id").toInt(), leg_count, places, exclude_not_finish);
		rr.appendTable(tt2);
	}
	return tt;
}
Beispiel #10
0
void ClassesWidget::reset()
{
	{
		m_cbxStage->blockSignals(true);
		m_cbxStage->clear();
		for(int i=0; i<eventPlugin()->stageCount(); i++)
			m_cbxStage->addItem(tr("E%1").arg(i+1), i+1);
		m_cbxStage->blockSignals(false);
		connect(m_cbxStage, SIGNAL(currentIndexChanged(int)), this, SLOT(reload()), Qt::UniqueConnection);
	}
	reload();
}
Beispiel #11
0
void ClassesWidget::reload()
{
	if(eventPlugin()->eventName().isEmpty()) {
		m_classesModel->clearRows();
		m_courseCodesModel->clearRows();
		return;
	}
	int stage_id = selectedStageId();
	{
		qf::core::sql::QueryBuilder qb1;
		qb1.select("COUNT(*)")
				.from("runs")
				.join("runs.competitorId", "competitors.id")
				.where("competitors.classId=classdefs.classId")
				.where("NOT runs.offRace")
				.where("runs.stageId=" QF_IARG(stage_id));
		qfs::QueryBuilder qb;
		qb.select2("classes", "*")
				.select2("classdefs", "*")
				.select2("courses", "id, name, length, climb")
				.select("(" + qb1.toString() + ") AS runsCount")
				.from("classes")
				.joinRestricted("classes.id", "classdefs.classId", "classdefs.stageId=" QF_IARG(stage_id))
				.join("classdefs.courseId", "courses.id")
				.orderBy("classes.name");//.limit(10);
		/*
		int class_id = m_cbxClasses->currentData().toInt();
		if(class_id > 0) {
			qb.where("competitors.classId=" + QString::number(class_id));
		}
		*/
		m_classesModel->setQueryBuilder(qb);
		m_classesModel->reload();
	}
	{
		qf::core::sql::Query q(m_classesModel->sqlConnection());
		q.exec("SELECT COUNT(*) FROM classdefs WHERE stageId=" QF_IARG(stage_id));
		bool ro = true;
		if(q.next())
			ro = (q.value(0).toInt() == 0);
		if(ro) {
			qfWarning() << tr("Courses are not imported, class table is read only.");
		}
		ui->tblClasses->setReadOnly(ro);
	}
	reloadCourseCodes();
}
void RunsTableDialogWidget::reload(int stage_id, int class_id, const QString &sort_column, int select_competitor_id)
{
	QString class_name = eventPlugin()->classNameById(class_id);
	setTitle(tr("Stage %1 Class %2").arg(stage_id).arg(class_name));
	runsTableWidget()->reload(stage_id, class_id, sort_column, select_competitor_id);
}
Beispiel #13
0
int CardChecker::cardCheckCheckTimeSec()
{
	return eventPlugin()->eventConfig()->cardCheckCheckTimeSec();
}
Beispiel #14
0
int CardChecker::stageIdForRun(int run_id)
{
	return eventPlugin()->stageIdForRun(run_id);
}
Beispiel #15
0
QVariantMap ReceiptsPlugin::receiptTablesData(int card_id)
{
	qfLogFuncFrame() << card_id;
	QF_TIME_SCOPE("receiptTablesData()");
	QVariantMap ret;
	CardReader::ReadCard read_card = cardReaderPlugin()->readCard(card_id);
	CardReader::CheckedCard checked_card = cardReaderPlugin()->checkCard(read_card);
	int current_stage_id = eventPlugin()->currentStageId();
	int run_id = checked_card.runId();
	int course_id = checked_card.courseId();
	int current_standings = 0;
	int competitors_finished = 0;
	QMap<int, int> best_laps; //< position->time
	///QMap<int, int> missing_codes; //< pos->code
	///QSet<int> out_of_order_codes;
	{
		qf::core::model::SqlTableModel model;
		qf::core::sql::QueryBuilder qb;
		qb.select2("competitors", "*")
				.select2("runs", "*")
				.select2("classes", "name")
				.select("COALESCE(competitors.lastName, '') || ' ' || COALESCE(competitors.firstName, '') AS competitorName")
				.from("runs")
				.join("runs.competitorId", "competitors.id")
				.join("competitors.classId", "classes.id")
				.where("runs.id=" QF_IARG(run_id));
		model.setQuery(qb.toString());
		model.reload();
		if(model.rowCount() == 1) {
			int class_id = model.value(0, "competitors.classId").toInt();
			{
				// find best laps for competitors class
				qf::core::sql::QueryBuilder qb_minlaps;
				// TODO: remove position field from DB in 0.1.5
				qb_minlaps.select("runlaps.position, MIN(runlaps.lapTimeMs) AS minLapTimeMs")
						.from("competitors")
						.joinRestricted("competitors.id", "runs.competitorId", "runs.stageId=" QF_IARG(current_stage_id) " AND competitors.classId=" QF_IARG(class_id), "JOIN")
						.joinRestricted("runs.id", "runlaps.runId", "runlaps.position > 0 AND runlaps.lapTimeMs > 0", "JOIN")
						.groupBy("runlaps.position");
				QString qs = qb_minlaps.toString();
				//qfInfo() << qs;
				qf::core::sql::Query q;
				q.exec(qs);
				while(q.next()) {
					int position = q.value("position").toInt();
					if(position == 0) {
						qfWarning() << "position == 0 in best runlaps";
						continue;
					}
					int lap = q.value("minLapTimeMs").toInt();
					if(lap == 0) {
						qfWarning() << "minLapTimeMs == 0 in best runlaps";
						continue;
					}
					best_laps[position] = lap;
					//qfInfo() << "bestlaps[" << pos << "] =" << lap;
				}
			}
			if(checked_card.isOk()) {
				// find current standings
				qf::core::sql::QueryBuilder qb;
				qb.select2("runs", "timeMs")
						.select("runs.disqualified OR NOT runs.isRunning OR runs.isRunning IS NULL OR runs.misPunch AS dis")
						.from("competitors")
						.joinRestricted("competitors.id", "runs.competitorId", "runs.stageId=" QF_IARG(current_stage_id) " AND competitors.classId=" QF_IARG(class_id))
						.where("runs.finishTimeMs > 0")
						.orderBy("misPunch, disqualified, isRunning, runs.timeMs");
				//qfInfo() << qb.toString();
				qf::core::sql::Query q;
				q.exec(qb.toString(), qf::core::Exception::Throw);
				while (q.next()) {
					bool dis = q.value("dis").toBool();
					int time = q.value("timeMs").toInt();
					if(!dis) {
						if(time <= checked_card.timeMs())
							current_standings++;
					}
					competitors_finished++;
				}
			}
		}
		qfu::TreeTable tt = model.toTreeTable();
		{
			qf::core::sql::QueryBuilder qb;
			qb.select2("courses", "length, climb")
					.select("(SELECT COUNT(*) FROM coursecodes WHERE courseId=courses.id) AS controlCount")
					.from("courses")
					.where("courses.id=" QF_IARG(course_id));
			qf::core::sql::Query q;
			q.exec(qb.toString());
			if(q.next()) {
				QSqlRecord rec = q.record();
				for (int i = 0; i < rec.count(); ++i) {
					QString fld_name = rec.fieldName(i);
					tt.setValue(fld_name, rec.value(i));
				}
			}
		}
		{
			qf::core::sql::QueryBuilder qb;
			qb.select2("config", "ckey, cvalue, ctype")
					.from("config")
					.where("ckey LIKE 'event.%'");
			qf::core::sql::Query q;
			q.exec(qb.toString());
			while(q.next()) {
				QVariant v = qf::core::Utils::retypeStringValue(q.value("cvalue").toString(), q.value("ctype").toString());
				tt.setValue(q.value("ckey").toString(), v);
			}
		}
		tt.setValue("stageCount", eventPlugin()->stageCount());
		tt.setValue("currentStageId", eventPlugin()->currentStageId());
		qfDebug() << "competitor:\n" << tt.toString();
		ret["competitor"] = tt.toVariant();
	}
	{
		qfu::TreeTable tt;
		tt.appendColumn("position", QVariant::Int);
		tt.appendColumn("code", QVariant::Int);
		tt.appendColumn("stpTimeMs", QVariant::Int);
		tt.appendColumn("lapTimeMs", QVariant::Int);
		tt.appendColumn("lossMs", QVariant::Int);
 		QMapIterator<QString, QVariant> it(checked_card);
		while(it.hasNext()) {
			it.next();
			if(it.key() != QLatin1String("punches"))
				tt.setValue(it.key(), it.value());
		}
		tt.setValue("isOk", checked_card.isOk());
		int position = 0;
		for(auto v : checked_card.punches()) {
			CardReader::CheckedPunch punch(v.toMap());
			qfu::TreeTableRow ttr = tt.appendRow();
			++position;
			int code = punch.code();
			ttr.setValue("position", position);
			ttr.setValue("code", code);
			ttr.setValue("stpTimeMs", punch.stpTimeMs());
			int lap = punch.lapTimeMs();
			ttr.setValue("lapTimeMs", lap);
			int best_lap = best_laps.value(position);
			if(lap > 0 && best_lap > 0) {
				int loss = lap - best_lap;
				ttr.setValue("lossMs", loss);
			}
		}
		/*
		{
			// runlaps table contains also finish time entry, it is under FINISH_PUNCH_POS
			// currently best_laps[999] contains best finish lap time for this class
			int loss = 0;
			int best_lap = best_laps.value(CardReader::CardReaderPlugin::FINISH_PUNCH_POS);
			if(best_lap > 0)
				loss = checked_card.finishLapTimeMs() - best_lap;
			//qfInfo() << "control_count:" << control_count << "finishLapTimeMs:" << checked_card.finishLapTimeMs() << "- best_lap:" << best_lap << "=" << loss;
			tt.setValue("finishLossMs", loss);
		}
		*/
		{
			QSet<int> correct_codes;
			for (int i = 0; i < checked_card.punchCount(); ++i) {
				correct_codes << checked_card.punchAt(i).code();
			}
			QVariantList xc;
			for (int i = 0; i < read_card.punchCount(); ++i) {
				int code = read_card.punchAt(i).code();
				if(!correct_codes.contains(code)) {
					xc.insert(xc.count(), QVariantList() << (i+1) << code);
				}
			}
			tt.setValue("extraCodes", xc);
		}
		tt.setValue("currentStandings", current_standings);
		tt.setValue("competitorsFinished", competitors_finished);
		tt.setValue("timeMs", checked_card.timeMs());

		qfDebug() << "card:\n" << tt.toString();
		ret["card"] = tt.toVariant();
	}
	return ret;
}
Beispiel #16
0
RacomClient::RacomClient(QObject *parent)
	: Super(RacomClient::serviceName(), parent)
{
	connect(eventPlugin(), &Event::EventPlugin::dbEventNotify, this, &RacomClient::onDbEventNotify, Qt::QueuedConnection);
}