Add clang-format style file and format accordingly

remotes/origin/HEAD
markuspg 4 years ago
parent ea2e335f8f
commit d5fe3526d1

@ -0,0 +1,118 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

@ -25,366 +25,374 @@
#include <QRegularExpression> #include <QRegularExpression>
#include "client.h" #include "client.h"
#include "settings.h"
#include "lablib.h" #include "lablib.h"
#include "settings.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
extern std::unique_ptr< lc::Lablib > lablib; extern std::unique_ptr<lc::Lablib> lablib;
lc::Client::Client( const QString &argIP, const QString &argMAC, const QString &argName, lc::Client::Client(const QString &argIP, const QString &argMAC,
unsigned short int argXPosition, unsigned short int argYPosition, const QString &argName, unsigned short int argXPosition,
const QString &argPingCmd ): unsigned short int argYPosition, const QString &argPingCmd)
ip{ argIP }, : ip{argIP}, mac{argMAC}, name{argName}, xPosition{argXPosition},
mac{ argMAC }, yPosition{argYPosition}, protectedCycles{0} {
name{ argName }, qRegisterMetaType<state_t>("STATE");
xPosition{ argXPosition },
yPosition{ argYPosition }, if (!argPingCmd.isEmpty()) {
protectedCycles{ 0 } pinger = new ClientPinger{ip, argPingCmd};
{ pinger->moveToThread(&pingerThread);
qRegisterMetaType< state_t >( "STATE" ); connect(&pingerThread, &QThread::finished, pinger, &QObject::deleteLater);
connect(this, &Client::PingWanted, pinger, &ClientPinger::doPing);
if ( !argPingCmd.isEmpty() ) { connect(pinger, &ClientPinger::PingFinished, this,
pinger = new ClientPinger{ ip, argPingCmd }; &Client::GotStatusChanged);
pinger->moveToThread( &pingerThread ); pingerThread.start();
connect( &pingerThread, &QThread::finished,
pinger, &QObject::deleteLater ); pingTimer = new QTimer{this};
connect( this, &Client::PingWanted, connect(pingTimer, &QTimer::timeout, this, &Client::RequestAPing);
pinger, &ClientPinger::doPing ); pingTimer->start(3000);
connect( pinger, &ClientPinger::PingFinished, }
this, &Client::GotStatusChanged );
pingerThread.start(); qDebug() << "Created client" << name << "with MAC" << mac << "and IP" << ip
<< "at position"
pingTimer = new QTimer{ this }; << QString{QString::number(xPosition) + "x" +
connect( pingTimer, &QTimer::timeout, QString::number(yPosition)};
this, &Client::RequestAPing ) ;
pingTimer->start( 3000 );
}
qDebug() << "Created client" << name << "with MAC" << mac << "and IP" << ip
<< "at position" << QString{ QString::number( xPosition ) + "x"
+ QString::number( yPosition ) };
} }
lc::Client::~Client() { lc::Client::~Client() {
if ( pingTimer ) { if (pingTimer) {
pingTimer->stop(); pingTimer->stop();
} }
delete pingTimer; delete pingTimer;
pingerThread.quit(); pingerThread.quit();
pingerThread.wait(); pingerThread.wait();
} }
void lc::Client::BeamFile( const QString &argFileToBeam, const QString * const argPublickeyPathUser, const QString * const argUserNameOnClients ) { void lc::Client::BeamFile(const QString &argFileToBeam,
if ( state < state_t::RESPONDING ) { const QString *const argPublickeyPathUser,
return; const QString *const argUserNameOnClients) {
} if (state < state_t::RESPONDING) {
return;
QStringList arguments; }
arguments << "-2" << "-i" << *argPublickeyPathUser << "-l" << "32768" << "-r"
<< argFileToBeam << QString{ *argUserNameOnClients + "@" + ip + ":media4ztree" }; QStringList arguments;
arguments << "-2"
// Start the process << "-i" << *argPublickeyPathUser << "-l"
QProcess beamFileProcess; << "32768"
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); << "-r" << argFileToBeam
beamFileProcess.setProcessEnvironment( env ); << QString{*argUserNameOnClients + "@" + ip + ":media4ztree"};
beamFileProcess.startDetached( settings->scpCmd, arguments );
// Start the process
qDebug() << settings->scpCmd << arguments.join( " " ); QProcess beamFileProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
beamFileProcess.setProcessEnvironment(env);
beamFileProcess.startDetached(settings->scpCmd, arguments);
qDebug() << settings->scpCmd << arguments.join(" ");
} }
void lc::Client::Boot() { void lc::Client::Boot() {
QStringList arguments{ QStringList{} << "-i" << settings->netwBrdAddr << mac }; QStringList arguments{QStringList{} << "-i" << settings->netwBrdAddr << mac};
// Start the process // Start the process
QProcess wakeonlanProcess; QProcess wakeonlanProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
wakeonlanProcess.setProcessEnvironment( env ); wakeonlanProcess.setProcessEnvironment(env);
wakeonlanProcess.startDetached( settings->wakeonlanCmd, arguments ); wakeonlanProcess.startDetached(settings->wakeonlanCmd, arguments);
// Output message via the debug messages tab // Output message via the debug messages tab
qDebug() << settings->wakeonlanCmd << arguments.join( " " ); qDebug() << settings->wakeonlanCmd << arguments.join(" ");
pingTimer->start( 3000 ); pingTimer->start(3000);
protectedCycles = 7; protectedCycles = 7;
GotStatusChanged( state_t::BOOTING ); GotStatusChanged(state_t::BOOTING);
} }
void lc::Client::GotStatusChanged( state_t argState ) { void lc::Client::GotStatusChanged(state_t argState) {
if ( ( protectedCycles > 0 ) && ( state == state_t::BOOTING ) && ( argState != state_t::RESPONDING ) ) { if ((protectedCycles > 0) && (state == state_t::BOOTING) &&
return; (argState != state_t::RESPONDING)) {
} return;
if ( ( protectedCycles > 0 ) && ( state == state_t::SHUTTING_DOWN ) && argState != state_t::NOT_RESPONDING ) { }
return; if ((protectedCycles > 0) && (state == state_t::SHUTTING_DOWN) &&
} argState != state_t::NOT_RESPONDING) {
state = argState; return;
qDebug() << name << "status changed to:" << static_cast< unsigned short int >( argState ); }
state = argState;
qDebug() << name
<< "status changed to:" << static_cast<unsigned short int>(argState);
} }
void lc::Client::KillZLeaf() { void lc::Client::KillZLeaf() {
QStringList arguments; QStringList arguments;
arguments << "-i" << settings->pkeyPathUser arguments << "-i" << settings->pkeyPathUser
<< QString{ settings->userNameOnClients + "@" + ip } << QString{settings->userNameOnClients + "@" + ip}
<< settings->killallCmd << "-I" << "-q" << "zleaf.exe"; << settings->killallCmd << "-I"
<< "-q"
// Start the process << "zleaf.exe";
QProcess killZLeafProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); // Start the process
killZLeafProcess.setProcessEnvironment( env ); QProcess killZLeafProcess;
killZLeafProcess.startDetached( settings->sshCmd, arguments ); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
killZLeafProcess.setProcessEnvironment(env);
// Output message via the debug messages tab killZLeafProcess.startDetached(settings->sshCmd, arguments);
qDebug() << settings->sshCmd << arguments.join( " " );
// Output message via the debug messages tab
qDebug() << settings->sshCmd << arguments.join(" ");
// Restart the ping_timer, because it is stopped when a zLeaf is started
pingTimer->start(3000);
}
// Restart the ping_timer, because it is stopped when a zLeaf is started void lc::Client::OpenFilesystem(const QString *const argUserToBeUsed) {
pingTimer->start( 3000 ); if (state < state_t::RESPONDING) {
return;
}
QStringList arguments = QStringList{}
<< QString{"sftp://" + *argUserToBeUsed + "@" + ip};
QProcess openFilesystemProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
openFilesystemProcess.setProcessEnvironment(env);
openFilesystemProcess.startDetached(settings->fileMngr, arguments);
qDebug() << settings->fileMngr << arguments.join(" ");
} }
void lc::Client::OpenFilesystem( const QString * const argUserToBeUsed ) { void lc::Client::OpenTerminal(const QString &argCommand,
if ( state < state_t::RESPONDING ) { const bool &argOpenAsRoot) {
return; if (!settings->termEmulCmd.isEmpty()) {
if (state < state_t::RESPONDING) {
return;
} }
QStringList arguments = QStringList{} << QString{ "sftp://" + *argUserToBeUsed + "@" + ip };
QProcess openFilesystemProcess; QStringList *arguments = nullptr;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); arguments = new QStringList;
openFilesystemProcess.setProcessEnvironment( env ); if (!argOpenAsRoot) {
openFilesystemProcess.startDetached( settings->fileMngr, arguments ); *arguments << "-e"
qDebug() << settings->fileMngr << arguments.join( " " ); << QString{settings->sshCmd + " -i " + settings->pkeyPathUser +
} " " + settings->userNameOnClients + "@" + ip};
} else {
*arguments << "-e"
<< QString{settings->sshCmd + " -i " + settings->pkeyPathRoot +
" " + "root@" + ip};
}
void lc::Client::OpenTerminal( const QString &argCommand, const bool &argOpenAsRoot ) { if (!argCommand.isEmpty()) {
if ( !settings->termEmulCmd.isEmpty() ) { arguments->last().append(" '" + argCommand + "'");
if ( state < state_t::RESPONDING ) {
return;
}
QStringList *arguments = nullptr;
arguments = new QStringList;
if ( !argOpenAsRoot ) {
*arguments << "-e"
<< QString{ settings->sshCmd + " -i " + settings->pkeyPathUser + " "
+ settings->userNameOnClients + "@" + ip };
} else {
*arguments << "-e" <<
QString{ settings->sshCmd + " -i " + settings->pkeyPathRoot
+ " " + "root@" + ip};
}
if ( !argCommand.isEmpty() ) {
arguments->last().append( " '" + argCommand + "'" );
}
QProcess openTerminalProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
openTerminalProcess.setProcessEnvironment( env );
openTerminalProcess.startDetached( settings->termEmulCmd, *arguments );
qDebug() << settings->termEmulCmd << arguments->join( " " );
delete arguments;
} }
QProcess openTerminalProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
openTerminalProcess.setProcessEnvironment(env);
openTerminalProcess.startDetached(settings->termEmulCmd, *arguments);
qDebug() << settings->termEmulCmd << arguments->join(" ");
delete arguments;
}
} }
void lc::Client::RequestAPing() { void lc::Client::RequestAPing() {
if ( protectedCycles > 0 ) { if (protectedCycles > 0) {
--protectedCycles; --protectedCycles;
} }
emit PingWanted(); emit PingWanted();
} }
void lc::Client::SetStateToZLEAF_RUNNING( QString argClientIP ) { void lc::Client::SetStateToZLEAF_RUNNING(QString argClientIP) {
if ( argClientIP != ip ) { if (argClientIP != ip) {
return; return;
} }
if ( state != state_t::ZLEAF_RUNNING ) { if (state != state_t::ZLEAF_RUNNING) {
pingTimer->stop(); pingTimer->stop();
// Inform the ClientPinger instance, that zLeaf is now running // Inform the ClientPinger instance, that zLeaf is now running
pinger->setStateToZLEAF_RUNNING(); pinger->setStateToZLEAF_RUNNING();
this->GotStatusChanged( state_t::ZLEAF_RUNNING ); this->GotStatusChanged(state_t::ZLEAF_RUNNING);
qDebug() << "Client" << name << "got 'ZLEAF_RUNNING' signal."; qDebug() << "Client" << name << "got 'ZLEAF_RUNNING' signal.";
} }
} }
void lc::Client::ShowDesktopViewOnly() { void lc::Client::ShowDesktopViewOnly() {
QStringList arguments; QStringList arguments;
arguments << ip; arguments << ip;
QProcess showDesktopProcess; QProcess showDesktopProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
showDesktopProcess.setProcessEnvironment( env ); showDesktopProcess.setProcessEnvironment(env);
showDesktopProcess.startDetached( settings->vncViewer, arguments ); showDesktopProcess.startDetached(settings->vncViewer, arguments);
// Output message via the debug messages tab // Output message via the debug messages tab
qDebug() << settings->vncViewer << arguments.join( " " ); qDebug() << settings->vncViewer << arguments.join(" ");
} }
void lc::Client::ShowDesktopFullControl() { void lc::Client::ShowDesktopFullControl() {
QStringList arguments; QStringList arguments;
arguments << ip + ":5901"; arguments << ip + ":5901";
QProcess showDesktopProcess; QProcess showDesktopProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
showDesktopProcess.setProcessEnvironment( env ); showDesktopProcess.setProcessEnvironment(env);
showDesktopProcess.startDetached( settings->vncViewer, arguments ); showDesktopProcess.startDetached(settings->vncViewer, arguments);
// Output message via the debug messages tab // Output message via the debug messages tab
qDebug() << settings->vncViewer << arguments.join( " " ); qDebug() << settings->vncViewer << arguments.join(" ");
} }
void lc::Client::Shutdown() { void lc::Client::Shutdown() {
if ( state == state_t::NOT_RESPONDING || state == state_t::BOOTING if (state == state_t::NOT_RESPONDING || state == state_t::BOOTING ||
|| state == state_t::SHUTTING_DOWN ) { state == state_t::SHUTTING_DOWN) {
return; return;
} }
QStringList arguments; QStringList arguments;
arguments << "-i" << settings->pkeyPathUser arguments << "-i" << settings->pkeyPathUser
<< QString{ settings->userNameOnClients + "@" + ip } << "sudo shutdown -P now"; << QString{settings->userNameOnClients + "@" + ip}
<< "sudo shutdown -P now";
// Start the process
QProcess shutdownProcess; // Start the process
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcess shutdownProcess;
shutdownProcess.setProcessEnvironment( env ); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
shutdownProcess.startDetached( settings->sshCmd, arguments ); shutdownProcess.setProcessEnvironment(env);
shutdownProcess.startDetached(settings->sshCmd, arguments);
// Output message via the debug messages tab
qDebug() << settings->sshCmd << arguments.join( " " ); // Output message via the debug messages tab
qDebug() << settings->sshCmd << arguments.join(" ");
// This additional 'ping_timer' start is needed for the case that the clients are shut down without prior closing of zLeaves
pingTimer->start( 3000 ); // This additional 'ping_timer' start is needed for the case that the clients
// are shut down without prior closing of zLeaves
protectedCycles = 3; pingTimer->start(3000);
GotStatusChanged( state_t::SHUTTING_DOWN );
protectedCycles = 3;
GotStatusChanged(state_t::SHUTTING_DOWN);
} }
void lc::Client::StartZLeaf( const QString * argFakeName, QString cmd ) { void lc::Client::StartZLeaf(const QString *argFakeName, QString cmd) {
if ( state < state_t::RESPONDING || zLeafVersion.isEmpty() || GetSessionPort() < 7000 ) { if (state < state_t::RESPONDING || zLeafVersion.isEmpty() ||
return; GetSessionPort() < 7000) {
} return;
}
// Create a QMessageBox for user interaction if there is already a zLeaf running
std::unique_ptr< QMessageBox > messageBoxRunningZLeafFound; // Create a QMessageBox for user interaction if there is already a zLeaf
if ( state == state_t::ZLEAF_RUNNING ) { // running
messageBoxRunningZLeafFound.reset( new QMessageBox{ QMessageBox::Warning, "Running zLeaf found", std::unique_ptr<QMessageBox> messageBoxRunningZLeafFound;
QString{ "There is already a zLeaf running on " + name + "." }, if (state == state_t::ZLEAF_RUNNING) {
QMessageBox::No | QMessageBox::Yes } ); messageBoxRunningZLeafFound.reset(new QMessageBox{
messageBoxRunningZLeafFound->setInformativeText( "Do you want to start a zLeaf on client " QMessageBox::Warning, "Running zLeaf found",
+ name + " nonetheless?" ); QString{"There is already a zLeaf running on " + name + "."},
messageBoxRunningZLeafFound->setDefaultButton( QMessageBox::No ); QMessageBox::No | QMessageBox::Yes});
messageBoxRunningZLeafFound->exec(); messageBoxRunningZLeafFound->setInformativeText(
} "Do you want to start a zLeaf on client " + name + " nonetheless?");
messageBoxRunningZLeafFound->setDefaultButton(QMessageBox::No);
if ( ( messageBoxRunningZLeafFound.get() != nullptr messageBoxRunningZLeafFound->exec();
&& messageBoxRunningZLeafFound->clickedButton() }
== messageBoxRunningZLeafFound->button( QMessageBox::Yes ) )
|| state != state_t::ZLEAF_RUNNING ) { if ((messageBoxRunningZLeafFound.get() != nullptr &&
QStringList arguments; messageBoxRunningZLeafFound->clickedButton() ==
if ( argFakeName == nullptr ) { messageBoxRunningZLeafFound->button(QMessageBox::Yes)) ||
arguments << "-i" << settings->pkeyPathUser state != state_t::ZLEAF_RUNNING) {
<< QString{ settings->userNameOnClients + "@" + ip }
<< cmd;
} else {
arguments << "-i" << settings->pkeyPathUser
<< QString{ settings->userNameOnClients + "@" + ip }
<< cmd
<< "/name" << *argFakeName;
}
// Start the process
QProcess startZLeafProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
startZLeafProcess.setProcessEnvironment( env );
startZLeafProcess.startDetached( settings->sshCmd, arguments );
// Output message via the debug messages tab
qDebug() << settings->sshCmd << arguments.join( " " );
}
}
void lc::Client::StartClientBrowser( const QString * const argURL, const bool * const argFullscreen, const QString * const argBrowser ) {
//Declarations
QStringList arguments; QStringList arguments;
if (argFakeName == nullptr) {
QString processedArgUrl(*argURL); arguments << "-i" << settings->pkeyPathUser
QRegularExpression clientRegEx(QStringLiteral("%CLIENT%")); << QString{settings->userNameOnClients + "@" + ip} << cmd;
processedArgUrl.replace(clientRegEx,this->name); } else {
//qDebug() << processedArgUrl; arguments << "-i" << settings->pkeyPathUser
<< QString{settings->userNameOnClients + "@" + ip} << cmd
if(argBrowser==QString("firefox")){ << "/name" << *argFakeName;
// Build arguments list for SSH command
arguments << "-i" << settings->pkeyPathUser
<< QString{ settings->userNameOnClients + "@" + ip }
<< "DISPLAY=:0.0"
<< settings->clientBrowserCmd
<< processedArgUrl;
// Add fullscreen toggle if checked
if (*argFullscreen == true){
arguments << "& sleep 3 && DISPLAY=:0.0 xdotool key --clearmodifiers F11";
}
} else if (argBrowser==QString("chromium")) {
// Build arguments list for SSH command
arguments << "-i" << settings->pkeyPathUser
<< QString{ settings->userNameOnClients + "@" + ip }
<< "DISPLAY=:0.0"
<< settings->clientChromiumCmd
<< "--noerrdialogs --kiosk"
<< "--app='" + processedArgUrl + "'"
<< "> /dev/null 2>&1 &disown";
} }
// Start the process // Start the process
QProcess startClientBrowserProcess; QProcess startZLeafProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
startClientBrowserProcess.setProcessEnvironment( env ); startZLeafProcess.setProcessEnvironment(env);
startClientBrowserProcess.startDetached( settings->sshCmd, arguments ); startZLeafProcess.startDetached(settings->sshCmd, arguments);
// Output message via the debug messages tab // Output message via the debug messages tab
qDebug() << settings->sshCmd << arguments.join( " " ); qDebug() << settings->sshCmd << arguments.join(" ");
}
} }
void lc::Client::StopClientBrowser() { void lc::Client::StartClientBrowser(const QString *const argURL,
//Declarations const bool *const argFullscreen,
QStringList arguments; const QString *const argBrowser) {
// Declarations
QStringList arguments;
QString processedArgUrl(*argURL);
QRegularExpression clientRegEx(QStringLiteral("%CLIENT%"));
processedArgUrl.replace(clientRegEx, this->name);
// qDebug() << processedArgUrl;
//Build arguments list if (argBrowser == QString("firefox")) {
// Build arguments list for SSH command
arguments << "-i" << settings->pkeyPathUser arguments << "-i" << settings->pkeyPathUser
<< QString{ settings->userNameOnClients + "@" + ip } << QString{settings->userNameOnClients + "@" + ip}
<< "killall" << "DISPLAY=:0.0" << settings->clientBrowserCmd
<< settings->clientBrowserCmd << processedArgUrl;
<< "& sleep 1 && rm -R /home/ewfuser/.mozilla/firefox/*"
<< "& killall"
<< settings->clientChromiumCmd;
// Start the process // Add fullscreen toggle if checked
QProcess startClientBrowserProcess; if (*argFullscreen == true) {
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); arguments << "& sleep 3 && DISPLAY=:0.0 xdotool key --clearmodifiers F11";
startClientBrowserProcess.setProcessEnvironment( env ); }
startClientBrowserProcess.startDetached( settings->sshCmd, arguments ); } else if (argBrowser == QString("chromium")) {
// Build arguments list for SSH command
arguments << "-i" << settings->pkeyPathUser
<< QString{settings->userNameOnClients + "@" + ip}
<< "DISPLAY=:0.0" << settings->clientChromiumCmd
<< "--noerrdialogs --kiosk"
<< "--app='" + processedArgUrl + "'"
<< "> /dev/null 2>&1 &disown";
}
// Start the process
QProcess startClientBrowserProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
startClientBrowserProcess.setProcessEnvironment(env);
startClientBrowserProcess.startDetached(settings->sshCmd, arguments);
// Output message via the debug messages tab
qDebug() << settings->sshCmd << arguments.join(" ");
}
// Output message via the debug messages tab void lc::Client::StopClientBrowser() {
qDebug() << settings->sshCmd << arguments.join( " " ); // Declarations
QStringList arguments;
// Build arguments list
arguments << "-i" << settings->pkeyPathUser
<< QString{settings->userNameOnClients + "@" + ip} << "killall"
<< settings->clientBrowserCmd
<< "& sleep 1 && rm -R /home/ewfuser/.mozilla/firefox/*"
<< "& killall" << settings->clientChromiumCmd;
// Start the process
QProcess startClientBrowserProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
startClientBrowserProcess.setProcessEnvironment(env);
startClientBrowserProcess.startDetached(settings->sshCmd, arguments);
// Output message via the debug messages tab
qDebug() << settings->sshCmd << arguments.join(" ");
} }
void lc::Client::ControlRMB(bool enable) { void lc::Client::ControlRMB(bool enable) {
//Declarations // Declarations
QStringList arguments; QStringList arguments;
//Build arguments list // Build arguments list
if(enable){ if (enable) {
arguments << "-i" << settings->pkeyPathUser arguments << "-i" << settings->pkeyPathUser
<< QString{ settings->userNameOnClients + "@" + ip } << QString{settings->userNameOnClients + "@" + ip}
<< "DISPLAY=:0 xinput set-button-map 'Microsoft Basic Optical Mouse' 1 2 3 4 5 6 7 8 9 10 11 12 > /dev/null 2>&1 &disown;"; << "DISPLAY=:0 xinput set-button-map 'Microsoft Basic Optical "
} else { "Mouse' 1 2 3 4 5 6 7 8 9 10 11 12 > /dev/null 2>&1 &disown;";
arguments << "-i" << settings->pkeyPathUser } else {
<< QString{ settings->userNameOnClients + "@" + ip } arguments << "-i" << settings->pkeyPathUser
<< "DISPLAY=:0 xinput set-button-map 'Microsoft Basic Optical Mouse' 1 2 0 4 5 6 7 8 9 10 11 12 > /dev/null 2>&1 &disown;"; << QString{settings->userNameOnClients + "@" + ip}
} << "DISPLAY=:0 xinput set-button-map 'Microsoft Basic Optical "
"Mouse' 1 2 0 4 5 6 7 8 9 10 11 12 > /dev/null 2>&1 &disown;";
// Start the process }
QProcess startClientBrowserProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); // Start the process
startClientBrowserProcess.setProcessEnvironment( env ); QProcess startClientBrowserProcess;
startClientBrowserProcess.startDetached( settings->sshCmd, arguments ); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
startClientBrowserProcess.setProcessEnvironment(env);
// Output message via the debug messages tab startClientBrowserProcess.startDetached(settings->sshCmd, arguments);
qDebug() << settings->sshCmd << arguments.join( " " );
// Output message via the debug messages tab
qDebug() << settings->sshCmd << arguments.join(" ");
} }

@ -28,129 +28,140 @@
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#include "global.h"
#include "clientpinger.h" #include "clientpinger.h"
#include "global.h"
namespace lc { namespace lc {
//! Class which represents the clients in the lab //! Class which represents the clients in the lab
/*! /*!
This class contains elements and functions needed to represent all functions of a client. This class contains elements and functions needed to represent all functions
of a client.
*/ */
class Client : public QObject { class Client : public QObject {
Q_OBJECT Q_OBJECT
public slots: public slots:
//! Sets the STATE of the client to 'ZLEAF_RUNNING' //! Sets the STATE of the client to 'ZLEAF_RUNNING'
void SetStateToZLEAF_RUNNING( QString argClientIP ); void SetStateToZLEAF_RUNNING(QString argClientIP);
public: public:
const QString ip; const QString ip;
const QString mac; const QString mac;
const QString name; const QString name;
const unsigned short int xPosition = 1; const unsigned short int xPosition = 1;
const unsigned short int yPosition = 1; const unsigned short int yPosition = 1;
/*! /*!
* \brief Client's constructor * \brief Client's constructor
* \param argIP The IP address the represented client has * \param argIP The IP address the represented client has
* \param argMAC The MAC address the represented client has * \param argMAC The MAC address the represented client has
* \param argName The hostname of the represented client * \param argName The hostname of the represented client
* \param argXPosition The client's x coordinate in the lab's grid * \param argXPosition The client's x coordinate in the lab's grid
* \param argYPosition The client's y coordinate in the lab's grid * \param argYPosition The client's y coordinate in the lab's grid
*/ */
Client( const QString &argIP, const QString &argMAC, const QString &argName, Client(const QString &argIP, const QString &argMAC, const QString &argName,
unsigned short int argXPosition, unsigned short int argYPosition, unsigned short int argXPosition, unsigned short int argYPosition,
const QString &argPingCmd ); const QString &argPingCmd);
//! Client's destructor //! Client's destructor
~Client(); ~Client();
//! Beams the chosen file to the client's 'media4ztree' directory //! Beams the chosen file to the client's 'media4ztree' directory
/*! /*!
@param argFileToBeam The file which shall be beamed to the client's 'media4ztree' directory @param argFileToBeam The file which shall be beamed to the
@param argPublickeyPathUser The path to the publickey for user login on the clients client's 'media4ztree' directory
@param argUserNameOnClients The name of the user on the clients @param argPublickeyPathUser The path to the publickey for user
*/ login on the clients
void BeamFile( const QString &argFileToBeam, const QString * const argPublickeyPathUser, const QString * const argUserNameOnClients ); @param argUserNameOnClients The name of the user on the clients
/*! */
* \brief Boots the client void BeamFile(const QString &argFileToBeam,
*/ const QString *const argPublickeyPathUser,
void Boot(); const QString *const argUserNameOnClients);
/*! /*!
* \brief DeactiveScreensaver deactivates potentially running screensavers on the client * \brief Boots the client
*/ */
void DeactiveScreensaver(); void Boot();
//! Returns the current state of the client /*!
/*! * \brief DeactiveScreensaver deactivates potentially running screensavers on
@return The current state of the client * the client
*/ */
state_t GetClientState() const { return state; } void DeactiveScreensaver();
int GetSessionPort() const { return sessionPort; } //! Returns the current state of the client
/*! /*!
* \brief Kills all processes 'zleaf.exe' on the client @return The current state of the client
*/ */
void KillZLeaf(); state_t GetClientState() const { return state; }
//! Opens a file manager for the client's file system int GetSessionPort() const { return sessionPort; }
/*! /*!
@param argUserToBeUsed The name of the user on the clients * \brief Kills all processes 'zleaf.exe' on the client
*/ */
void OpenFilesystem( const QString * const argUserToBeUsed ); void KillZLeaf();
/*! //! Opens a file manager for the client's file system
* \brief Opens a terminal for the client /*!
* \param argCommand A command which shall be executed in the terminal window (Pass an empty QString if not wanted) @param argUserToBeUsed The name of the user on the clients
* \param argOpenAsRoot Run the terminal session as root (true) or as normal user (false) */
*/ void OpenFilesystem(const QString *const argUserToBeUsed);
void OpenTerminal( const QString &argCommand, const bool &argOpenAsRoot ); /*!
void SetSessionPort( int argSP ) { sessionPort = argSP; } * \brief Opens a terminal for the client
void SetzLeafVersion( const QString &argzLeafV ) { zLeafVersion = argzLeafV; } * \param argCommand A command which shall be executed in the terminal window
//! Shows the desktop of the given client * (Pass an empty QString if not wanted) \param argOpenAsRoot Run the terminal
void ShowDesktopViewOnly(); * session as root (true) or as normal user (false)
void ShowDesktopFullControl(); */
/*! void OpenTerminal(const QString &argCommand, const bool &argOpenAsRoot);
* \brief Shuts down the client void SetSessionPort(int argSP) { sessionPort = argSP; }
*/ void SetzLeafVersion(const QString &argzLeafV) { zLeafVersion = argzLeafV; }
void Shutdown(); //! Shows the desktop of the given client
void ShowDesktopViewOnly();
/*! void ShowDesktopFullControl();
* \brief Starts a zLeaf instance on the client /*!
* @param argFakeName The name the zLeaf instance shall have (if not the default, which is the hostname of the client) * \brief Shuts down the client
*/ */
void StartZLeaf(const QString *argFakeName = nullptr, QString cmd = "" ); void Shutdown();
/*! /*!
* \brief Opens a browser window on the client * \brief Starts a zLeaf instance on the client
* @param argURL URL to open in clients browser * @param argFakeName The name the zLeaf instance shall have (if not the
*/ * default, which is the hostname of the client)
void StartClientBrowser( const QString *argURL = nullptr, const bool *argFullscreen = nullptr, const QString *argBrowser = nullptr ); */
void StartZLeaf(const QString *argFakeName = nullptr, QString cmd = "");
/*!
* \brief Closes all browser instances /*!
*/ * \brief Opens a browser window on the client
void StopClientBrowser(); * @param argURL URL to open in clients browser
*/
/*! void StartClientBrowser(const QString *argURL = nullptr,
* \brief Enable/Disable right mouse button const bool *argFullscreen = nullptr,
*/ const QString *argBrowser = nullptr);
void ControlRMB(bool enable = true);
/*!
* \brief Closes all browser instances
*/
void StopClientBrowser();
/*!
* \brief Enable/Disable right mouse button
*/
void ControlRMB(bool enable = true);
private: private:
const QString &GetzLeafVersion() const { return zLeafVersion; } const QString &GetzLeafVersion() const { return zLeafVersion; }
unsigned short int protectedCycles; unsigned short int protectedCycles;
ClientPinger *pinger = nullptr; ClientPinger *pinger = nullptr;
QThread pingerThread; QThread pingerThread;
state_t state = state_t::UNINITIALIZED; state_t state = state_t::UNINITIALIZED;
QTimer *pingTimer = nullptr; //! QTimer used to trigger pings by pinger's ClientPinger instance QTimer *pingTimer = nullptr; //! QTimer used to trigger pings by pinger's
int sessionPort = 0; //! ClientPinger instance
QString zLeafVersion; int sessionPort = 0;
QString zLeafVersion;
private slots: private slots:
void GotStatusChanged( state_t argState ); void GotStatusChanged(state_t argState);
void RequestAPing(); void RequestAPing();
signals: signals:
void PingWanted(); void PingWanted();
}; };
} } // namespace lc
#endif // CLIENT_H #endif // CLIENT_H

@ -22,93 +22,108 @@
#include "clienthelpnotificationserver.h" #include "clienthelpnotificationserver.h"
#include "settings.h" #include "settings.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
lc::ClientHelpNotificationServer::ClientHelpNotificationServer( QObject *argParent ) : lc::ClientHelpNotificationServer::ClientHelpNotificationServer(
QObject{ argParent }, QObject *argParent)
hostAddress{ settings->serverIP } : QObject{argParent}, hostAddress{settings->serverIP} {
{ QNetworkConfigurationManager manager;
QNetworkConfigurationManager manager; if (manager.capabilities() &
if ( manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired ) { QNetworkConfigurationManager::NetworkSessionRequired) {
// Get saved network configuration // Get saved network configuration
QSettings settings{ QSettings::UserScope, QLatin1String{ "QtProject" } }; QSettings settings{QSettings::UserScope, QLatin1String{"QtProject"}};
settings.beginGroup( QLatin1String{ "QtNetwork" } ); settings.beginGroup(QLatin1String{"QtNetwork"});
const QString id = settings.value( QLatin1String{ "DefaultNetworkConfiguration" } ).toString(); const QString id =
settings.endGroup(); settings.value(QLatin1String{"DefaultNetworkConfiguration"}).toString();
settings.endGroup();
// If the saved network configuration is not currently discovered use the system default // If the saved network configuration is not currently discovered use the
QNetworkConfiguration config = manager.configurationFromIdentifier( id ); // system default
if ( ( config.state() & QNetworkConfiguration::Discovered ) != QNetworkConfiguration::Discovered ) { QNetworkConfiguration config = manager.configurationFromIdentifier(id);
config = manager.defaultConfiguration(); if ((config.state() & QNetworkConfiguration::Discovered) !=
} QNetworkConfiguration::Discovered) {
networkSession = new QNetworkSession{ config, this }; config = manager.defaultConfiguration();
connect( networkSession, &QNetworkSession::opened,
this, &ClientHelpNotificationServer::OpenSession );
networkSession->open();
} else {
OpenSession();
} }
networkSession = new QNetworkSession{config, this};
connect(networkSession, &QNetworkSession::opened, this,
&ClientHelpNotificationServer::OpenSession);
networkSession->open();
} else {
OpenSession();
}
connect( helpMessageServer, &QTcpServer::newConnection, connect(helpMessageServer, &QTcpServer::newConnection, this,
this, &ClientHelpNotificationServer::SendReply ); &ClientHelpNotificationServer::SendReply);
} }
void lc::ClientHelpNotificationServer::OpenSession() { void lc::ClientHelpNotificationServer::OpenSession() {
// Save the used configuration // Save the used configuration
if ( networkSession ) { if (networkSession) {
QNetworkConfiguration config = networkSession->configuration(); QNetworkConfiguration config = networkSession->configuration();
QString id; QString id;
if ( config.type() == QNetworkConfiguration::UserChoice ) { if (config.type() == QNetworkConfiguration::UserChoice) {
id = networkSession->sessionProperty( QLatin1String{ "UserChoiceConfiguration" } ).toString(); id = networkSession
} else { ->sessionProperty(QLatin1String{"UserChoiceConfiguration"})
id = config.identifier(); .toString();
} } else {
id = config.identifier();
QSettings settings( QSettings::UserScope, QLatin1String{ "QtProject" } );
settings.beginGroup( QLatin1String{ "QtNetwork" } );
settings.setValue( QLatin1String{ "DefaultNetworkConfiguration" }, id );
settings.endGroup();
} }
helpMessageServer = new QTcpServer{ this }; QSettings settings(QSettings::UserScope, QLatin1String{"QtProject"});
if ( !helpMessageServer->listen( hostAddress, settings->clientHelpNotificationServerPort ) ) { settings.beginGroup(QLatin1String{"QtNetwork"});
QMessageBox messageBox{ QMessageBox::Critical, tr( "Unable to start the client help notification server" ), settings.setValue(QLatin1String{"DefaultNetworkConfiguration"}, id);
tr( "Unable to start the client help notification server.\nThe following error occurred:\n\n%1." ).arg( helpMessageServer->errorString() ), QMessageBox::Ok }; settings.endGroup();
messageBox.exec(); }
return;
} helpMessageServer = new QTcpServer{this};
if (!helpMessageServer->listen(hostAddress,
settings->clientHelpNotificationServerPort)) {
QMessageBox messageBox{
QMessageBox::Critical,
tr("Unable to start the client help notification server"),
tr("Unable to start the client help notification server.\nThe "
"following error occurred:\n\n%1.")
.arg(helpMessageServer->errorString()),
QMessageBox::Ok};
messageBox.exec();
return;
}
} }
void lc::ClientHelpNotificationServer::SendReply() { void lc::ClientHelpNotificationServer::SendReply() {
QByteArray block; QByteArray block;
QDataStream out{ &block, QIODevice::WriteOnly }; QDataStream out{&block, QIODevice::WriteOnly};
out.setVersion( QDataStream::Qt_5_2 ); out.setVersion(QDataStream::Qt_5_2);
out << ( quint16 )0; out << (quint16)0;
out << QString{ "Help demand retrieved." }; out << QString{"Help demand retrieved."};
out.device()->seek( 0 ); out.device()->seek(0);
out << ( quint16 )( block.size() - sizeof( quint16 ) ); out << (quint16)(block.size() - sizeof(quint16));
QTcpSocket *clientConnection = helpMessageServer->nextPendingConnection(); QTcpSocket *clientConnection = helpMessageServer->nextPendingConnection();
QString peerAddress = clientConnection->peerAddress().toString(); QString peerAddress = clientConnection->peerAddress().toString();
QString peerName; QString peerName;
bool unknownClient = false; bool unknownClient = false;
if ( settings->clIPsToClMap.contains( peerAddress ) ) { if (settings->clIPsToClMap.contains(peerAddress)) {
peerName = settings->clIPsToClMap[ peerAddress ]->name; peerName = settings->clIPsToClMap[peerAddress]->name;
} else { } else {
unknownClient = true; unknownClient = true;
} }
connect( clientConnection, &QTcpSocket::disconnected, clientConnection, &QTcpSocket::deleteLater ); connect(clientConnection, &QTcpSocket::disconnected, clientConnection,
clientConnection->write( block ); &QTcpSocket::deleteLater);
clientConnection->disconnectFromHost(); clientConnection->write(block);
clientConnection->disconnectFromHost();
if ( unknownClient ) { if (unknownClient) {
QMessageBox requestReceivedBox{ QMessageBox::Information, tr( "Unknown client asked for help."), QMessageBox requestReceivedBox{
tr( "An unknown client with IP '%1' asked for help.").arg( peerAddress ), QMessageBox::Ok }; QMessageBox::Information, tr("Unknown client asked for help."),
requestReceivedBox.exec(); tr("An unknown client with IP '%1' asked for help.").arg(peerAddress),
} else { QMessageBox::Ok};
QMessageBox requestReceivedBox{ QMessageBox::Information, tr( "'%1' asked for help.").arg( peerName ), requestReceivedBox.exec();
tr( "'%1' asked for help.").arg( peerName ), QMessageBox::Ok }; } else {
requestReceivedBox.exec(); QMessageBox requestReceivedBox{
} QMessageBox::Information, tr("'%1' asked for help.").arg(peerName),
tr("'%1' asked for help.").arg(peerName), QMessageBox::Ok};
requestReceivedBox.exec();
}
} }

@ -22,32 +22,32 @@
#include "src/Lib/client.h" #include "src/Lib/client.h"
#include <QObject>
#include <QHostAddress> #include <QHostAddress>
#include <QMessageBox> #include <QMessageBox>
#include <QObject>
#include <QtNetwork> #include <QtNetwork>
namespace lc { namespace lc {
class ClientHelpNotificationServer : public QObject { class ClientHelpNotificationServer : public QObject {
Q_OBJECT Q_OBJECT
public: public:
explicit ClientHelpNotificationServer( QObject *argParent = nullptr ); explicit ClientHelpNotificationServer(QObject *argParent = nullptr);
signals: signals:
public slots: public slots:
private: private:
QTcpServer *helpMessageServer = nullptr; QTcpServer *helpMessageServer = nullptr;
const QHostAddress hostAddress; const QHostAddress hostAddress;
QNetworkSession *networkSession = nullptr; QNetworkSession *networkSession = nullptr;
private slots: private slots:
void OpenSession(); void OpenSession();
void SendReply(); void SendReply();
}; };
} } // namespace lc
#endif // CLIENTHELPNOTIFICATIONSERVER_H #endif // CLIENTHELPNOTIFICATIONSERVER_H

@ -19,45 +19,48 @@
#include "clientpinger.h" #include "clientpinger.h"
lc::ClientPinger::ClientPinger( const QString &argIP, lc::ClientPinger::ClientPinger(const QString &argIP,
const QString &argPingCommand, QObject *argParent ) : const QString &argPingCommand,
QObject{ argParent }, QObject *argParent)
// Arguments: -c 1 (send 1 ECHO_REQUEST packet) -w 1 (timeout after 1 second) -q (quiet output) : QObject{argParent},
pingArguments{ QStringList{} << "-c" << "1" << "-w" << "1" << "-q" << argIP }, // Arguments: -c 1 (send 1 ECHO_REQUEST packet) -w 1 (timeout after 1
pingCommand{ argPingCommand }, // second) -q (quiet output)
pingProcess{ new QProcess{ this } }, pingArguments{QStringList{} << "-c"
state{ state_t::UNINITIALIZED } << "1"
{ << "-w"
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); << "1"
pingProcess->setProcessEnvironment(env); << "-q" << argIP},
// emit ping_string(new QString(*ping_command + " " + ping_arguments->join(" "))); pingCommand{argPingCommand},
pingProcess{new QProcess{this}}, state{state_t::UNINITIALIZED} {
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
pingProcess->setProcessEnvironment(env);
// emit ping_string(new QString(*ping_command + " " + ping_arguments->join("
// ")));
} }
lc::ClientPinger::~ClientPinger() { lc::ClientPinger::~ClientPinger() { delete pingProcess; }
delete pingProcess;
}
void lc::ClientPinger::doPing() { void lc::ClientPinger::doPing() {
// Initialize the new state to be queried // Initialize the new state to be queried
state_t newState = state_t::UNINITIALIZED; state_t newState = state_t::UNINITIALIZED;
// Query the current state of the client // Query the current state of the client
pingProcess->start( pingCommand, pingArguments ); pingProcess->start(pingCommand, pingArguments);
if ( !pingProcess->waitForFinished( 2500 ) ) if (!pingProcess->waitForFinished(2500))
newState = state_t::ERROR; newState = state_t::ERROR;
else { else {
if ( pingProcess->exitCode() == 0 ) if (pingProcess->exitCode() == 0)
newState = state_t::RESPONDING; newState = state_t::RESPONDING;
else else
newState = state_t::NOT_RESPONDING; newState = state_t::NOT_RESPONDING;
} }
if ( newState != state ) { if (newState != state) {
state = newState; state = newState;
emit PingFinished( newState ); emit PingFinished(newState);
} }
} }
void lc::ClientPinger::setStateToZLEAF_RUNNING() { void lc::ClientPinger::setStateToZLEAF_RUNNING() {
state = state_t::ZLEAF_RUNNING; state = state_t::ZLEAF_RUNNING;
} }

@ -28,43 +28,50 @@
namespace lc { namespace lc {
//! The ClientPinger class is used to do repetitive pings of the owning Client instance's client. //! The ClientPinger class is used to do repetitive pings of the owning Client
//! instance's client.
/*! /*!
This class is just used for executing repetitive pings. This class is just used for executing repetitive pings.
*/ */
class ClientPinger : public QObject { class ClientPinger : public QObject {
Q_OBJECT Q_OBJECT
public: public:
//! ClientPinger's constructor //! ClientPinger's constructor
/*! /*!
@param argIP A reference to the owning Client instance's IP address @param argIP A reference to the owning Client instance's IP
@param argPingCommand The path were the command to be executed for pings resides address
@param argParent The ClientPinger's parent owning this instance of it @param argPingCommand The path were the command to be executed for pings
*/ resides
explicit ClientPinger( const QString &argIP, const QString &argPingCommand, @param argParent The ClientPinger's parent owning this instance of
QObject *argParent = nullptr ); it
//! ClientPinger's destructor */
~ClientPinger(); explicit ClientPinger(const QString &argIP, const QString &argPingCommand,
QObject *argParent = nullptr);
//! ClientPinger's destructor
~ClientPinger();
public slots: public slots:
//! This slot executes a ping when called. //! This slot executes a ping when called.
void doPing(); void doPing();
//! Retrieves the information, that zLeaf is running (otherwise restarting will not result in status updates) //! Retrieves the information, that zLeaf is running (otherwise restarting
void setStateToZLEAF_RUNNING(); //! will not result in status updates)
void setStateToZLEAF_RUNNING();
private: private:
const QStringList pingArguments; //! The arguments for the 'ping' command const QStringList pingArguments; //! The arguments for the 'ping' command
const QString pingCommand; //! The 'ping' command itself const QString pingCommand; //! The 'ping' command itself
QProcess * pingProcess; //! The 'ping' process which will be executed on every call of 'do_ping()' QProcess *pingProcess; //! The 'ping' process which will be executed on every
state_t state; //! Stores the current state of the client //! call of 'do_ping()'
state_t state; //! Stores the current state of the client
signals: signals:
//! This signal was just implemented for testing purposes //! This signal was just implemented for testing purposes
//! This signal is emitted if the ping finished and the state of the client changed //! This signal is emitted if the ping finished and the state of the client
void PingFinished( state_t state ); //! changed
void PingFinished(state_t state);
}; };
} } // namespace lc
#endif // CLIENTPINGER_H #endif // CLIENTPINGER_H

@ -23,21 +23,23 @@
#include <QMetaType> #include <QMetaType>
//! Opens a terminal for the client //! Opens a terminal for the client
enum class state_t : unsigned short int { enum class state_t : unsigned short int {
//! The client is booting but not yet responding //! The client is booting but not yet responding
BOOTING, BOOTING,
//! An error occurred determining the client's state //! An error occurred determining the client's state
ERROR, ERROR,
//! The client is not responding to pings //! The client is not responding to pings
NOT_RESPONDING, NOT_RESPONDING,
//! The client is shutting down but not yet stopped responding //! The client is shutting down but not yet stopped responding
SHUTTING_DOWN, SHUTTING_DOWN,
//! The client's state is not yet defined (should only occur directly after client creation) //! The client's state is not yet defined (should only occur directly after
UNINITIALIZED, //! client creation)
//! The client is responding to pings UNINITIALIZED,
RESPONDING, //! The client is responding to pings
//! The client is running a zLeaf RESPONDING,
ZLEAF_RUNNING}; //! The client is running a zLeaf
Q_DECLARE_METATYPE( state_t ) ZLEAF_RUNNING
};
Q_DECLARE_METATYPE(state_t)
#endif // GLOBAL_H #endif // GLOBAL_H

@ -24,164 +24,172 @@
#include "lablib.h" #include "lablib.h"
lc::Lablib::Lablib( QObject *argParent ) : lc::Lablib::Lablib(QObject *argParent)
QObject{ argParent }, : QObject{argParent}, labSettings{"Labcontrol", "Labcontrol", this},
labSettings{ "Labcontrol", "Labcontrol", this }, sessionsModel{new SessionsModel{this}} {
sessionsModel{ new SessionsModel{ this } } for (const auto &s : settings->GetClients()) {
{ connect(this, &Lablib::ZLEAF_RUNNING, s, &Client::SetStateToZLEAF_RUNNING);
for ( const auto &s : settings->GetClients() ) { }
connect( this, &Lablib::ZLEAF_RUNNING, DetectInstalledZTreeVersionsAndLaTeXHeaders();
s, &Client::SetStateToZLEAF_RUNNING );
} // Initialize all 'netstat' query mechanisms
DetectInstalledZTreeVersionsAndLaTeXHeaders(); if (!settings->netstatCmd.isEmpty()) {
netstatAgent = new NetstatAgent{settings->netstatCmd};
// Initialize all 'netstat' query mechanisms netstatAgent->moveToThread(&netstatThread);
if ( !settings->netstatCmd.isEmpty() ) { connect(&netstatThread, &QThread::finished, netstatAgent,
netstatAgent = new NetstatAgent{ settings->netstatCmd }; &QObject::deleteLater);
netstatAgent->moveToThread( &netstatThread ); connect(netstatAgent, &NetstatAgent::QueryFinished, this,
connect( &netstatThread, &QThread::finished, netstatAgent, &QObject::deleteLater ); &Lablib::GotNetstatQueryResult);
connect( netstatAgent, &NetstatAgent::QueryFinished, netstatThread.start();
this, &Lablib::GotNetstatQueryResult ); netstatTimer = new QTimer{this};
netstatThread.start(); connect(netstatTimer, &QTimer::timeout, netstatAgent,
netstatTimer = new QTimer{ this }; &NetstatAgent::QueryClientConnections);
connect( netstatTimer, &QTimer::timeout, netstatTimer->start(500);
netstatAgent, &NetstatAgent::QueryClientConnections ); }
netstatTimer->start( 500 );
} // Initialize the server for client help requests retrieval
if (settings->clientHelpNotificationServerPort &&
// Initialize the server for client help requests retrieval !settings->serverIP.isEmpty()) {
if ( settings->clientHelpNotificationServerPort && !settings->serverIP.isEmpty() ) { clientHelpNotificationServer = new ClientHelpNotificationServer{this};
clientHelpNotificationServer = new ClientHelpNotificationServer{ this }; }
}
} }
lc::Lablib::~Lablib () { lc::Lablib::~Lablib() {
if ( netstatTimer ) { if (netstatTimer) {
netstatTimer->stop(); netstatTimer->stop();
delete netstatTimer; delete netstatTimer;
} }
netstatThread.quit(); netstatThread.quit();
netstatThread.wait(); netstatThread.wait();
} }
bool lc::Lablib::CheckIfUserIsAdmin() const { bool lc::Lablib::CheckIfUserIsAdmin() const {
for ( const auto &s : settings->adminUsers ) { for (const auto &s : settings->adminUsers) {
if ( s == settings->localUserName ) { if (s == settings->localUserName) {
qDebug() << "User" << settings->localUserName << "has administrative rights."; qDebug() << "User" << settings->localUserName
return true; << "has administrative rights.";
} return true;
} }
return false; }
return false;
} }
void lc::Lablib::DetectInstalledZTreeVersionsAndLaTeXHeaders() { void lc::Lablib::DetectInstalledZTreeVersionsAndLaTeXHeaders() {}
}
void lc::Lablib::GotNetstatQueryResult( QStringList *argActiveZLeafConnections ) { void lc::Lablib::GotNetstatQueryResult(QStringList *argActiveZLeafConnections) {
if ( argActiveZLeafConnections != nullptr ) { if (argActiveZLeafConnections != nullptr) {
for ( auto s: *argActiveZLeafConnections ) { for (auto s : *argActiveZLeafConnections) {
// Set all given clients' statuses to 'ZLEAF_RUNNING' // Set all given clients' statuses to 'ZLEAF_RUNNING'
emit ZLEAF_RUNNING( s ); emit ZLEAF_RUNNING(s);
}
} }
else } else
qDebug() << "Netstat status query failed."; qDebug() << "Netstat status query failed.";
delete argActiveZLeafConnections; delete argActiveZLeafConnections;
} }
void lc::Lablib::ShowOrsee() { void lc::Lablib::ShowOrsee() {
QProcess showOrseeProcess; QProcess showOrseeProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
showOrseeProcess.setProcessEnvironment( env ); showOrseeProcess.setProcessEnvironment(env);
QString program{ settings->browserCmd }; QString program{settings->browserCmd};
QStringList arguments{ QStringList{} << settings->orseeUrl }; QStringList arguments{QStringList{} << settings->orseeUrl};
showOrseeProcess.startDetached( program, arguments ); showOrseeProcess.startDetached(program, arguments);
// Output message via the debug messages tab // Output message via the debug messages tab
qDebug() << program << arguments.join( " " ); qDebug() << program << arguments.join(" ");
} }
void lc::Lablib::ShowPreprints() { void lc::Lablib::ShowPreprints() {
// Start the process // Start the process
QProcess showPreprintsProcess; QProcess showPreprintsProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
showPreprintsProcess.setProcessEnvironment( env ); showPreprintsProcess.setProcessEnvironment(env);
QString program{ settings->fileMngr }; QString program{settings->fileMngr};
QStringList arguments{ QStringList{} << settings->lcDataDir + "/preprints" }; QStringList arguments{QStringList{} << settings->lcDataDir + "/preprints"};
showPreprintsProcess.startDetached( program, arguments ); showPreprintsProcess.startDetached(program, arguments);
// Output message via the debug messages tab // Output message via the debug messages tab
qDebug() << program << arguments.join( " " ); qDebug() << program << arguments.join(" ");
} }
void lc::Lablib::StartNewSession( QVector< Client* > argAssocCl, void lc::Lablib::StartNewSession(QVector<Client *> argAssocCl,
QString argParticipNameReplacement, QString argParticipNameReplacement,
bool argPrintLocalReceipts, QString argReceiptsHeader, bool argPrintLocalReceipts,
QString argzTreeDataTargetPath, quint16 argzTreePort, QString argReceiptsHeader,
QString argzTreeVersion ) { QString argzTreeDataTargetPath,
if ( !QDir( argzTreeDataTargetPath ).exists() ) { quint16 argzTreePort,
QMessageBox messageBox{ QMessageBox::Critical, tr( "Data target path does not exist" ), QString argzTreeVersion) {
tr( "Your chosen data target path does not exist." if (!QDir(argzTreeDataTargetPath).exists()) {
" Do you want it to be created automatically?" ), QMessageBox messageBox{QMessageBox::Critical,
QMessageBox::Yes | QMessageBox::No }; tr("Data target path does not exist"),
tr("Your chosen data target path does not exist."
" Do you want it to be created automatically?"),
QMessageBox::Yes | QMessageBox::No};
messageBox.exec();
if (messageBox.clickedButton() == messageBox.button(QMessageBox::No)) {
QMessageBox messageBox{
QMessageBox::Critical,
tr("Data target directory will not"
" be created"),
tr("Your chosen data target directory does not exist and"
" will not be created. Please choose another one."),
QMessageBox::Ok};
messageBox.exec();
return;
} else {
if (!QDir().mkpath(argzTreeDataTargetPath)) {
QMessageBox messageBox{
QMessageBox::Critical,
tr("Data target directory could"
" not be created"),
tr("Your chosen data target directory does not exist"
" and could not be created. Please choose another"
" one."),
QMessageBox::Ok};
messageBox.exec(); messageBox.exec();
if ( messageBox.clickedButton() == messageBox.button( QMessageBox::No ) ) { return;
QMessageBox messageBox{ QMessageBox::Critical, tr( "Data target directory will not" }
" be created" ),
tr( "Your chosen data target directory does not exist and"
" will not be created. Please choose another one." ),
QMessageBox::Ok };
messageBox.exec();
return;
} else {
if ( !QDir().mkpath( argzTreeDataTargetPath ) ) {
QMessageBox messageBox{ QMessageBox::Critical, tr( "Data target directory could"
" not be created" ),
tr( "Your chosen data target directory does not exist"
" and could not be created. Please choose another"
" one." ), QMessageBox::Ok };
messageBox.exec();
return;
}
}
}
try {
sessionsModel->push_back( new Session{ std::move( argAssocCl ),
argzTreeDataTargetPath,
argzTreePort, argzTreeVersion,
argPrintLocalReceipts,
argParticipNameReplacement,
argReceiptsHeader } );
occupiedPorts.append( sessionsModel->back()->zTreePort );
}
catch ( Session::lcDataTargetPathCreationFailed ) {
QMessageBox::information( nullptr, tr( "Chosen data target path could not be created" ),
tr( "The path specified by your chosen data target path '%1'"
" could not be created. Please check if it is a valid"
" location and you have all needed permissions." )
.arg( argzTreeDataTargetPath ) );
} }
}
try {
sessionsModel->push_back(
new Session{std::move(argAssocCl), argzTreeDataTargetPath, argzTreePort,
argzTreeVersion, argPrintLocalReceipts,
argParticipNameReplacement, argReceiptsHeader});
occupiedPorts.append(sessionsModel->back()->zTreePort);
} catch (Session::lcDataTargetPathCreationFailed) {
QMessageBox::information(
nullptr, tr("Chosen data target path could not be created"),
tr("The path specified by your chosen data target path '%1'"
" could not be created. Please check if it is a valid"
" location and you have all needed permissions.")
.arg(argzTreeDataTargetPath));
}
} }
void lc::Lablib::SetLocalZLeafDefaultName( const QString &argName ) { void lc::Lablib::SetLocalZLeafDefaultName(const QString &argName) {
settings->SetLocalzLeafName( argName ); settings->SetLocalzLeafName(argName);
labSettings.setValue( "local_zLeaf_name", argName ); labSettings.setValue("local_zLeaf_name", argName);
} }
//Returns the commandline that is issued on the client when zleaf is started // Returns the commandline that is issued on the client when zleaf is started
QStringList lc::Lablib::getzLeafArgs( int sessionPort, QString zleafVersion ){ QStringList lc::Lablib::getzLeafArgs(int sessionPort, QString zleafVersion) {
QStringList arguments; QStringList arguments;
if ( sessionPort == 7000 ) { if (sessionPort == 7000) {
arguments << "DISPLAY=:0.0" << settings->tasksetCmd << "0x00000001" << settings->wineCmd arguments << "DISPLAY=:0.0" << settings->tasksetCmd << "0x00000001"
<< QString{ settings->zTreeInstDir + "/zTree_" + zleafVersion + "/zleaf.exe" } << settings->wineCmd
<< "/server" << settings->serverIP; << QString{settings->zTreeInstDir + "/zTree_" + zleafVersion +
} else { "/zleaf.exe"}
arguments << "DISPLAY=:0.0" << settings->tasksetCmd << "0x00000001" << settings->wineCmd << "/server" << settings->serverIP;
<< QString{ settings->zTreeInstDir + "/zTree_" + zleafVersion + "/zleaf.exe" } } else {
<< "/server" << settings->serverIP << "/channel" arguments << "DISPLAY=:0.0" << settings->tasksetCmd << "0x00000001"
<< QString::number( sessionPort- 7000 ); << settings->wineCmd
} << QString{settings->zTreeInstDir + "/zTree_" + zleafVersion +
"/zleaf.exe"}
//Return the crafted QStringList << "/server" << settings->serverIP << "/channel"
return arguments; << QString::number(sessionPort - 7000);
}
// Return the crafted QStringList
return arguments;
} }

@ -45,87 +45,95 @@
#include "sessionsmodel.h" #include "sessionsmodel.h"
#include "settings.h" #include "settings.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
namespace lc { namespace lc {
//! This class represents the entire lab and running sessions. //! This class represents the entire lab and running sessions.
/*! /*!
This class contains elements and functions needed to represent the lab and running sessions. This class contains elements and functions needed to represent the lab and
running sessions.
*/ */
class Lablib : public QObject class Lablib : public QObject {
{ Q_OBJECT
Q_OBJECT
public: public:
/*! /*!
* \brief Lablib's constructor * \brief Lablib's constructor
* \param[in] argParent This 'lcLablib' instance's parent QObject * \param[in] argParent This 'lcLablib' instance's parent QObject
*/ */
Lablib( QObject *argParent = nullptr ); Lablib(QObject *argParent = nullptr);
/** Lablib's destructor /** Lablib's destructor
*/ */
~Lablib(); ~Lablib();
/*! /*!
* \brief CheckIfUserIsAdmin checks if the account with the passed user name has administrative rights * \brief CheckIfUserIsAdmin checks if the account with the passed user name
* \param argUserName The account name which shall checked for administrative rights * has administrative rights \param argUserName The account name which shall
* \return True, if the account has administrative rights; false, otherwise * checked for administrative rights \return True, if the account has
*/ * administrative rights; false, otherwise
bool CheckIfUserIsAdmin() const; */
/** Returns a pointer to a QVector<unsigned int> containing all by sessions occupied ports bool CheckIfUserIsAdmin() const;
* /** Returns a pointer to a QVector<unsigned int> containing all by sessions
* @return A pointer to a QVector<unsigned int> containing all occupied ports * occupied ports
*/ *
const QVector< quint16 > &GetOccupiedPorts () const { return occupiedPorts; } * @return A pointer to a QVector<unsigned int> containing all occupied ports
/** Returns a pointer to the QAbstractTableModel storing the Session instances */
* const QVector<quint16> &GetOccupiedPorts() const { return occupiedPorts; }
* @return A pointer to the QAbstractTableModel storing the Session instances /** Returns a pointer to the QAbstractTableModel storing the Session instances
*/ *
SessionsModel *GetSessionsModel () const { return sessionsModel; } * @return A pointer to the QAbstractTableModel storing the Session instances
//! Sets the default name of local zLeaf instances */
/** SessionsModel *GetSessionsModel() const { return sessionsModel; }
* @param argName The default name local zLeaf instances shall have //! Sets the default name of local zLeaf instances
*/ /**
void SetLocalZLeafDefaultName( const QString &argName ); * @param argName The default name local zLeaf instances shall have
void ShowOrsee(); */
void ShowPreprints(); void SetLocalZLeafDefaultName(const QString &argName);
void StartNewSession( QVector< Client* > argAssocCl, QString argParticipNameReplacement, void ShowOrsee();
bool argPrintLocalReceipts, QString argReceiptsHeader, void ShowPreprints();
QString argzTreeDataTargetPath, quint16 argzTreePort, void StartNewSession(QVector<Client *> argAssocCl,
QString argzTreeVersion ); QString argParticipNameReplacement,
bool argPrintLocalReceipts, QString argReceiptsHeader,
/*! QString argzTreeDataTargetPath, quint16 argzTreePort,
* \brief Returns the commandline to issue on the client(s) in order to start zLeaf QString argzTreeVersion);
* @param sessionPort The port zLeaf shall connect to
* @param zLeafVersion zLeaf Version to start /*!
*/ * \brief Returns the commandline to issue on the client(s) in order to start
QStringList getzLeafArgs( int sessionPort, QString zleafVersion ); * zLeaf
* @param sessionPort The port zLeaf shall connect to
* @param zLeafVersion zLeaf Version to start
*/
QStringList getzLeafArgs(int sessionPort, QString zleafVersion);
public slots: public slots:
signals: signals:
void ZLEAF_RUNNING( QString argClientIP ); void ZLEAF_RUNNING(QString argClientIP);
private slots: private slots:
//! Gets the output from NetstatAgent //! Gets the output from NetstatAgent
void GotNetstatQueryResult( QStringList *argActiveZLeafConnections ); void GotNetstatQueryResult(QStringList *argActiveZLeafConnections);
private: private:
//! Detects installed zTree version and LaTeX headers //! Detects installed zTree version and LaTeX headers
void DetectInstalledZTreeVersionsAndLaTeXHeaders(); void DetectInstalledZTreeVersionsAndLaTeXHeaders();
/** Reads all settings from the QSettings 'labSettings' object. /** Reads all settings from the QSettings 'labSettings' object.
*/ */
void ReadSettings(); void ReadSettings();
ClientHelpNotificationServer *clientHelpNotificationServer = nullptr; //! A server to retrieve help requests from the clients ClientHelpNotificationServer *clientHelpNotificationServer =
QSettings labSettings; nullptr; //! A server to retrieve help requests from the clients
NetstatAgent *netstatAgent = nullptr; //! Tries to detect active zLeaf connections from the clients QSettings labSettings;
QThread netstatThread; NetstatAgent *netstatAgent =
QTimer *netstatTimer = nullptr; //! A timer for regular execution of the NetstatAgent instance's request mechanism nullptr; //! Tries to detect active zLeaf connections from the clients
QVector< quint16 > occupiedPorts; QThread netstatThread;
SessionsModel *sessionsModel = nullptr; //! A derivation from QAbstractTableModel used to store the single Session instances QTimer *netstatTimer = nullptr; //! A timer for regular execution of the
//! NetstatAgent instance's request mechanism
QVector<quint16> occupiedPorts;
SessionsModel *sessionsModel =
nullptr; //! A derivation from QAbstractTableModel used to store the
//! single Session instances
}; };
} } // namespace lc
#endif // LABLIB_H #endif // LABLIB_H

@ -19,36 +19,40 @@
#include "netstatagent.h" #include "netstatagent.h"
lc::NetstatAgent::NetstatAgent( const QString &argNetstatCommand, QObject *argParent ) : lc::NetstatAgent::NetstatAgent(const QString &argNetstatCommand,
QObject{ argParent }, QObject *argParent)
extractionRegexp{ "\\d+\\.\\d+\\.\\d+\\.\\d+" }, : QObject{argParent}, extractionRegexp{"\\d+\\.\\d+\\.\\d+\\.\\d+"},
netstatArguments{ QStringList{} << "-anp" << "--tcp" }, netstatArguments{QStringList{} << "-anp"
netstatCommand{ argNetstatCommand }, << "--tcp"},
netstatQueryProcess{ this }, netstatCommand{argNetstatCommand}, netstatQueryProcess{this},
searchRegexp{ "\\W(ESTABLISHED|VERBUNDEN)( +)(\\d+)(/ztree.exe)\\W", QRegularExpression::CaseInsensitiveOption } searchRegexp{"\\W(ESTABLISHED|VERBUNDEN)( +)(\\d+)(/ztree.exe)\\W",
{ QRegularExpression::CaseInsensitiveOption} {
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
netstatQueryProcess.setProcessEnvironment( env ); netstatQueryProcess.setProcessEnvironment(env);
} }
void lc::NetstatAgent::QueryClientConnections() { void lc::NetstatAgent::QueryClientConnections() {
netstatQueryProcess.start( netstatCommand, netstatArguments ); netstatQueryProcess.start(netstatCommand, netstatArguments);
if ( !netstatQueryProcess.waitForFinished( 400 ) ) { if (!netstatQueryProcess.waitForFinished(400)) {
emit QueryFinished( nullptr ); emit QueryFinished(nullptr);
} else { } else {
// Get all 'netstat_query_process' standard output and store it temporarily in 'temp_strings' // Get all 'netstat_query_process' standard output and store it temporarily
QByteArray netstatQueryProcessOutputByteArray = netstatQueryProcess.readAllStandardOutput(); // in 'temp_strings'
QString netstatQueryProcessOutputString( netstatQueryProcessOutputByteArray ); QByteArray netstatQueryProcessOutputByteArray =
QStringList tempStrings = netstatQueryProcessOutputString.split( '\n', QString::SkipEmptyParts ); netstatQueryProcess.readAllStandardOutput();
QString netstatQueryProcessOutputString(netstatQueryProcessOutputByteArray);
QStringList tempStrings =
netstatQueryProcessOutputString.split('\n', QString::SkipEmptyParts);
QStringList *netstatQueryProcessOutput = new QStringList; QStringList *netstatQueryProcessOutput = new QStringList;
for ( auto s: tempStrings ) { for (auto s : tempStrings) {
if ( s.contains( searchRegexp ) ) { if (s.contains(searchRegexp)) {
QRegularExpressionMatch match = extractionRegexp.match( s, s.indexOf( ':', 0, Qt::CaseInsensitive ) ); QRegularExpressionMatch match =
netstatQueryProcessOutput->append( match.captured() ); extractionRegexp.match(s, s.indexOf(':', 0, Qt::CaseInsensitive));
} netstatQueryProcessOutput->append(match.captured());
} }
emit QueryFinished(netstatQueryProcessOutput);
} }
emit QueryFinished(netstatQueryProcessOutput);
}
} }

@ -27,31 +27,34 @@
namespace lc { namespace lc {
//! The NetstatAgent class is used to do repetitive runs of the 'netstat' program to check for active zLeaf connections. //! The NetstatAgent class is used to do repetitive runs of the 'netstat'
//! program to check for active zLeaf connections.
/*! /*!
This class is just used for repetive executions of netstat. This class is just used for repetive executions of netstat.
*/ */
class NetstatAgent : public QObject { class NetstatAgent : public QObject {
Q_OBJECT Q_OBJECT
public: public:
explicit NetstatAgent( const QString &argNetstatCommand, QObject *argParent = nullptr ); explicit NetstatAgent(const QString &argNetstatCommand,
QObject *argParent = nullptr);
signals: signals:
//! This signal is emitted if the query of the currently active zLeaf connections finished //! This signal is emitted if the query of the currently active zLeaf
void QueryFinished(QStringList *argActiveZLeafConnections); //! connections finished
void QueryFinished(QStringList *argActiveZLeafConnections);
public slots: public slots:
void QueryClientConnections(); void QueryClientConnections();
private: private:
const QRegularExpression extractionRegexp; const QRegularExpression extractionRegexp;
const QStringList netstatArguments; const QStringList netstatArguments;
const QString &netstatCommand; const QString &netstatCommand;
QProcess netstatQueryProcess; QProcess netstatQueryProcess;
const QRegularExpression searchRegexp; const QRegularExpression searchRegexp;
}; };
} } // namespace lc
#endif // NETSTATAGENT_H #endif // NETSTATAGENT_H

@ -24,267 +24,293 @@
#include "receipts_handler.h" #include "receipts_handler.h"
#include "settings.h" #include "settings.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
lc::ReceiptsHandler::ReceiptsHandler( const QString &argZTreeDataTargetPath, lc::ReceiptsHandler::ReceiptsHandler(
bool argPrintReceiptsForLocalClients, const QString &argZTreeDataTargetPath, bool argPrintReceiptsForLocalClients,
const QString &argAnonymousReceiptsPlaceholder, const QString &argAnonymousReceiptsPlaceholder,
const QString &argLatexHeaderName, const QString &argLatexHeaderName, QObject *argParent)
QObject *argParent ) : : QObject{argParent},
QObject{ argParent }, anonymousReceiptsPlaceholder{argAnonymousReceiptsPlaceholder},
anonymousReceiptsPlaceholder{ argAnonymousReceiptsPlaceholder }, dateString{QDateTime::currentDateTime().toString("yyMMdd_hhmm")},
dateString{ QDateTime::currentDateTime().toString( "yyMMdd_hhmm" ) }, expectedPaymentFileName{dateString + ".pay"},
expectedPaymentFileName{ dateString + ".pay" }, expectedPaymentFilePath{argZTreeDataTargetPath + "/" + dateString +
expectedPaymentFilePath{ argZTreeDataTargetPath + "/" + dateString + ".pay" }, ".pay"},
latexHeaderName{ argLatexHeaderName }, latexHeaderName{argLatexHeaderName}, paymentFile{expectedPaymentFilePath},
paymentFile{ expectedPaymentFilePath }, printReceiptsForLocalClients{argPrintReceiptsForLocalClients},
printReceiptsForLocalClients{ argPrintReceiptsForLocalClients }, timer{new QTimer{this}}, zTreeDataTargetPath{argZTreeDataTargetPath} {
timer{ new QTimer{ this } }, qDebug() << "Expected payment file name is:" << expectedPaymentFilePath;
zTreeDataTargetPath{ argZTreeDataTargetPath }
{ // Create a QTimer regularly checking if the payment file was created and
qDebug() << "Expected payment file name is:" << expectedPaymentFilePath; // print it if so
connect(timer, &QTimer::timeout, this, &ReceiptsHandler::PrintReceipts);
// Create a QTimer regularly checking if the payment file was created and print it if so timer->start(2000);
connect( timer, &QTimer::timeout,
this, &ReceiptsHandler::PrintReceipts );
timer->start( 2000 );
} }
lc::ReceiptsHandler::ReceiptsHandler( const QString &argZTreeDataTargetPath, lc::ReceiptsHandler::ReceiptsHandler(
bool argPrintReceiptsForLocalClients, const QString &argZTreeDataTargetPath, bool argPrintReceiptsForLocalClients,
const QString &argAnonymousReceiptsPlaceholder, const QString &argAnonymousReceiptsPlaceholder,
const QString &argLatexHeaderName, const QString &argLatexHeaderName, const QString &argDateString,
const QString &argDateString, QObject *argParent ) : QObject *argParent)
QObject{ argParent }, : QObject{argParent},
anonymousReceiptsPlaceholder{ argAnonymousReceiptsPlaceholder }, anonymousReceiptsPlaceholder{argAnonymousReceiptsPlaceholder},
dateString{ argDateString }, dateString{argDateString}, expectedPaymentFileName{argDateString +
expectedPaymentFileName{ argDateString + ".pay" }, ".pay"},
expectedPaymentFilePath{ argZTreeDataTargetPath + "/" + argDateString + ".pay" }, expectedPaymentFilePath{argZTreeDataTargetPath + "/" + argDateString +
latexHeaderName{ argLatexHeaderName }, ".pay"},
paymentFile{ expectedPaymentFilePath }, latexHeaderName{argLatexHeaderName}, paymentFile{expectedPaymentFilePath},
printReceiptsForLocalClients{ argPrintReceiptsForLocalClients }, printReceiptsForLocalClients{argPrintReceiptsForLocalClients},
zTreeDataTargetPath{ argZTreeDataTargetPath } zTreeDataTargetPath{argZTreeDataTargetPath} {
{ qDebug() << "Expected payment file name is:" << expectedPaymentFilePath;
qDebug() << "Expected payment file name is:" << expectedPaymentFilePath;
PrintReceipts();
PrintReceipts();
} }
void lc::ReceiptsHandler::PrintReceipts() { void lc::ReceiptsHandler::PrintReceipts() {
// If the payment file exists, print it // If the payment file exists, print it
if ( paymentFile.exists() ) { if (paymentFile.exists()) {
qDebug() << "The payment file has been created and will be printed"; qDebug() << "The payment file has been created and will be printed";
if ( timer ) { if (timer) {
timer->stop(); timer->stop();
}
CreateReceiptsFromPaymentFile();
} }
CreateReceiptsFromPaymentFile();
}
} }
void lc::ReceiptsHandler::CreateReceiptsFromPaymentFile() { void lc::ReceiptsHandler::CreateReceiptsFromPaymentFile() {
// Get the data needed for receipts creation from the payment file // Get the data needed for receipts creation from the payment file
QVector<QString> *rawParticipantsData = nullptr; QVector<QString> *rawParticipantsData = nullptr;
rawParticipantsData = GetParticipantsDataFromPaymentFile(); rawParticipantsData = GetParticipantsDataFromPaymentFile();
for ( int i = 0; i < rawParticipantsData->size(); i++ ) { for (int i = 0; i < rawParticipantsData->size(); i++) {
qDebug() << "Payment file line" << QString::number( i ) << ":\t" << rawParticipantsData->at( i ); qDebug() << "Payment file line" << QString::number(i) << ":\t"
} << rawParticipantsData->at(i);
}
// Extract the data of the participant's whose receipts shall be printed
/* The tab separated fields in the payment file are: // Extract the data of the participant's whose receipts shall be printed
* SUBJECT COMPUTER INTERESTED NAME PROFIT SIGNATURE /* The tab separated fields in the payment file are:
*/ * SUBJECT COMPUTER INTERESTED NAME PROFIT SIGNATURE
QVector<paymentEntry_t*> *participants = new QVector<paymentEntry_t*>; */
double overall_payoff = 0.0; QVector<paymentEntry_t *> *participants = new QVector<paymentEntry_t *>;
for ( QVector<QString>::iterator it = rawParticipantsData->begin(); it != rawParticipantsData->end() - 1; ++it ) { double overall_payoff = 0.0;
// Split the lines containing the participants' data into their inidivual parts for (QVector<QString>::iterator it = rawParticipantsData->begin();
QStringList temp_participant_data = it->split('\t', QString::KeepEmptyParts); it != rawParticipantsData->end() - 1; ++it) {
qDebug() << temp_participant_data.join( " - " ); // Split the lines containing the participants' data into their inidivual
if ( !printReceiptsForLocalClients && temp_participant_data.at( 3 ).contains( "local" ) ) { // parts
qDebug() << "Receipt for local client" << temp_participant_data.at( 1 ) << "will not be printed."; QStringList temp_participant_data =
} it->split('\t', QString::KeepEmptyParts);
else { qDebug() << temp_participant_data.join(" - ");
// Create a new struct instance for participant data and fill it if (!printReceiptsForLocalClients &&
paymentEntry_t *participant = new paymentEntry_t; temp_participant_data.at(3).contains("local")) {
participant->computer = temp_participant_data.at(1); qDebug() << "Receipt for local client" << temp_participant_data.at(1)
participant->name = temp_participant_data.at(3); << "will not be printed.";
participant->payoff = temp_participant_data.at(4).toDouble(); } else {
overall_payoff += participant->payoff; // Create a new struct instance for participant data and fill it
participants->append(participant); paymentEntry_t *participant = new paymentEntry_t;
} participant->computer = temp_participant_data.at(1);
} participant->name = temp_participant_data.at(3);
delete rawParticipantsData; participant->payoff = temp_participant_data.at(4).toDouble();
rawParticipantsData = nullptr; overall_payoff += participant->payoff;
participants->append(participant);
// Make receipts overview anonymous if requested (at this stage just names are removed, so that the overview still containts the client names
if ( !anonymousReceiptsPlaceholder.isEmpty() ) {
MakeReceiptsAnonymous( participants, false );
}
// Load the LaTeX header
QString *latexText = LoadLatexHeader();
if ( latexText == nullptr ) {
for ( auto s : *participants ) {
delete s;
}
delete participants;
participants = nullptr;
return;
}
// Write the comprehension table
latexText->append( "\n\\COMPREHENSION{\n" );
unsigned short int zeile = 0;
for ( auto s : *participants ) {
latexText->append( expectedPaymentFileName + " & " + s->computer + " & " + s->name + " & " + QString::number( s->payoff, 'f', 2 ) + " \\EUR\\\\\n" );
if ( zeile % 2 == 0 ) {
latexText->append( "\\rowcolor[gray]{0.9}\n" );
}
++zeile;
} }
}
// MISSING: Appending show up entries to the overview delete rawParticipantsData;
rawParticipantsData = nullptr;
// Make also the clients on the receipts anonymous. This is done as second step, so that the beforehand created overview still contains the clients
if ( !anonymousReceiptsPlaceholder.isEmpty() ) { // Make receipts overview anonymous if requested (at this stage just names are
MakeReceiptsAnonymous( participants, true ); // removed, so that the overview still containts the client names
} if (!anonymousReceiptsPlaceholder.isEmpty()) {
MakeReceiptsAnonymous(participants, false);
// Add the LaTeX middle sequence }
latexText->append( "}{" + QString::number( overall_payoff, 'f', 2 ) + "}\n\n%%Einzelquittungen\n" );
// Load the LaTeX header
// Write the single receipts QString *latexText = LoadLatexHeader();
for ( auto s : *participants ) { if (latexText == nullptr) {
if ( s->payoff >= 0 ) { for (auto s : *participants) {
latexText->append( "\\GAINRECEIPT{" + expectedPaymentFileName + "}{" + s->computer + "}{" + s->name + "}{" + QString::number( s->payoff, 'f', 2 ) + "}\n" ); delete s;
}
else {
latexText->append( "\\LOSSRECEIPT{" + expectedPaymentFileName + "}{" + s->computer + "}{" + s->name + "}{" + QString::number( s->payoff, 'f', 2 ) + "}\n" );
}
delete s;
} }
delete participants; delete participants;
participants = nullptr; participants = nullptr;
return;
// Append LaTeX ending }
latexText->append( "\\end{document}" );
// Write the comprehension table
qDebug() << *latexText; latexText->append("\n\\COMPREHENSION{\n");
unsigned short int zeile = 0;
// Create the tex file for (auto s : *participants) {
QFile *texFile = new QFile{ zTreeDataTargetPath + "/" + dateString + ".tex" }; latexText->append(expectedPaymentFileName + " & " + s->computer + " & " +
qDebug() << "Tex file" << texFile->fileName() << "will be created for receipts printing."; s->name + " & " + QString::number(s->payoff, 'f', 2) +
// Clean up any already existing files " \\EUR\\\\\n");
if ( texFile->exists() ) { if (zeile % 2 == 0) {
if ( !texFile->remove() ) { latexText->append("\\rowcolor[gray]{0.9}\n");
QMessageBox messageBox( QMessageBox::Critical, "Tex file removing failed", "There already exists a tex file at '" + texFile->fileName()
+ "' which cannot be removed. The creation of the receipts printout may fail.", QMessageBox::Ok );
messageBox.exec();
}
} }
// Create a new file ++zeile;
if ( !texFile->open( QIODevice::Text | QIODevice::WriteOnly ) ) { }
QMessageBox messageBox( QMessageBox::Critical, "Tex file creation failed", "The creation of the tex file for receipts printing at '" + texFile->fileName()
+ "' failed. Receipts printing will not work.", QMessageBox::Ok ); // MISSING: Appending show up entries to the overview
messageBox.exec();
return; // Make also the clients on the receipts anonymous. This is done as second
// step, so that the beforehand created overview still contains the clients
if (!anonymousReceiptsPlaceholder.isEmpty()) {
MakeReceiptsAnonymous(participants, true);
}
// Add the LaTeX middle sequence
latexText->append("}{" + QString::number(overall_payoff, 'f', 2) +
"}\n\n%%Einzelquittungen\n");
// Write the single receipts
for (auto s : *participants) {
if (s->payoff >= 0) {
latexText->append("\\GAINRECEIPT{" + expectedPaymentFileName + "}{" +
s->computer + "}{" + s->name + "}{" +
QString::number(s->payoff, 'f', 2) + "}\n");
} else {
latexText->append("\\LOSSRECEIPT{" + expectedPaymentFileName + "}{" +
s->computer + "}{" + s->name + "}{" +
QString::number(s->payoff, 'f', 2) + "}\n");
} }
delete s;
// Open a QTextStream to write to the file }
QTextStream out( texFile ); delete participants;
participants = nullptr;
out << *latexText;
delete latexText; // Append LaTeX ending
latexText = nullptr; latexText->append("\\end{document}");
receiptsPrinter = new ReceiptsPrinter{ dateString, zTreeDataTargetPath, this }; qDebug() << *latexText;
receiptsPrinter->start();
connect( receiptsPrinter, &ReceiptsPrinter::PrintingFinished, // Create the tex file
this, &ReceiptsHandler::DeleteReceiptsPrinterInstance ); QFile *texFile = new QFile{zTreeDataTargetPath + "/" + dateString + ".tex"};
connect( receiptsPrinter, &ReceiptsPrinter::ErrorOccurred, qDebug() << "Tex file" << texFile->fileName()
this, &ReceiptsHandler::DisplayMessageBox ); << "will be created for receipts printing.";
// Clean up any already existing files
// Clean up if (texFile->exists()) {
texFile->close(); if (!texFile->remove()) {
delete texFile; QMessageBox messageBox(QMessageBox::Critical, "Tex file removing failed",
"There already exists a tex file at '" +
texFile->fileName() +
"' which cannot be removed. The creation of "
"the receipts printout may fail.",
QMessageBox::Ok);
messageBox.exec();
}
}
// Create a new file
if (!texFile->open(QIODevice::Text | QIODevice::WriteOnly)) {
QMessageBox messageBox(
QMessageBox::Critical, "Tex file creation failed",
"The creation of the tex file for receipts printing at '" +
texFile->fileName() + "' failed. Receipts printing will not work.",
QMessageBox::Ok);
messageBox.exec();
return;
}
// Open a QTextStream to write to the file
QTextStream out(texFile);
out << *latexText;
delete latexText;
latexText = nullptr;
receiptsPrinter = new ReceiptsPrinter{dateString, zTreeDataTargetPath, this};
receiptsPrinter->start();
connect(receiptsPrinter, &ReceiptsPrinter::PrintingFinished, this,
&ReceiptsHandler::DeleteReceiptsPrinterInstance);
connect(receiptsPrinter, &ReceiptsPrinter::ErrorOccurred, this,
&ReceiptsHandler::DisplayMessageBox);
// Clean up
texFile->close();
delete texFile;
} }
void lc::ReceiptsHandler::DeleteReceiptsPrinterInstance() { void lc::ReceiptsHandler::DeleteReceiptsPrinterInstance() {
receiptsPrinter->quit(); receiptsPrinter->quit();
receiptsPrinter->wait(); receiptsPrinter->wait();
receiptsPrinter->deleteLater(); receiptsPrinter->deleteLater();
receiptsPrinter = nullptr; receiptsPrinter = nullptr;
qDebug() << "Deleted 'ReceiptsPrinter' instance."; qDebug() << "Deleted 'ReceiptsPrinter' instance.";
emit PrintingFinished(); emit PrintingFinished();
} }
void lc::ReceiptsHandler::DisplayMessageBox( QString *argErrorMessage, QString *argHeading ) { void lc::ReceiptsHandler::DisplayMessageBox(QString *argErrorMessage,
QMessageBox messageBox( QMessageBox::Warning, *argHeading, *argErrorMessage, QMessageBox::Ok ); QString *argHeading) {
delete argHeading; QMessageBox messageBox(QMessageBox::Warning, *argHeading, *argErrorMessage,
delete argErrorMessage; QMessageBox::Ok);
messageBox.exec(); delete argHeading;
delete argErrorMessage;
messageBox.exec();
} }
QVector<QString> *lc::ReceiptsHandler::GetParticipantsDataFromPaymentFile() { QVector<QString> *lc::ReceiptsHandler::GetParticipantsDataFromPaymentFile() {
// Create the vector to store the single lines of the file // Create the vector to store the single lines of the file
QVector<QString> *participantsData = new QVector<QString>; QVector<QString> *participantsData = new QVector<QString>;
// Open the payment file for reading and create a QTextStream // Open the payment file for reading and create a QTextStream
paymentFile.open( QIODevice::ReadOnly | QIODevice::Text ); paymentFile.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in( &paymentFile ); QTextStream in(&paymentFile);
in.setCodec( "ISO 8859-1" ); in.setCodec("ISO 8859-1");
// Read the file line by line and store them in the vector // Read the file line by line and store them in the vector
while ( true ) { while (true) {
QString line = in.readLine(); QString line = in.readLine();
if ( line.isNull() ) { if (line.isNull()) {
break; break;
}
participantsData->append( line );
} }
participantsData->append(line);
}
// Remove the first line, since it is not needed // Remove the first line, since it is not needed
participantsData->erase( participantsData->begin() ); participantsData->erase(participantsData->begin());
// Close the file afterwards // Close the file afterwards
paymentFile.close(); paymentFile.close();
return participantsData; return participantsData;
} }
QString *lc::ReceiptsHandler::LoadLatexHeader() { QString *lc::ReceiptsHandler::LoadLatexHeader() {
// Prepare all facilities to read the latex header file // Prepare all facilities to read the latex header file
QFile latexHeaderFile( settings->lcDataDir + "/" + latexHeaderName + "_header.tex" ); QFile latexHeaderFile(settings->lcDataDir + "/" + latexHeaderName +
if ( !latexHeaderFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) { "_header.tex");
QMessageBox messageBox{ QMessageBox::Critical, tr( "LaTeX header could not be loaded" ), if (!latexHeaderFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
tr( "The LaTeX header at '%1/%2_header.tex' could not be loaded. Receipts printing will not work." ) QMessageBox messageBox{QMessageBox::Critical,
.arg( settings->lcDataDir ).arg( latexHeaderName ), QMessageBox::Ok }; tr("LaTeX header could not be loaded"),
messageBox.exec(); tr("The LaTeX header at '%1/%2_header.tex' could "
return nullptr; "not be loaded. Receipts printing will not work.")
} .arg(settings->lcDataDir)
QTextStream in( &latexHeaderFile ); .arg(latexHeaderName),
QMessageBox::Ok};
messageBox.exec();
return nullptr;
}
QTextStream in(&latexHeaderFile);
QString *header = nullptr; QString *header = nullptr;
header = new QString( in.readAll() ); header = new QString(in.readAll());
latexHeaderFile.close(); latexHeaderFile.close();
return header; return header;
} }
void lc::ReceiptsHandler::MakeReceiptsAnonymous( QVector<paymentEntry_t*> *argDataVector, bool argAlsoAnonymizeClients ) { void lc::ReceiptsHandler::MakeReceiptsAnonymous(
if ( !argAlsoAnonymizeClients ) { QVector<paymentEntry_t *> *argDataVector, bool argAlsoAnonymizeClients) {
qDebug() << "Names are made anonymous"; if (!argAlsoAnonymizeClients) {
for ( QVector< paymentEntry_t* >::iterator it = argDataVector->begin(); it != argDataVector->end(); ++it ) { qDebug() << "Names are made anonymous";
( *it )->name = anonymousReceiptsPlaceholder; for (QVector<paymentEntry_t *>::iterator it = argDataVector->begin();
} it != argDataVector->end(); ++it) {
(*it)->name = anonymousReceiptsPlaceholder;
} }
else { } else {
qDebug() << "Clients and names are made anonymous"; qDebug() << "Clients and names are made anonymous";
for ( QVector< paymentEntry_t* >::iterator it = argDataVector->begin(); it != argDataVector->end(); ++it ) { for (QVector<paymentEntry_t *>::iterator it = argDataVector->begin();
( *it )->name = anonymousReceiptsPlaceholder; it != argDataVector->end(); ++it) {
( *it )->computer = "\\hspace{1cm}"; (*it)->name = anonymousReceiptsPlaceholder;
} (*it)->computer = "\\hspace{1cm}";
} }
}
} }

@ -34,60 +34,83 @@ namespace lc {
//! A struct representing one payoff entry. //! A struct representing one payoff entry.
/*! /*!
This class represents a single payoff entry which will be used in the receipts creation process. Multiple instances of this will be used to represent the individual participants' outcomes. This class represents a single payoff entry which will be used in the receipts
creation process. Multiple instances of this will be used to represent the
individual participants' outcomes.
*/ */
struct paymentEntry_t {QString computer; QString name; double payoff;}; struct paymentEntry_t {
QString computer;
QString name;
double payoff;
};
//! A class to handle receipts printing. //! A class to handle receipts printing.
/*! /*!
This class is element of every session and is used to handle the receipts printing. This class is element of every session and is used to handle the receipts
printing.
*/ */
class ReceiptsHandler : public QObject { class ReceiptsHandler : public QObject {
Q_OBJECT Q_OBJECT
public: public:
explicit ReceiptsHandler( const QString &argZTreeDataTargetPath, explicit ReceiptsHandler(const QString &argZTreeDataTargetPath,
bool argPrintReceiptsForLocalClients, bool argPrintReceiptsForLocalClients,
const QString &argAnonymousReceiptsPlaceholder, const QString &argAnonymousReceiptsPlaceholder,
const QString &argLatexHeaderName, QObject *argParent = nullptr ); const QString &argLatexHeaderName,
explicit ReceiptsHandler( const QString &argZTreeDataTargetPath, QObject *argParent = nullptr);
bool argPrintReceiptsForLocalClients, explicit ReceiptsHandler(const QString &argZTreeDataTargetPath,
const QString &argAnonymousReceiptsPlaceholder, bool argPrintReceiptsForLocalClients,
const QString &argLatexHeaderName, const QString &argAnonymousReceiptsPlaceholder,
const QString &argDateString, QObject *argParent = nullptr ); const QString &argLatexHeaderName,
const QString &argDateString,
QObject *argParent = nullptr);
signals: signals:
void PrintingFinished(); void PrintingFinished();
private slots: private slots:
/*! Deletes the ReceiptsPrinter instance after successful printing /*! Deletes the ReceiptsPrinter instance after successful printing
*/ */
void DeleteReceiptsPrinterInstance(); void DeleteReceiptsPrinterInstance();
/*! Displays QMessageBox widgets for errors given by the ReceiptsPrinter instance /*! Displays QMessageBox widgets for errors given by the ReceiptsPrinter
*/ * instance
void DisplayMessageBox(QString *argErrorMessage, QString *argHeading); */
/*! Prints the receipts void DisplayMessageBox(QString *argErrorMessage, QString *argHeading);
*/ /*! Prints the receipts
void PrintReceipts(); */
void PrintReceipts();
private: private:
void CreateReceiptsFromPaymentFile(); void CreateReceiptsFromPaymentFile();
QVector<QString> *GetParticipantsDataFromPaymentFile(); QVector<QString> *GetParticipantsDataFromPaymentFile();
QString *LoadLatexHeader(); QString *LoadLatexHeader();
void MakeReceiptsAnonymous( QVector<paymentEntry_t*> *argDataVector, bool argAlsoAnonymizeClients ); void MakeReceiptsAnonymous(QVector<paymentEntry_t *> *argDataVector,
bool argAlsoAnonymizeClients);
const QString anonymousReceiptsPlaceholder; //!< Placeholder which shall be inserted for participant names if anonymous printing is desired (QString != "") const QString
const QString dateString; //!< The expected date string of the payment file in form 'yyMMdd_hhmm' anonymousReceiptsPlaceholder; //!< Placeholder which shall be inserted for
const QString expectedPaymentFileName; //!< The name of the expected payment file //!< participant names if anonymous printing
const QString expectedPaymentFilePath; //!< The path of the expected payment file //!< is desired (QString != "")
const QString latexHeaderName; //!< The name of the chosen LaTeX header template const QString dateString; //!< The expected date string of the payment file in
QFile paymentFile; //!< A pointer to the '*.pay' file being watched for existance and starting the printing process //!< form 'yyMMdd_hhmm'
const bool printReceiptsForLocalClients; //!< Stores if receipts shall be printed for local clients const QString
ReceiptsPrinter *receiptsPrinter = nullptr; //!< Creates new thread for receipts printing expectedPaymentFileName; //!< The name of the expected payment file
QTimer *timer = nullptr; //!< Used for regular checking if the payment file was created const QString
const QString zTreeDataTargetPath; //!< A reference to the data target path stored in the session class instance expectedPaymentFilePath; //!< The path of the expected payment file
const QString
latexHeaderName; //!< The name of the chosen LaTeX header template
QFile paymentFile; //!< A pointer to the '*.pay' file being watched for
//!< existance and starting the printing process
const bool printReceiptsForLocalClients; //!< Stores if receipts shall be
//!< printed for local clients
ReceiptsPrinter *receiptsPrinter =
nullptr; //!< Creates new thread for receipts printing
QTimer *timer =
nullptr; //!< Used for regular checking if the payment file was created
const QString zTreeDataTargetPath; //!< A reference to the data target path
//!< stored in the session class instance
}; };
} } // namespace lc
#endif // RECEIPTS_HANDLER_H #endif // RECEIPTS_HANDLER_H

@ -22,20 +22,13 @@
#include "receiptsprinter.h" #include "receiptsprinter.h"
#include "settings.h" #include "settings.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
lc::ReceiptsPrinter::ReceiptsPrinter( const QString &argDateString, lc::ReceiptsPrinter::ReceiptsPrinter(const QString &argDateString,
const QString &argWorkpath, const QString &argWorkpath,
QObject *argParent ) : QObject *argParent)
QThread{ argParent }, : QThread{argParent}, dateString{argDateString},
dateString{ argDateString }, dvipsCmd{settings->dvipsCmd}, latexCmd{settings->latexCmd},
dvipsCmd{ settings->dvipsCmd }, lprCmd{settings->lprCmd}, postscriptViewer{settings->postscriptViewer},
latexCmd{ settings->latexCmd }, ps2pdfCmd{settings->ps2pdfCmd}, rmCmd{settings->rmCmd},
lprCmd{ settings->lprCmd }, vncViewer{settings->vncViewer}, workpath{argWorkpath} {}
postscriptViewer{ settings->postscriptViewer },
ps2pdfCmd{ settings->ps2pdfCmd },
rmCmd{ settings->rmCmd },
vncViewer{ settings->vncViewer },
workpath{ argWorkpath }
{
}

@ -33,134 +33,159 @@ namespace lc {
This class is used to do the actual printing of the receipts in an own thread. This class is used to do the actual printing of the receipts in an own thread.
*/ */
class ReceiptsPrinter : public QThread { class ReceiptsPrinter : public QThread {
Q_OBJECT Q_OBJECT
void run() Q_DECL_OVERRIDE { void run() Q_DECL_OVERRIDE {
// Compile the TeX file to dvi // Compile the TeX file to dvi
QStringList arguments; QStringList arguments;
arguments << "-interaction" << "batchmode" << QString{ dateString + ".tex" }; arguments << "-interaction"
<< "batchmode" << QString{dateString + ".tex"};
QProcess *process = nullptr;
process = new QProcess{}; QProcess *process = nullptr;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); process = new QProcess{};
process->setProcessEnvironment( env ); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
process->setWorkingDirectory( workpath ); process->setProcessEnvironment(env);
process->start( latexCmd, arguments ); process->setWorkingDirectory(workpath);
if( !process->waitForFinished( processTimeOut ) ) { process->start(latexCmd, arguments);
QMessageBox message_box{ QMessageBox::Warning, "dvi creation failed", "The creation of the receipts dvi timed out after 30 seconds. Automatic receipts creation will not work.", QMessageBox::Ok }; if (!process->waitForFinished(processTimeOut)) {
message_box.exec(); QMessageBox message_box{
delete process; QMessageBox::Warning, "dvi creation failed",
process = nullptr; "The creation of the receipts dvi timed out after 30 seconds. "
return; "Automatic receipts creation will not work.",
} QMessageBox::Ok};
delete process; message_box.exec();
process = nullptr; delete process;
process = nullptr;
return;
}
delete process;
process = nullptr;
// Convert the dvi file to postscript
arguments = QStringList{};
arguments << "-q*"
<< "-o" << QString{dateString + ".ps"}
<< QString{dateString + ".dvi"};
process = new QProcess{};
process->setProcessEnvironment(env);
process->setWorkingDirectory(workpath);
process->start(dvipsCmd, arguments);
if (!process->waitForFinished(processTimeOut)) {
emit ErrorOccurred(
new QString{
"The conversion of the receipts dvi to postscript timed out "
"after 30 seconds. Automatic receipts creation will not work."},
new QString{"dvi to postscript conversion failed"});
delete process;
process = nullptr;
return;
}
delete process;
process = nullptr;
// Print the postscript file
if (!lprCmd.isEmpty()) {
arguments = QStringList{};
arguments << QString{workpath + "/" + dateString + ".ps"};
process = new QProcess{};
process->setProcessEnvironment(env);
process->setWorkingDirectory(workpath);
process->start(lprCmd, arguments);
if (!process->waitForFinished(processTimeOut)) {
emit ErrorOccurred(
new QString{"The receipts postscript file was successfully created "
"but could not be printed."},
new QString{"Printing failed"});
}
delete process;
process = nullptr;
}
// Convert the dvi file to postscript // Convert the postscript file to pdf
if (!ps2pdfCmd.isEmpty()) {
arguments = QStringList{};
arguments << QString{workpath + "/" + dateString + ".ps"}
<< QString{workpath + "/" + dateString + ".pdf"};
process = new QProcess{};
process->setProcessEnvironment(env);
process->setWorkingDirectory(workpath);
process->start(ps2pdfCmd, arguments);
if (!process->waitForFinished(processTimeOut)) {
emit ErrorOccurred(
new QString{"The receipts were successfully printed but the "
"creation of the PDF file failed."},
new QString{"PDF creation failed"});
}
delete process;
process = nullptr;
// Show the postscript file if the conversion succeeded
if (!postscriptViewer.isEmpty()) {
arguments = QStringList{}; arguments = QStringList{};
arguments << "-q*" << "-o" << QString{ dateString + ".ps" } << QString{ dateString + ".dvi" }; arguments << QString{workpath + "/" + dateString + ".ps"};
process = new QProcess{}; process = new QProcess{};
process->setProcessEnvironment( env ); process->setProcessEnvironment(env);
process->setWorkingDirectory( workpath ); process->setWorkingDirectory(workpath);
process->start( dvipsCmd, arguments ); process->startDetached(postscriptViewer, arguments);
if( !process->waitForFinished( processTimeOut ) ) {
emit ErrorOccurred(new QString{ "The conversion of the receipts dvi to postscript timed out after 30 seconds. Automatic receipts creation will not work." }, new QString{ "dvi to postscript conversion failed" } );
delete process;
process = nullptr;
return;
}
delete process; delete process;
process = nullptr; process = nullptr;
}
}
// Print the postscript file // Clean up the zTree working path
if ( !lprCmd.isEmpty() ) { if (!rmCmd.isEmpty()) {
arguments = QStringList{}; arguments = QStringList{};
arguments << QString{ workpath + "/" + dateString + ".ps" }; arguments << QString{workpath + "/" + dateString + ".aux"}
<< QString{workpath + "/" + dateString + ".dvi"}
process = new QProcess{}; << QString{workpath + "/" + dateString + ".log"}
process->setProcessEnvironment( env ); << QString{workpath + "/" + dateString + ".tex"};
process->setWorkingDirectory( workpath );
process->start( lprCmd, arguments ); process = new QProcess{};
if( !process->waitForFinished( processTimeOut ) ) { process->setProcessEnvironment(env);
emit ErrorOccurred( new QString{ "The receipts postscript file was successfully created but could not be printed." }, new QString{ "Printing failed" } ); process->setWorkingDirectory(workpath);
} process->start(rmCmd, arguments);
delete process; if (!process->waitForFinished(processTimeOut)) {
process = nullptr; emit ErrorOccurred(
} new QString("The cleanup of the temporary files for receipts "
"creation timed out. Some spare files may be left in "
// Convert the postscript file to pdf "your zTree working directory."),
if ( !ps2pdfCmd.isEmpty() ) { new QString("Cleanup failed"));
arguments = QStringList{}; }
arguments << QString{ workpath + "/" + dateString + ".ps" } << QString{ workpath + "/" + dateString + ".pdf" }; delete process;
process = nullptr;
process = new QProcess{};
process->setProcessEnvironment( env );
process->setWorkingDirectory( workpath );
process->start( ps2pdfCmd, arguments );
if( !process->waitForFinished( processTimeOut ) ) {
emit ErrorOccurred( new QString{ "The receipts were successfully printed but the creation of the PDF file failed." }, new QString{ "PDF creation failed" } );
}
delete process;
process = nullptr;
// Show the postscript file if the conversion succeeded
if ( !postscriptViewer.isEmpty() ) {
arguments = QStringList{};
arguments << QString{ workpath + "/" + dateString + ".ps" };
process = new QProcess{};
process->setProcessEnvironment( env );
process->setWorkingDirectory( workpath );
process->startDetached( postscriptViewer, arguments );
delete process;
process = nullptr;
}
}
// Clean up the zTree working path
if ( !rmCmd.isEmpty() ) {
arguments = QStringList{};
arguments << QString{ workpath + "/" + dateString + ".aux" }
<< QString{ workpath + "/" + dateString + ".dvi" }
<< QString{ workpath + "/" + dateString + ".log" }
<< QString{ workpath + "/" + dateString + ".tex" };
process = new QProcess{};
process->setProcessEnvironment( env );
process->setWorkingDirectory( workpath );
process->start( rmCmd, arguments);
if( !process->waitForFinished( processTimeOut ) ) {
emit ErrorOccurred(new QString("The cleanup of the temporary files for receipts creation timed out. Some spare files may be left in your zTree working directory."), new QString("Cleanup failed"));
}
delete process;
process = nullptr;
}
emit PrintingFinished();
} }
emit PrintingFinished();
}
public: public:
explicit ReceiptsPrinter( const QString &argDateString, explicit ReceiptsPrinter(const QString &argDateString,
const QString &argWorkpath, const QString &argWorkpath,
QObject *argParent = nullptr ); QObject *argParent = nullptr);
signals: signals:
void ErrorOccurred(QString *error_message, QString *heading); void ErrorOccurred(QString *error_message, QString *heading);
void PrintingFinished(); void PrintingFinished();
private: private:
const QString dateString; //! The date string contained in the file paths const QString dateString; //! The date string contained in the file paths
const QString dvipsCmd; const QString dvipsCmd;
const QString latexCmd; const QString latexCmd;
const QString lprCmd; const QString lprCmd;
const QString postscriptViewer; const QString postscriptViewer;
const int processTimeOut = 15000; //! The maximum time which will be granted to a started process const int processTimeOut =
const QString ps2pdfCmd; 15000; //! The maximum time which will be granted to a started process
const QString rmCmd; const QString ps2pdfCmd;
const QString vncViewer; const QString rmCmd;
const QString workpath; //!< The path were zTree was ordered to store all its data const QString vncViewer;
const QString
workpath; //!< The path were zTree was ordered to store all its data
}; };
} } // namespace lc
#endif // RECEIPTSPRINTER_H #endif // RECEIPTSPRINTER_H

@ -22,97 +22,106 @@
#include "session.h" #include "session.h"
#include "settings.h" #include "settings.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
lc::Session::Session( QVector< Client* > &&argAssocClients, lc::Session::Session(QVector<Client *> &&argAssocClients,
const QString &argZTreeDataTargetPath, const quint16 argZTreePort, const QString &argZTreeDataTargetPath,
const QString &argZTreeVersionPath, bool argPrintReceiptsForLocalClients, const quint16 argZTreePort,
const QString &argAnonymousReceiptsPlaceholder, const QString &argZTreeVersionPath,
const QString &argLatexHeaderName, QObject *argParent ): bool argPrintReceiptsForLocalClients,
QObject{ argParent }, const QString &argAnonymousReceiptsPlaceholder,
zTreePort{ argZTreePort }, const QString &argLatexHeaderName, QObject *argParent)
anonymousReceiptsPlaceholder{ argAnonymousReceiptsPlaceholder }, : QObject{argParent}, zTreePort{argZTreePort},
assocClients{ std::move( argAssocClients ) }, anonymousReceiptsPlaceholder{argAnonymousReceiptsPlaceholder},
latexHeaderName{ argLatexHeaderName }, assocClients{std::move(argAssocClients)},
printReceiptsForLocalClients{ argPrintReceiptsForLocalClients }, latexHeaderName{argLatexHeaderName},
zTreeDataTargetPath{ argZTreeDataTargetPath }, printReceiptsForLocalClients{argPrintReceiptsForLocalClients},
zTreeVersionPath{ argZTreeVersionPath } zTreeDataTargetPath{argZTreeDataTargetPath}, zTreeVersionPath{
{ argZTreeVersionPath} {
// This part ensures, that both class instances are created in the same minute, so that the payment file name can be guessed correctly // This part ensures, that both class instances are created in the same
QDateTime current_time; // minute, so that the payment file name can be guessed correctly
current_time = QDateTime::currentDateTime(); QDateTime current_time;
current_time = QDateTime::currentDateTime();
// If in the last three seconds of a minute, wait for the next one to start
if ( QTime::currentTime().second() > 56 ) { // If in the last three seconds of a minute, wait for the next one to start
QTimer::singleShot( 5000, this, SLOT( InitializeClasses() ) ); if (QTime::currentTime().second() > 56) {
} else { QTimer::singleShot(5000, this, SLOT(InitializeClasses()));
InitializeClasses(); } else {
} InitializeClasses();
}
if ( !settings->wmctrlCmd.isEmpty() ) {
QTimer::singleShot( 5000, this, SLOT( RenameWindow() ) ); if (!settings->wmctrlCmd.isEmpty()) {
} QTimer::singleShot(5000, this, SLOT(RenameWindow()));
}
} }
lc::Session::~Session() { lc::Session::~Session() {
for ( auto &client : assocClients ) { for (auto &client : assocClients) {
client->SetSessionPort( 0 ); client->SetSessionPort(0);
client->SetzLeafVersion( "" ); client->SetzLeafVersion("");
} }
} }
QVariant lc::Session::GetDataItem( int argIndex ) { QVariant lc::Session::GetDataItem(int argIndex) {
switch ( argIndex ) { switch (argIndex) {
case 0: case 0:
return QVariant{ zTreeVersionPath.split( '_', QString::KeepEmptyParts, Qt::CaseInsensitive )[ 1 ] }; return QVariant{zTreeVersionPath.split('_', QString::KeepEmptyParts,
case 1: Qt::CaseInsensitive)[1]};
return QVariant{ zTreePort }; case 1:
default: return QVariant{zTreePort};
return QVariant{}; default:
} return QVariant{};
}
} }
void lc::Session::InitializeClasses() { void lc::Session::InitializeClasses() {
// Create the new data directory // Create the new data directory
QDir dir{ zTreeDataTargetPath }; QDir dir{zTreeDataTargetPath};
QString date_string( QDateTime::currentDateTime().toString( "yyMMdd_hhmm" ) ); QString date_string(QDateTime::currentDateTime().toString("yyMMdd_hhmm"));
if ( !dir.mkdir( zTreeDataTargetPath + "/" + date_string + "-" + QString::number( zTreePort ) ) ) { if (!dir.mkdir(zTreeDataTargetPath + "/" + date_string + "-" +
throw lcDataTargetPathCreationFailed{}; QString::number(zTreePort))) {
} throw lcDataTargetPathCreationFailed{};
zTreeDataTargetPath.append( "/" + date_string + "-" + QString::number( zTreePort ) ); }
qDebug() << "New session's chosen_zTree_data_target_path:" << zTreeDataTargetPath; zTreeDataTargetPath.append("/" + date_string + "-" +
QString::number(zTreePort));
zTreeInstance = new ZTree{ zTreeDataTargetPath, zTreePort, zTreeVersionPath, this }; qDebug() << "New session's chosen_zTree_data_target_path:"
connect( zTreeInstance, &ZTree::ZTreeClosed, << zTreeDataTargetPath;
this, &Session::OnzTreeClosed );
// Only create a 'Receipts_Handler' instance, if all neccessary variables were set zTreeInstance =
if ( latexHeaderName != "None found" && !settings->dvipsCmd.isEmpty() new ZTree{zTreeDataTargetPath, zTreePort, zTreeVersionPath, this};
&& !settings->latexCmd.isEmpty() ) { connect(zTreeInstance, &ZTree::ZTreeClosed, this, &Session::OnzTreeClosed);
new ReceiptsHandler{ zTreeDataTargetPath, printReceiptsForLocalClients, // Only create a 'Receipts_Handler' instance, if all neccessary variables were
anonymousReceiptsPlaceholder, latexHeaderName, this }; // set
} else { if (latexHeaderName != "None found" && !settings->dvipsCmd.isEmpty() &&
qDebug() << "No 'ReceiptsHandler' instance was created."; !settings->latexCmd.isEmpty()) {
} new ReceiptsHandler{zTreeDataTargetPath, printReceiptsForLocalClients,
anonymousReceiptsPlaceholder, latexHeaderName, this};
} else {
qDebug() << "No 'ReceiptsHandler' instance was created.";
}
} }
void lc::Session::OnzTreeClosed( int argExitCode ) { void lc::Session::OnzTreeClosed(int argExitCode) {
qDebug() << "z-Tree running on port" << zTreePort << "closed with exit code" << argExitCode; qDebug() << "z-Tree running on port" << zTreePort << "closed with exit code"
emit SessionFinished( this ); << argExitCode;
emit SessionFinished(this);
} }
void lc::Session::RenameWindow() { void lc::Session::RenameWindow() {
// Example: wmctrl -r <window name> -T <new name> // Example: wmctrl -r <window name> -T <new name>
QStringList arguments; QStringList arguments;
arguments << "-r" << "zTree - Untitled Treatment 1" << "-T" << QString{ "zTree on port " + QString::number( zTreePort ) }; arguments << "-r"
<< "zTree - Untitled Treatment 1"
<< "-T" << QString{"zTree on port " + QString::number(zTreePort)};
// Start the process // Start the process
QProcess renameZTreeWindowProcess; QProcess renameZTreeWindowProcess;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
renameZTreeWindowProcess.setProcessEnvironment( env ); renameZTreeWindowProcess.setProcessEnvironment(env);
renameZTreeWindowProcess.startDetached( settings->wmctrlCmd, arguments ); renameZTreeWindowProcess.startDetached(settings->wmctrlCmd, arguments);
qDebug() << "Renamed window"; qDebug() << "Renamed window";
// emit session_started(); // emit session_started();
} }

@ -32,52 +32,63 @@ class Client;
//! A class containing an entire session. //! A class containing an entire session.
/*! /*!
This class represents an entire session with its zTree instance and the corresponding lcReceiptsHandler instance. This class represents an entire session with its zTree instance and the
corresponding lcReceiptsHandler instance.
*/ */
class Session : public QObject { class Session : public QObject {
Q_OBJECT Q_OBJECT
public: public:
const int zTreePort = 7000; //! The port this session's zTree instance is running on const int zTreePort =
7000; //! The port this session's zTree instance is running on
Session( QVector< Client* > &&argAssocClients, const QString &argZTreeDataTargetPath, Session(QVector<Client *> &&argAssocClients,
const quint16 argZTreePort, const QString &argZTreeVersionPath, const QString &argZTreeDataTargetPath, const quint16 argZTreePort,
bool argPrintReceiptsForLocalClients, const QString &argZTreeVersionPath,
const QString &argAnonymousReceiptsPlaceholder, bool argPrintReceiptsForLocalClients,
const QString &argLatexHeaderName, QObject *argParent = nullptr ); const QString &argAnonymousReceiptsPlaceholder,
~Session(); const QString &argLatexHeaderName, QObject *argParent = nullptr);
~Session();
/*! Returns the data item with the given index /*! Returns the data item with the given index
* *
* @param argIndex The index of the desired item * @param argIndex The index of the desired item
*/ */
QVariant GetDataItem( int argIndex ); QVariant GetDataItem(int argIndex);
//! This gets thrown as an exception if the chosen data target path could not be created. //! This gets thrown as an exception if the chosen data target path could not
class lcDataTargetPathCreationFailed {}; //! be created.
class lcDataTargetPathCreationFailed {};
signals: signals:
void SessionFinished( Session *argSession ); void SessionFinished(Session *argSession);
private slots: private slots:
/*! Starts the session by creating instances of the relevant classes /*! Starts the session by creating instances of the relevant classes
*/ */
void InitializeClasses(); void InitializeClasses();
void OnzTreeClosed( int argExitCode ); void OnzTreeClosed(int argExitCode);
/*! Changes zTree's window title to contain its port number to make zTree windows distinguishable /*! Changes zTree's window title to contain its port number to make zTree
*/ * windows distinguishable
void RenameWindow(); */
void RenameWindow();
private: private:
const QString anonymousReceiptsPlaceholder; //! Placeholder which shall be inserted for participant names if anonymous printing is desired (QString != "") const QString
const QVector< Client* > assocClients; anonymousReceiptsPlaceholder; //! Placeholder which shall be inserted for
const QString latexHeaderName; //! The name of the chosen LaTeX header //! participant names if anonymous printing
const bool printReceiptsForLocalClients = true; //! True if receipts shall be printed for local clients //! is desired (QString != "")
QString zTreeDataTargetPath; //! The path were the data of this zTree instance's session will be saved const QVector<Client *> assocClients;
ZTree *zTreeInstance= nullptr; //! The session's zTree instance const QString latexHeaderName; //! The name of the chosen LaTeX header
const QString zTreeVersionPath; //! The path to the version of zTree used by this session's instance const bool printReceiptsForLocalClients =
true; //! True if receipts shall be printed for local clients
QString zTreeDataTargetPath; //! The path were the data of this zTree
//! instance's session will be saved
ZTree *zTreeInstance = nullptr; //! The session's zTree instance
const QString zTreeVersionPath; //! The path to the version of zTree used by
//! this session's instance
}; };
} } // namespace lc
#endif // SESSION_H #endif // SESSION_H

@ -21,66 +21,64 @@
#include "sessionsmodel.h" #include "sessionsmodel.h"
lc::SessionsModel::SessionsModel( QObject *argParent ) : lc::SessionsModel::SessionsModel(QObject *argParent)
QAbstractTableModel{ argParent } : QAbstractTableModel{argParent} {}
{
}
lc::Session *lc::SessionsModel::back() const { lc::Session *lc::SessionsModel::back() const { return sessionsList.back(); }
return sessionsList.back();
}
int lc::SessionsModel::columnCount(const QModelIndex &parent) const { int lc::SessionsModel::columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent); Q_UNUSED(parent);
return 2; return 2;
} }
QVariant lc::SessionsModel::data(const QModelIndex &index, int role) const { QVariant lc::SessionsModel::data(const QModelIndex &index, int role) const {
if (!index.isValid()) if (!index.isValid())
return QVariant{}; return QVariant{};
if (index.row() >= sessionsList.size() || index.row() < 0) if (index.row() >= sessionsList.size() || index.row() < 0)
return QVariant{}; return QVariant{};
if (role == Qt::DisplayRole) if (role == Qt::DisplayRole)
return sessionsList.at( index.row() )->GetDataItem( index.column() ); return sessionsList.at(index.row())->GetDataItem(index.column());
return QVariant{}; return QVariant{};
} }
QVariant lc::SessionsModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant lc::SessionsModel::headerData(int section, Qt::Orientation orientation,
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { int role) const {
switch(section) { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
case 0: switch (section) {
return tr("zTree Version"); case 0:
case 1: return tr("zTree Version");
return tr("Port"); case 1:
case 2: return tr("Port");
return tr("LaTeX Header"); case 2:
case 3: return tr("LaTeX Header");
return tr("Anonymous Receipts Placeholder"); case 3:
default: return tr("Anonymous Receipts Placeholder");
return QVariant{}; default:
} return QVariant{};
} }
return QVariant{}; }
return QVariant{};
} }
void lc::SessionsModel::push_back( Session *argSession ) { void lc::SessionsModel::push_back(Session *argSession) {
connect( argSession, &Session::SessionFinished, connect(argSession, &Session::SessionFinished, this,
this, &SessionsModel::RemoveSession ); &SessionsModel::RemoveSession);
argSession->setParent( this ); argSession->setParent(this);
sessionsList.push_back( argSession ); sessionsList.push_back(argSession);
} }
void lc::SessionsModel::RemoveSession( Session *argSession ) { void lc::SessionsModel::RemoveSession(Session *argSession) {
if ( sessionsList.removeAll( argSession ) ) { if (sessionsList.removeAll(argSession)) {
qDebug() << "Successfully removed" << argSession << "from lc::SessionsModel"; qDebug() << "Successfully removed" << argSession
argSession->deleteLater(); << "from lc::SessionsModel";
} argSession->deleteLater();
}
} }
int lc::SessionsModel::rowCount(const QModelIndex &parent) const { int lc::SessionsModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent); Q_UNUSED(parent);
return sessionsList.length(); return sessionsList.length();
} }

@ -27,28 +27,28 @@
namespace lc { namespace lc {
class SessionsModel : public QAbstractTableModel { class SessionsModel : public QAbstractTableModel {
Q_OBJECT Q_OBJECT
public: public:
explicit SessionsModel(QObject *parent = 0); explicit SessionsModel(QObject *parent = 0);
SessionsModel(const SessionsModel&) = delete; SessionsModel(const SessionsModel &) = delete;
Session *back() const; Session *back() const;
int columnCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const; QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const;
void push_back( Session *argSession ); void push_back(Session *argSession);
int rowCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent) const;
signals: signals:
public slots: public slots:
private: private:
QList< Session* > sessionsList; QList<Session *> sessionsList;
private slots: private slots:
void RemoveSession( Session *argSession ); void RemoveSession(Session *argSession);
}; };
} } // namespace lc
#endif // SESSIONSMODEL_H #endif // SESSIONSMODEL_H

@ -25,370 +25,423 @@
#include "client.h" #include "client.h"
#include "settings.h" #include "settings.h"
lc::Settings::Settings( const QSettings &argSettings, QObject *argParent ) : lc::Settings::Settings(const QSettings &argSettings, QObject *argParent)
QObject{ argParent }, : QObject{argParent}, defaultReceiptIndex{GetDefaultReceiptIndex(
defaultReceiptIndex{ GetDefaultReceiptIndex( argSettings ) }, argSettings)},
browserCmd{ ReadSettingsItem( "browser_command", browserCmd{ReadSettingsItem("browser_command",
"Opening ORSEE in a browser will not work.", "Opening ORSEE in a browser will not work.",
argSettings, true ) }, argSettings, true)},
clientBrowserCmd{ ReadSettingsItem( "client_browser_command", clientBrowserCmd{
"Opening a browser window on clients will not work.", ReadSettingsItem("client_browser_command",
argSettings, false ) }, "Opening a browser window on clients will not work.",
clientChromiumCmd{ ReadSettingsItem( "client_chromium_command", argSettings, false)},
"Opening a chromium window on clients will not work.", clientChromiumCmd{ReadSettingsItem(
argSettings, false ) }, "client_chromium_command",
dvipsCmd{ ReadSettingsItem( "dvips_command", "Opening a chromium window on clients will not work.", argSettings,
"Receipts creation will not work.", false)},
argSettings, true ) }, dvipsCmd{ReadSettingsItem("dvips_command",
fileMngr{ ReadSettingsItem( "file_manager", "Receipts creation will not work.", argSettings,
true)},
fileMngr{ReadSettingsItem("file_manager",
"The display of preprints will not work.", "The display of preprints will not work.",
argSettings, true ) }, argSettings, true)},
killallCmd{ ReadSettingsItem( "killall_command", killallCmd{ReadSettingsItem(
"Killing 'zleaf.exe' instances will not work.", "killall_command", "Killing 'zleaf.exe' instances will not work.",
argSettings, true ) }, argSettings, true)},
latexCmd{ ReadSettingsItem( "latex_command", latexCmd{ReadSettingsItem("latex_command",
"Receipts creation will not work.", "Receipts creation will not work.", argSettings,
argSettings, true ) }, true)},
lcDataDir{ ReadSettingsItem( "labcontrol_data_directory", lcDataDir{ReadSettingsItem(
"Datapath not set. Labcontrol will missbehave with high propability.", "labcontrol_data_directory",
argSettings, true ) }, "Datapath not set. Labcontrol will missbehave with high propability.",
localUserName{ GetLocalUserName() }, argSettings, true)},
localzLeafSize{ ReadSettingsItem( "local_zLeaf_size", localUserName{GetLocalUserName()}, localzLeafSize{ReadSettingsItem(
"Resolution of local zLeaf window", "local_zLeaf_size",
argSettings, false ) }, "Resolution of local zLeaf window",
lprCmd{ ReadSettingsItem( "lpr_command", argSettings, false)},
"Receipts printing will not work.", lprCmd{ReadSettingsItem("lpr_command", "Receipts printing will not work.",
argSettings, true ) }, argSettings, true)},
netstatCmd{ ReadSettingsItem( "netstat_command", netstatCmd{ReadSettingsItem(
"Detection of active zLeaf connections will not work.", "netstat_command",
argSettings, true ) }, "Detection of active zLeaf connections will not work.", argSettings,
netwBrdAddr{ ReadSettingsItem( "network_broadcast_address", true)},
netwBrdAddr{ReadSettingsItem("network_broadcast_address",
"Booting the clients will not work.", "Booting the clients will not work.",
argSettings, false ) }, argSettings, false)},
orseeUrl{ ReadSettingsItem( "orsee_url", orseeUrl{ReadSettingsItem("orsee_url",
"Opening ORSEE in a browser will not work.", "Opening ORSEE in a browser will not work.",
argSettings, false ) }, argSettings, false)},
pingCmd{ ReadSettingsItem( "ping_command", pingCmd{ReadSettingsItem("ping_command",
"Status updates for the clients will not work.", "Status updates for the clients will not work.",
argSettings, true ) }, argSettings, true)},
postscriptViewer{ ReadSettingsItem( "postscript_viewer", postscriptViewer{ReadSettingsItem(
"Viewing the generated receipts postscript file will not work.", "postscript_viewer",
argSettings, true ) }, "Viewing the generated receipts postscript file will not work.",
ps2pdfCmd{ ReadSettingsItem( "ps2pdf_command", argSettings, true)},
"Converting and viewing the generated receipts file will not work.", ps2pdfCmd{ReadSettingsItem(
argSettings, true ) }, "ps2pdf_command",
pkeyPathRoot{ ReadSettingsItem( "pkey_path_root", "Converting and viewing the generated receipts file will not work.",
"Administration actions concerning the clients will not be available.", argSettings, true)},
argSettings, true ) }, pkeyPathRoot{ReadSettingsItem("pkey_path_root",
pkeyPathUser{ ReadSettingsItem( "pkey_path_user", "Administration actions concerning the "
"Many actions concerning the clients will not be available.", "clients will not be available.",
argSettings, true ) }, argSettings, true)},
rmCmd{ ReadSettingsItem( "rm_command", pkeyPathUser{ReadSettingsItem(
"Cleanup of the zTree data target path will not work.", "pkey_path_user",
argSettings, true ) }, "Many actions concerning the clients will not be available.",
scpCmd{ ReadSettingsItem( "scp_command", argSettings, true)},
"Beaming files to the clients will not be possible.", rmCmd{ReadSettingsItem(
argSettings, true ) }, "rm_command", "Cleanup of the zTree data target path will not work.",
serverIP{ ReadSettingsItem( "server_ip", argSettings, true)},
"Starting zLeaves and retrieving client help messages will not work.", scpCmd{ReadSettingsItem(
argSettings, false ) }, "scp_command", "Beaming files to the clients will not be possible.",
sshCmd{ ReadSettingsItem( "ssh_command", argSettings, true)},
"All actions concerning the clients will not be possible.", serverIP{ReadSettingsItem(
argSettings, true ) }, "server_ip",
tasksetCmd{ ReadSettingsItem( "taskset_command", "Starting zLeaves and retrieving client help messages will not work.",
"Running z-Leaves or z-Tree will be possible.", argSettings, false)},
argSettings, true ) }, sshCmd{ReadSettingsItem(
termEmulCmd{ ReadSettingsItem( "terminal_emulator_command", "ssh_command",
"Conducting administrative tasks will not be possible.", "All actions concerning the clients will not be possible.",
argSettings, true ) }, argSettings, true)},
userNameOnClients{ ReadSettingsItem( "user_name_on_clients", tasksetCmd{ReadSettingsItem(
"All actions concerning the clients performed by the experiment user will not work.", "taskset_command", "Running z-Leaves or z-Tree will be possible.",
argSettings, false ) }, argSettings, true)},
vncViewer{ ReadSettingsItem( "vnc_viewer", termEmulCmd{ReadSettingsItem(
"terminal_emulator_command",
"Conducting administrative tasks will not be possible.", argSettings,
true)},
userNameOnClients{
ReadSettingsItem("user_name_on_clients",
"All actions concerning the clients performed by "
"the experiment user will not work.",
argSettings, false)},
vncViewer{ReadSettingsItem("vnc_viewer",
"Viewing the clients' screens will not work.", "Viewing the clients' screens will not work.",
argSettings, true ) }, argSettings, true)},
wakeonlanCmd{ ReadSettingsItem( "wakeonlan_command", wakeonlanCmd{ReadSettingsItem("wakeonlan_command",
"Booting the clients will not work.", "Booting the clients will not work.",
argSettings, true ) }, argSettings, true)},
webcamDisplayCmd{ ReadSettingsItem( "webcam_command", webcamDisplayCmd{
"Displaying the laboratory's webcams will not work.", ReadSettingsItem("webcam_command",
argSettings, true ) }, "Displaying the laboratory's webcams will not work.",
webcams{ argSettings.value( "webcams", "" ).toString().split( '|', QString::SkipEmptyParts, argSettings, true)},
Qt::CaseInsensitive ) }, webcams{argSettings.value("webcams", "")
webcams_names{ argSettings.value( "webcams_names", "" ).toString().split( '|', QString::SkipEmptyParts, .toString()
Qt::CaseInsensitive ) }, .split('|', QString::SkipEmptyParts, Qt::CaseInsensitive)},
wineCmd{ ReadSettingsItem( "wine_command", webcams_names{
argSettings.value("webcams_names", "")
.toString()
.split('|', QString::SkipEmptyParts, Qt::CaseInsensitive)},
wineCmd{ReadSettingsItem("wine_command",
"Running z-Leaves or z-Tree will be possible.", "Running z-Leaves or z-Tree will be possible.",
argSettings, true ) }, argSettings, true)},
wmctrlCmd{ ReadSettingsItem( "wmctrl_command", wmctrlCmd{ReadSettingsItem(
"Setting zTree's window title to its port number will not work.", "wmctrl_command",
argSettings, true ) }, "Setting zTree's window title to its port number will not work.",
xsetCmd{ ReadSettingsItem( "xset_command", argSettings, true)},
"Deactivating the screen saver on the clients will not be possible.", xsetCmd{ReadSettingsItem(
argSettings, true ) }, "xset_command",
zTreeInstDir{ ReadSettingsItem( "ztree_installation_directory", "Deactivating the screen saver on the clients will not be possible.",
"zTree will not be available.", argSettings, true)},
argSettings, true ) }, zTreeInstDir{ReadSettingsItem("ztree_installation_directory",
restartCrashedSessionScript{ ReadSettingsItem( "restart_crashed_session_script", "zTree will not be available.", argSettings,
"Script to be called after session crash", true)},
argSettings, false ) }, restartCrashedSessionScript{ReadSettingsItem(
adminUsers{ GetAdminUsers( argSettings ) }, "restart_crashed_session_script",
installedLaTeXHeaders{ DetectInstalledLaTeXHeaders() }, "Script to be called after session crash", argSettings, false)},
installedZTreeVersions{ DetectInstalledzTreeVersions() }, adminUsers{GetAdminUsers(argSettings)},
clientHelpNotificationServerPort{ GetClientHelpNotificationServerPort( argSettings ) }, installedLaTeXHeaders{DetectInstalledLaTeXHeaders()},
chosenzTreePort{ GetInitialPort( argSettings ) }, installedZTreeVersions{DetectInstalledzTreeVersions()},
clients{ CreateClients( argSettings, pingCmd ) }, clientHelpNotificationServerPort{
localzLeafName{ ReadSettingsItem( "local_zLeaf_name", GetClientHelpNotificationServerPort(argSettings)},
"The local zLeaf default name will default to 'local'.", chosenzTreePort{GetInitialPort(argSettings)}, clients{CreateClients(
argSettings, false ) }, argSettings, pingCmd)},
clIPsToClMap{ CreateClIPsToClMap( clients ) } localzLeafName{ReadSettingsItem(
{ "local_zLeaf_name",
// Let the local zLeaf name default to 'local' if none was given in the settings "The local zLeaf default name will default to 'local'.", argSettings,
if ( localzLeafName.isEmpty() ) { false)},
qDebug() << "'local_zLeaf_name' was not set, defaulting to 'local'"; clIPsToClMap{CreateClIPsToClMap(clients)} {
localzLeafName = "local"; // Let the local zLeaf name default to 'local' if none was given in the
} // settings
if ( webcams.isEmpty() ) { if (localzLeafName.isEmpty()) {
qDebug() << "'webcams' was not properly set. No stationary webcams will be available."; qDebug() << "'local_zLeaf_name' was not set, defaulting to 'local'";
} else { localzLeafName = "local";
qDebug() << "The following webcams where loaded:" << webcams; }
} if (webcams.isEmpty()) {
qDebug() << "Detected z-Tree versions" << installedZTreeVersions; qDebug() << "'webcams' was not properly set. No stationary webcams will be "
"available.";
} else {
qDebug() << "The following webcams where loaded:" << webcams;
}
qDebug() << "Detected z-Tree versions" << installedZTreeVersions;
} }
lc::Settings::~Settings() { lc::Settings::~Settings() {
for ( QVector< Client* >::iterator it = clients.begin(); it != clients.end(); ++it ) { for (QVector<Client *>::iterator it = clients.begin(); it != clients.end();
delete *it; ++it) {
} delete *it;
}
} }
bool lc::Settings::CheckPathAndComplain( const QString &argPath, const QString &argVariableName, bool lc::Settings::CheckPathAndComplain(const QString &argPath,
const QString &argMessage ) { const QString &argVariableName,
if ( !QFile::exists( argPath ) ) { const QString &argMessage) {
qDebug() << "The path" << argPath << "specified by" << argVariableName if (!QFile::exists(argPath)) {
<< "does not exist:" << argMessage; qDebug() << "The path" << argPath << "specified by" << argVariableName
return false; << "does not exist:" << argMessage;
} return false;
qDebug() << argVariableName << ":" << argPath; }
return true; qDebug() << argVariableName << ":" << argPath;
return true;
} }
QVector< lc::Client* > lc::Settings::CreateClients( const QSettings &argSettings, QVector<lc::Client *> lc::Settings::CreateClients(const QSettings &argSettings,
const QString &argPingCmd ) { const QString &argPingCmd) {
QVector< Client* > tempClientVec; QVector<Client *> tempClientVec;
// Get the client quantity to check the value lists for clients creation for correct length // Get the client quantity to check the value lists for clients creation for
int clientQuantity = 0; // correct length
if ( !argSettings.contains("client_quantity" ) ) { int clientQuantity = 0;
qWarning() << "'client_quantity' was not set. The client quantity will be guessed" if (!argSettings.contains("client_quantity")) {
" by the amount of client IPs set in 'client_ips'."; qWarning()
clientQuantity = argSettings.value( "client_ips", "" ).toString() << "'client_quantity' was not set. The client quantity will be guessed"
.split( '/', QString::SkipEmptyParts, Qt::CaseSensitive ).length(); " by the amount of client IPs set in 'client_ips'.";
qDebug() << "'clientQuantity':" << clientQuantity; clientQuantity = argSettings.value("client_ips", "")
} else { .toString()
bool ok = true; .split('/', QString::SkipEmptyParts, Qt::CaseSensitive)
clientQuantity = argSettings.value( "client_quantity" ).toInt( &ok ); .length();
if ( !ok ) { qDebug() << "'clientQuantity':" << clientQuantity;
qWarning() << "The variable 'client_quantity' was not convertible to int"; } else {
} bool ok = true;
qDebug() << "'clientQuantity':" << clientQuantity; clientQuantity = argSettings.value("client_quantity").toInt(&ok);
if (!ok) {
qWarning() << "The variable 'client_quantity' was not convertible to int";
} }
qDebug() << "'clientQuantity':" << clientQuantity;
}
// Create all the clients in the lab // Create all the clients in the lab
QStringList clientIPs = argSettings.value( "client_ips" ).toString() QStringList clientIPs =
.split( '|', QString::SkipEmptyParts, Qt::CaseSensitive ); argSettings.value("client_ips")
if ( clientIPs.length() != clientQuantity ) { .toString()
qWarning() << "The quantity of client ips does not match the client quantity. Client" .split('|', QString::SkipEmptyParts, Qt::CaseSensitive);
" creation will fail. No clients will be available for interaction."; if (clientIPs.length() != clientQuantity) {
return tempClientVec; qWarning()
} << "The quantity of client ips does not match the client quantity. "
qDebug() << "Client IPs:" << clientIPs.join( " / " ); "Client"
" creation will fail. No clients will be available for interaction.";
return tempClientVec;
}
qDebug() << "Client IPs:" << clientIPs.join(" / ");
QStringList clientMACs = argSettings.value( "client_macs" ).toString() QStringList clientMACs =
.split( '|', QString::SkipEmptyParts, Qt::CaseSensitive ); argSettings.value("client_macs")
if ( clientMACs.length() != clientQuantity ) { .toString()
qWarning() << "The quantity of client macs does not match the client quantity. Client" .split('|', QString::SkipEmptyParts, Qt::CaseSensitive);
" creation will fail. No clients will be available for interaction."; if (clientMACs.length() != clientQuantity) {
return tempClientVec; qWarning()
} << "The quantity of client macs does not match the client quantity. "
qDebug() << "Client MACs:" << clientMACs.join( " / " ); "Client"
" creation will fail. No clients will be available for interaction.";
return tempClientVec;
}
qDebug() << "Client MACs:" << clientMACs.join(" / ");
QStringList clientNames = argSettings.value( "client_names" ).toString() QStringList clientNames =
.split( '|', QString::SkipEmptyParts, Qt::CaseSensitive ); argSettings.value("client_names")
if ( clientNames.length() != clientQuantity ) { .toString()
qWarning() << "The quantity of client names does not match the client quantity. Client" .split('|', QString::SkipEmptyParts, Qt::CaseSensitive);
" creation will fail. No clients will be available for interaction."; if (clientNames.length() != clientQuantity) {
return tempClientVec; qWarning()
} << "The quantity of client names does not match the client quantity. "
qDebug() << "Client names:" << clientNames.join( " / " ); "Client"
" creation will fail. No clients will be available for interaction.";
return tempClientVec;
}
qDebug() << "Client names:" << clientNames.join(" / ");
QStringList clientXPositions = argSettings.value( "client_xpos" ).toString() QStringList clientXPositions =
.split( '|', QString::SkipEmptyParts, Qt::CaseSensitive ); argSettings.value("client_xpos")
if ( clientXPositions.length() != clientQuantity ) { .toString()
qWarning() << "The quantity of client x positions does not match the client quantity." .split('|', QString::SkipEmptyParts, Qt::CaseSensitive);
" Client creation will fail. No clients will be available for interaction."; if (clientXPositions.length() != clientQuantity) {
return tempClientVec; qWarning() << "The quantity of client x positions does not match the "
} "client quantity."
qDebug() << "clientXPositions:" << clientXPositions.join( " / " ); " Client creation will fail. No clients will be available "
"for interaction.";
return tempClientVec;
}
qDebug() << "clientXPositions:" << clientXPositions.join(" / ");
QStringList clientYPositions = argSettings.value( "client_ypos" ).toString() QStringList clientYPositions =
.split( '|', QString::SkipEmptyParts, Qt::CaseSensitive ); argSettings.value("client_ypos")
if ( clientYPositions.length() != clientQuantity ) { .toString()
qWarning() << "The quantity of client y positions does not match the client quantity." .split('|', QString::SkipEmptyParts, Qt::CaseSensitive);
" Client creation will fail. No clients will be available for interaction."; if (clientYPositions.length() != clientQuantity) {
return tempClientVec; qWarning() << "The quantity of client y positions does not match the "
} "client quantity."
qDebug() << "clientYPositions:" << clientYPositions.join( " / " ); " Client creation will fail. No clients will be available "
"for interaction.";
return tempClientVec;
}
qDebug() << "clientYPositions:" << clientYPositions.join(" / ");
for ( int i = 0; i < clientQuantity; i++ ) { for (int i = 0; i < clientQuantity; i++) {
tempClientVec.append( new Client{ clientIPs[ i ], clientMACs[ i ], clientNames[ i ], tempClientVec.append(new Client{clientIPs[i], clientMACs[i], clientNames[i],
clientXPositions[ i ].toUShort(), clientXPositions[i].toUShort(),
clientYPositions[ i ].toUShort(), argPingCmd } ); clientYPositions[i].toUShort(),
} argPingCmd});
}
return tempClientVec; return tempClientVec;
} }
QMap< QString, lc::Client* > lc::Settings::CreateClIPsToClMap( const QVector< Client* > &argClients ) { QMap<QString, lc::Client *>
QMap< QString, Client* > tempMap; lc::Settings::CreateClIPsToClMap(const QVector<Client *> &argClients) {
for ( const auto &s : argClients ) { QMap<QString, Client *> tempMap;
tempMap.insert( s->ip, s ); for (const auto &s : argClients) {
tempMap.insert(s->ip, s);
// Get the address of the Client instance in RAM for display // Get the address of the Client instance in RAM for display
const void *clientPtrAddr = static_cast< const void* >( tempMap[ s->ip ] ); const void *clientPtrAddr = static_cast<const void *>(tempMap[s->ip]);
qDebug() << "Added" << s->name qDebug() << "Added" << s->name
<< "to 'clientIPsToClientsMap':" << clientPtrAddr; << "to 'clientIPsToClientsMap':" << clientPtrAddr;
} }
return tempMap; return tempMap;
} }
QStringList lc::Settings::DetectInstalledLaTeXHeaders() const { QStringList lc::Settings::DetectInstalledLaTeXHeaders() const {
QStringList tempLaTeXHeaders{ "None found" }; QStringList tempLaTeXHeaders{"None found"};
// Detect the installed LaTeX headers // Detect the installed LaTeX headers
if ( !lcDataDir.isEmpty() ) { if (!lcDataDir.isEmpty()) {
QDir laTeXDirectory{ lcDataDir, "*_header.tex", QDir::Name, QDir laTeXDirectory{lcDataDir, "*_header.tex", QDir::Name,
QDir::CaseSensitive | QDir::Files | QDir::Readable }; QDir::CaseSensitive | QDir::Files | QDir::Readable};
if ( !laTeXDirectory.exists() || laTeXDirectory.entryList().isEmpty() ) { if (!laTeXDirectory.exists() || laTeXDirectory.entryList().isEmpty()) {
qDebug() << "Receipts printing will not work. No LaTeX headers could be found in" qDebug() << "Receipts printing will not work. No LaTeX headers could be "
<< lcDataDir; "found in"
} else { << lcDataDir;
tempLaTeXHeaders = laTeXDirectory.entryList(); } else {
tempLaTeXHeaders.replaceInStrings( "_header.tex", "" ); tempLaTeXHeaders = laTeXDirectory.entryList();
qDebug() << "LaTeX headers:" << tempLaTeXHeaders.join( " / " ); tempLaTeXHeaders.replaceInStrings("_header.tex", "");
} qDebug() << "LaTeX headers:" << tempLaTeXHeaders.join(" / ");
} }
return tempLaTeXHeaders; }
return tempLaTeXHeaders;
} }
QStringList lc::Settings::DetectInstalledzTreeVersions() const { QStringList lc::Settings::DetectInstalledzTreeVersions() const {
QStringList tempInstzTreeVersions; QStringList tempInstzTreeVersions;
if ( !zTreeInstDir.isEmpty() ) { if (!zTreeInstDir.isEmpty()) {
QDir zTreeDirectory{ zTreeInstDir, "zTree_*", QDir::Name, QDir zTreeDirectory{zTreeInstDir, "zTree_*", QDir::Name,
QDir::NoDotAndDotDot | QDir::Dirs QDir::NoDotAndDotDot | QDir::Dirs | QDir::Readable |
| QDir::Readable | QDir::CaseSensitive }; QDir::CaseSensitive};
if ( zTreeDirectory.entryList().isEmpty() ) { if (zTreeDirectory.entryList().isEmpty()) {
qWarning() << "No zTree versions could be found in" << zTreeInstDir; qWarning() << "No zTree versions could be found in" << zTreeInstDir;
} else { } else {
tempInstzTreeVersions = zTreeDirectory.entryList(); tempInstzTreeVersions = zTreeDirectory.entryList();
tempInstzTreeVersions.replaceInStrings( "zTree_", "" ); tempInstzTreeVersions.replaceInStrings("zTree_", "");
}
} }
return tempInstzTreeVersions; }
return tempInstzTreeVersions;
} }
QStringList lc::Settings::GetAdminUsers( const QSettings &argSettings ) { QStringList lc::Settings::GetAdminUsers(const QSettings &argSettings) {
// Read the list of users with administrative rights // Read the list of users with administrative rights
if ( !argSettings.contains( "admin_users" ) ) { if (!argSettings.contains("admin_users")) {
qDebug() << "The 'admin_users' variable was not set." qDebug() << "The 'admin_users' variable was not set."
" No users will be able to conduct administrative tasks."; " No users will be able to conduct administrative tasks.";
return QStringList{};
} else {
QStringList adminUsers{ argSettings.value( "admin_users", "" ).toString()
.split( '|', QString::SkipEmptyParts, Qt::CaseInsensitive ) };
qDebug() << "'adminUsers':" << adminUsers.join( " / " );
return adminUsers;
}
return QStringList{}; return QStringList{};
} else {
QStringList adminUsers{
argSettings.value("admin_users", "")
.toString()
.split('|', QString::SkipEmptyParts, Qt::CaseInsensitive)};
qDebug() << "'adminUsers':" << adminUsers.join(" / ");
return adminUsers;
}
return QStringList{};
} }
quint16 lc::Settings::GetClientHelpNotificationServerPort( const QSettings &argSettings ) { quint16 lc::Settings::GetClientHelpNotificationServerPort(
// Read the port the ClientHelpNotificationServer shall listen on const QSettings &argSettings) {
quint16 clientHelpNotificationServerPort = argSettings.value( "client_help_server_port", // Read the port the ClientHelpNotificationServer shall listen on
0 ).toUInt(); quint16 clientHelpNotificationServerPort =
if ( !clientHelpNotificationServerPort ) { argSettings.value("client_help_server_port", 0).toUInt();
qDebug() << "The 'client_help_server_port' variable was not set or set to zero." if (!clientHelpNotificationServerPort) {
" The ClientHelpNotificationServer will be deactivated therefore." qDebug()
" Clients' help requests will be ignored by the server."; << "The 'client_help_server_port' variable was not set or set to zero."
return 0; " The ClientHelpNotificationServer will be deactivated therefore."
} else { " Clients' help requests will be ignored by the server.";
qDebug() << "'clientHelpNotificationServerPort':" << clientHelpNotificationServerPort;
return clientHelpNotificationServerPort;
}
return 0; return 0;
} else {
qDebug() << "'clientHelpNotificationServerPort':"
<< clientHelpNotificationServerPort;
return clientHelpNotificationServerPort;
}
return 0;
} }
int lc::Settings::GetDefaultReceiptIndex( const QSettings &argSettings ) { int lc::Settings::GetDefaultReceiptIndex(const QSettings &argSettings) {
// Read the default receipt index for the 'CBReceipts' combobox // Read the default receipt index for the 'CBReceipts' combobox
if ( !argSettings.contains( "default_receipt_index" ) ) { if (!argSettings.contains("default_receipt_index")) {
qDebug() << "'default_receipt_index' was not set. It will default to '0'."; qDebug() << "'default_receipt_index' was not set. It will default to '0'.";
return 0; return 0;
} }
int tempIndex = argSettings.value( "default_receipt_index", 0 ).toInt(); int tempIndex = argSettings.value("default_receipt_index", 0).toInt();
qDebug() << "'defaultReceiptIndex':" << tempIndex; qDebug() << "'defaultReceiptIndex':" << tempIndex;
return tempIndex; return tempIndex;
} }
int lc::Settings::GetInitialPort( const QSettings &argSettings ) { int lc::Settings::GetInitialPort(const QSettings &argSettings) {
// Read the initial port number // Read the initial port number
if ( !argSettings.contains( "initial_port" ) ) { if (!argSettings.contains("initial_port")) {
qDebug() << "The 'initial_port' variable was not set." qDebug()
" Labcontrol will default to port 7000 for new zTree instances."; << "The 'initial_port' variable was not set."
} " Labcontrol will default to port 7000 for new zTree instances.";
int initialPort = argSettings.value( "initial_port", 7000 ).toInt(); }
qDebug() << "'initial_port':" << initialPort; int initialPort = argSettings.value("initial_port", 7000).toInt();
return initialPort; qDebug() << "'initial_port':" << initialPort;
return initialPort;
} }
QString lc::Settings::GetLocalUserName() { QString lc::Settings::GetLocalUserName() {
const QProcessEnvironment env{ QProcessEnvironment::systemEnvironment() }; const QProcessEnvironment env{QProcessEnvironment::systemEnvironment()};
QString userName; QString userName;
// For Linux // For Linux
if ( env.contains( "USER" ) ) { if (env.contains("USER")) {
userName = env.value( "USER", "" ); userName = env.value("USER", "");
qDebug() << "The local user name is" << userName; qDebug() << "The local user name is" << userName;
} else if ( env.contains( "USERNAME" ) ) { // For Windows } else if (env.contains("USERNAME")) { // For Windows
userName = env.value( "USERNAME", "" ); userName = env.value("USERNAME", "");
qDebug() << "The local user name is" << userName; qDebug() << "The local user name is" << userName;
} else { } else {
qWarning() << "The local user name could not be queried"; qWarning() << "The local user name could not be queried";
} }
return userName; return userName;
} }
QString lc::Settings::ReadSettingsItem( const QString &argVariableName, QString lc::Settings::ReadSettingsItem(const QString &argVariableName,
const QString &argMessage, const QString &argMessage,
const QSettings &argSettings, const QSettings &argSettings,
bool argItemIsFile) { bool argItemIsFile) {
if ( !argSettings.contains( argVariableName ) ) { if (!argSettings.contains(argVariableName)) {
qDebug() << argVariableName << "was not set." << argMessage; qDebug() << argVariableName << "was not set." << argMessage;
return QString{};
} else {
QString tempString{ argSettings.value( argVariableName ).toString() };
if ( argItemIsFile
&& !CheckPathAndComplain( tempString, argVariableName, argMessage ) ) {
tempString.clear();
}
return tempString;
}
return QString{}; return QString{};
} else {
QString tempString{argSettings.value(argVariableName).toString()};
if (argItemIsFile &&
!CheckPathAndComplain(tempString, argVariableName, argMessage)) {
tempString.clear();
}
return tempString;
}
return QString{};
} }
void lc::Settings::SetLocalzLeafSize( QString arg) { void lc::Settings::SetLocalzLeafSize(QString arg) { localzLeafSize = arg; }
localzLeafSize = arg;
}
void lc::Settings::SetChosenZTreePort( const int argPort ){ void lc::Settings::SetChosenZTreePort(const int argPort) {
chosenzTreePort = argPort; chosenzTreePort = argPort;
} }

@ -29,101 +29,104 @@
namespace lc { namespace lc {
class Settings : public QObject { class Settings : public QObject {
Q_OBJECT Q_OBJECT
public: public:
Settings() = delete; Settings() = delete;
explicit Settings( const QSettings &argSettings, QObject *argParent = nullptr ); explicit Settings(const QSettings &argSettings, QObject *argParent = nullptr);
Settings( const Settings &argSettings ) = delete; Settings(const Settings &argSettings) = delete;
Settings& operator=( const Settings &argSettings ) = delete; Settings &operator=(const Settings &argSettings) = delete;
Settings( Settings &&argSettings ) = delete; Settings(Settings &&argSettings) = delete;
Settings& operator=( Settings &&argSettings ) = delete; Settings &operator=(Settings &&argSettings) = delete;
~Settings(); ~Settings();
int GetChosenZTreePort() const { return chosenzTreePort; } int GetChosenZTreePort() const { return chosenzTreePort; }
QVector< Client* > &GetClients() { return clients; } QVector<Client *> &GetClients() { return clients; }
QString GetLocalzLeafName() const; QString GetLocalzLeafName() const;
void SetChosenZTreePort( const int argPort ); void SetChosenZTreePort(const int argPort);
void SetLocalzLeafName( const QString &argLocalzLeafName ); void SetLocalzLeafName(const QString &argLocalzLeafName);
const int defaultReceiptIndex = 0; const int defaultReceiptIndex = 0;
const QString browserCmd; const QString browserCmd;
const QString clientBrowserCmd; const QString clientBrowserCmd;
const QString clientChromiumCmd; const QString clientChromiumCmd;
const QString dvipsCmd; const QString dvipsCmd;
const QString fileMngr; const QString fileMngr;
const QString killallCmd; const QString killallCmd;
const QString latexCmd; const QString latexCmd;
const QString lcDataDir; const QString lcDataDir;
const QString localUserName; const QString localUserName;
QString localzLeafSize; QString localzLeafSize;
void SetLocalzLeafSize( QString arg); void SetLocalzLeafSize(QString arg);
QString GetLocalzLeafSize() const { return localzLeafSize; } QString GetLocalzLeafSize() const { return localzLeafSize; }
const QString lprCmd; const QString lprCmd;
const QString netstatCmd; const QString netstatCmd;
const QString netwBrdAddr; const QString netwBrdAddr;
const QString orseeUrl; const QString orseeUrl;
const QString pingCmd; const QString pingCmd;
const QString postscriptViewer; const QString postscriptViewer;
const QString ps2pdfCmd; const QString ps2pdfCmd;
const QString pkeyPathRoot; const QString pkeyPathRoot;
const QString pkeyPathUser; const QString pkeyPathUser;
const QString rmCmd; const QString rmCmd;
const QString scpCmd; const QString scpCmd;
const QString serverIP; const QString serverIP;
const QString sshCmd; const QString sshCmd;
const QString tasksetCmd; const QString tasksetCmd;
const QString termEmulCmd; const QString termEmulCmd;
const QString userNameOnClients; const QString userNameOnClients;
const QString vncViewer; const QString vncViewer;
const QString wakeonlanCmd; const QString wakeonlanCmd;
const QString webcamDisplayCmd; const QString webcamDisplayCmd;
const QStringList webcams; const QStringList webcams;
const QStringList webcams_names; const QStringList webcams_names;
const QString wineCmd; const QString wineCmd;
const QString wmctrlCmd; const QString wmctrlCmd;
const QString xsetCmd; const QString xsetCmd;
const QString zTreeInstDir; const QString zTreeInstDir;
const QString restartCrashedSessionScript; const QString restartCrashedSessionScript;
const QStringList adminUsers; const QStringList adminUsers;
const QStringList installedLaTeXHeaders; const QStringList installedLaTeXHeaders;
const QStringList installedZTreeVersions; const QStringList installedZTreeVersions;
const quint16 clientHelpNotificationServerPort = 0; const quint16 clientHelpNotificationServerPort = 0;
private: private:
static bool CheckPathAndComplain( const QString &argPath, const QString &argVariableName, static bool CheckPathAndComplain(const QString &argPath,
const QString &argMessage ); const QString &argVariableName,
static QVector< Client* > CreateClients( const QSettings &argSettings, const QString &argMessage);
const QString &argPingCmd ); static QVector<Client *> CreateClients(const QSettings &argSettings,
static QMap< QString, Client* > CreateClIPsToClMap( const QVector< Client* > &argClients ); const QString &argPingCmd);
QStringList DetectInstalledLaTeXHeaders() const; static QMap<QString, Client *>
QStringList DetectInstalledzTreeVersions() const; CreateClIPsToClMap(const QVector<Client *> &argClients);
static QStringList GetAdminUsers( const QSettings &argSettings ); QStringList DetectInstalledLaTeXHeaders() const;
static quint16 GetClientHelpNotificationServerPort( const QSettings &argSettings ); QStringList DetectInstalledzTreeVersions() const;
static int GetDefaultReceiptIndex( const QSettings &argSettings ); static QStringList GetAdminUsers(const QSettings &argSettings);
static int GetInitialPort( const QSettings &argSettings ); static quint16
static QString GetLocalUserName(); GetClientHelpNotificationServerPort(const QSettings &argSettings);
static QString ReadSettingsItem( const QString &argVariableName, static int GetDefaultReceiptIndex(const QSettings &argSettings);
const QString &argMessage, static int GetInitialPort(const QSettings &argSettings);
const QSettings &argSettings, static QString GetLocalUserName();
bool argItemIsFile ); static QString ReadSettingsItem(const QString &argVariableName,
const QString &argMessage,
const QSettings &argSettings,
bool argItemIsFile);
int chosenzTreePort = 0; int chosenzTreePort = 0;
QVector< Client* > clients; QVector<Client *> clients;
QString localzLeafName; QString localzLeafName;
public: public:
const QMap< QString, Client* > clIPsToClMap; const QMap<QString, Client *> clIPsToClMap;
}; };
} } // namespace lc
inline QString lc::Settings::GetLocalzLeafName() const { inline QString lc::Settings::GetLocalzLeafName() const {
return localzLeafName; return localzLeafName;
} }
inline void lc::Settings::SetLocalzLeafName( const QString &argLocalzLeafName ) { inline void lc::Settings::SetLocalzLeafName(const QString &argLocalzLeafName) {
localzLeafName = argLocalzLeafName; localzLeafName = argLocalzLeafName;
} }
#endif // SETTINGS_H #endif // SETTINGS_H

@ -24,28 +24,29 @@
#include "settings.h" #include "settings.h"
#include "ztree.h" #include "ztree.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
lc::ZTree::ZTree( const QString &argZTreeDataTargetPath, const int &argZTreePort, lc::ZTree::ZTree(const QString &argZTreeDataTargetPath, const int &argZTreePort,
const QString &argZTreeVersionPath, QObject *argParent ) : const QString &argZTreeVersionPath, QObject *argParent)
QObject{ argParent } : QObject{argParent} {
{ QStringList arguments{QStringList{}
QStringList arguments{ QStringList{} << "-c" << "0" << settings->wineCmd << "-c"
<< QString{ settings->zTreeInstDir + "/zTree_" << "0" << settings->wineCmd
+ argZTreeVersionPath + "/ztree.exe" } << QString{settings->zTreeInstDir + "/zTree_" +
<< "/datadir" << QString{ "Z:/" + argZTreeDataTargetPath } argZTreeVersionPath + "/ztree.exe"}
<< "/privdir" << QString{ "Z:/" + argZTreeDataTargetPath } << "/datadir" << QString{"Z:/" + argZTreeDataTargetPath}
<< "/gsfdir" << QString{ "Z:/" + argZTreeDataTargetPath } << "/privdir" << QString{"Z:/" + argZTreeDataTargetPath}
<< "/tempdir" << QString{ "Z:/" + argZTreeDataTargetPath } << "/gsfdir" << QString{"Z:/" + argZTreeDataTargetPath}
<< "/leafdir" << QString{ "Z:/" + argZTreeDataTargetPath } << "/tempdir" << QString{"Z:/" + argZTreeDataTargetPath}
<< "/channel" << QString::number( argZTreePort - 7000 ) }; << "/leafdir" << QString{"Z:/" + argZTreeDataTargetPath}
<< "/channel" << QString::number(argZTreePort - 7000)};
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
zTreeInstance.setProcessEnvironment( env ); zTreeInstance.setProcessEnvironment(env);
zTreeInstance.setWorkingDirectory( QDir::homePath() ); zTreeInstance.setWorkingDirectory(QDir::homePath());
zTreeInstance.start( settings->tasksetCmd, arguments, QIODevice::NotOpen ); zTreeInstance.start(settings->tasksetCmd, arguments, QIODevice::NotOpen);
connect( &zTreeInstance, SIGNAL( finished( int ) ), connect(&zTreeInstance, SIGNAL(finished(int)), this,
this, SIGNAL( ZTreeClosed( int ) ) ); SIGNAL(ZTreeClosed(int)));
qDebug() << settings->tasksetCmd << arguments.join( " " ); qDebug() << settings->tasksetCmd << arguments.join(" ");
} }

@ -30,23 +30,23 @@ namespace lc {
//! A class to contain running zTree instances. //! A class to contain running zTree instances.
/*! /*!
This class is element of every session and is used to handle all zTree related data. This class is element of every session and is used to handle all zTree related
data.
*/ */
class ZTree: public QObject { class ZTree : public QObject {
Q_OBJECT Q_OBJECT
public: public:
ZTree( const QString &argZTreeDataTargetPath, ZTree(const QString &argZTreeDataTargetPath, const int &argZTreePort,
const int &argZTreePort, const QString &argZTreeVersionPath, const QString &argZTreeVersionPath, QObject *argParent = nullptr);
QObject *argParent = nullptr );
signals: signals:
void ZTreeClosed( int argExitCode ); void ZTreeClosed(int argExitCode);
private: private:
QProcess zTreeInstance; QProcess zTreeInstance;
}; };
} } // namespace lc
#endif // ZTREE_H #endif // ZTREE_H

@ -21,49 +21,47 @@
#include <QMessageBox> #include <QMessageBox>
#include "Lib/settings.h"
#include "localzleafstarter.h" #include "localzleafstarter.h"
#include "ui_localzleafstarter.h" #include "ui_localzleafstarter.h"
#include "Lib/settings.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
lc::LocalzLeafStarter::LocalzLeafStarter( QWidget *argParent ) : lc::LocalzLeafStarter::LocalzLeafStarter(QWidget *argParent)
QWidget{ argParent }, : QWidget{argParent}, ui{new Ui::LocalzLeafStarter} {
ui{ new Ui::LocalzLeafStarter } ui->setupUi(this);
{
ui->setupUi( this );
//Choose initial port from settings // Choose initial port from settings
if ( settings->GetChosenZTreePort() ) { if (settings->GetChosenZTreePort()) {
ui->SBzLeafPort->setValue( settings->GetChosenZTreePort() ); ui->SBzLeafPort->setValue(settings->GetChosenZTreePort());
} }
//Choose initial z-Leave size from settings // Choose initial z-Leave size from settings
ui->LELocalzLeafSize->setText( settings->GetLocalzLeafSize() ); ui->LELocalzLeafSize->setText(settings->GetLocalzLeafSize());
ui->CBzLeafVersion->addItem(tr("Please choose a version"));
ui->CBzLeafVersion->addItem( tr( "Please choose a version" ) ); if (!settings->installedZTreeVersions.isEmpty()) {
if ( !settings->installedZTreeVersions.isEmpty() ) { ui->CBzLeafVersion->addItems(settings->installedZTreeVersions);
ui->CBzLeafVersion->addItems( settings->installedZTreeVersions ); }
}
} }
lc::LocalzLeafStarter::~LocalzLeafStarter() { lc::LocalzLeafStarter::~LocalzLeafStarter() { delete ui; }
delete ui;
}
void lc::LocalzLeafStarter::on_PBStartLocalzLeaf_clicked() { void lc::LocalzLeafStarter::on_PBStartLocalzLeaf_clicked() {
if ( ui->CBzLeafVersion->currentIndex() == 0 ) { if (ui->CBzLeafVersion->currentIndex() == 0) {
QMessageBox::information( this, tr( "No z-Tree version chosen" ), QMessageBox::information(
tr( "The was not chosen a z-Tree version, yet. This is" this, tr("No z-Tree version chosen"),
" mandatory, so please set one" ) , QMessageBox::Ok ); tr("The was not chosen a z-Tree version, yet. This is"
return; " mandatory, so please set one"),
} QMessageBox::Ok);
return;
}
//Set chosen z-Leaf size // Set chosen z-Leaf size
settings->SetLocalzLeafSize( ui->LELocalzLeafSize->text() ); settings->SetLocalzLeafSize(ui->LELocalzLeafSize->text());
//Emit start local z-Leaf request to main window // Emit start local z-Leaf request to main window
emit LocalzLeafRequested( ui->LEzLeafName->text(), ui->CBzLeafVersion->currentText(), emit LocalzLeafRequested(ui->LEzLeafName->text(),
ui->SBzLeafPort->value() ); ui->CBzLeafVersion->currentText(),
ui->SBzLeafPort->value());
} }

@ -29,22 +29,23 @@ class LocalzLeafStarter;
} }
class LocalzLeafStarter : public QWidget { class LocalzLeafStarter : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit LocalzLeafStarter( QWidget *argParent = nullptr ); explicit LocalzLeafStarter(QWidget *argParent = nullptr);
~LocalzLeafStarter(); ~LocalzLeafStarter();
signals: signals:
void LocalzLeafRequested( QString argzLeafName, QString argzLeafVersion, int argzTreePort ); void LocalzLeafRequested(QString argzLeafName, QString argzLeafVersion,
int argzTreePort);
private: private:
Ui::LocalzLeafStarter *ui = nullptr; Ui::LocalzLeafStarter *ui = nullptr;
private slots: private slots:
void on_PBStartLocalzLeaf_clicked(); void on_PBStartLocalzLeaf_clicked();
}; };
} } // namespace lc
#endif // LOCALZLEAFSTARTER_H #endif // LOCALZLEAFSTARTER_H

@ -21,16 +21,16 @@
#include <QApplication> #include <QApplication>
#include "mainwindow.h"
#include "Lib/settings.h" #include "Lib/settings.h"
#include "mainwindow.h"
std::unique_ptr<lc::Settings> settings;
std::unique_ptr< lc::Settings > settings; int main(int argc, char *argv[]) {
QApplication a{argc, argv};
settings.reset(new lc::Settings{QSettings{"Labcontrol", "Labcontrol"}});
lc::MainWindow w;
w.show();
int main( int argc, char *argv[] ) { return a.exec();
QApplication a{ argc, argv };
settings.reset( new lc::Settings{ QSettings{ "Labcontrol", "Labcontrol" } } );
lc::MainWindow w;
w.show();
return a.exec();
} }

File diff suppressed because it is too large Load Diff

@ -20,7 +20,15 @@
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
enum class icons_t : unsigned short int { UNKNOWN, OFF, DOWN, BOOT, ON, ZLEAF, ICON_QUANTITY }; enum class icons_t : unsigned short int {
UNKNOWN,
OFF,
DOWN,
BOOT,
ON,
ZLEAF,
ICON_QUANTITY
};
#include "Lib/client.h" #include "Lib/client.h"
#include "Lib/lablib.h" #include "Lib/lablib.h"
@ -45,94 +53,109 @@ class MainWindow;
//! The class containing the graphical user interface. //! The class containing the graphical user interface.
/*! /*!
This class represents the graphical user interface and all connected functionality. This class represents the graphical user interface and all connected
functionality.
*/ */
class MainWindow : public QMainWindow { class MainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow( QWidget *argParent = nullptr ); explicit MainWindow(QWidget *argParent = nullptr);
~MainWindow(); ~MainWindow();
private slots: private slots:
void on_CBWebcamChooser_activated(int index); void on_CBWebcamChooser_activated(int index);
void on_PBBeamFile_clicked(); void on_PBBeamFile_clicked();
void on_PBBoot_clicked(); void on_PBBoot_clicked();
void on_PBChooseFile_clicked(); void on_PBChooseFile_clicked();
void on_PBExecute_clicked(); void on_PBExecute_clicked();
void on_PBKillLocalzLeaf_clicked(); void on_PBKillLocalzLeaf_clicked();
void on_PBOpenFilesystem_clicked(); void on_PBOpenFilesystem_clicked();
void on_PBOpenTerminal_clicked(); void on_PBOpenTerminal_clicked();
void on_PBPrintPaymentFileManually_clicked(); void on_PBPrintPaymentFileManually_clicked();
void on_PBRunzLeaf_clicked(); void on_PBRunzLeaf_clicked();
void on_PBShowORSEE_clicked(); void on_PBShowORSEE_clicked();
void on_PBShowPreprints_clicked(); void on_PBShowPreprints_clicked();
void on_PBShutdown_clicked(); void on_PBShutdown_clicked();
void on_PBStartLocalzLeaf_clicked(); void on_PBStartLocalzLeaf_clicked();
void on_PBStartSession_clicked(); void on_PBStartSession_clicked();
void on_PBStartzLeaf_clicked(); void on_PBStartzLeaf_clicked();
void on_PBViewDesktopViewOnly_clicked(); void on_PBViewDesktopViewOnly_clicked();
void on_PBViewDesktopFullControl_clicked(); void on_PBViewDesktopFullControl_clicked();
void on_RBUseLocalUser_toggled(bool checked); void on_RBUseLocalUser_toggled(bool checked);
void StartLocalzLeaf( QString argzLeafName, QString argzLeafVersion, int argzTreePort ); void StartLocalzLeaf(QString argzLeafName, QString argzLeafVersion,
//! Updates the icons of the QTableView displaying the clients' states int argzTreePort);
/*! //! Updates the icons of the QTableView displaying the clients' states
* This function iterates over all valid items of the 'TVClients' and sets their states /*!
* by querying the represented 'lcClient' instances. * This function iterates over all valid items of the 'TVClients' and sets
*/ * their states by querying the represented 'lcClient' instances.
void UpdateClientsTableView(); */
void UpdateClientsTableView();
signals: signals:
/*Session actions*/ /*Session actions*/
void RequestNewDataTargetPath(); void RequestNewDataTargetPath();
void RequestNewSession( QVector< Client* > argAssocCl, QString argParticipNameReplacement, void RequestNewSession(QVector<Client *> argAssocCl,
bool argPrintLocalReceipts, QString argReceiptsHeader, QString argParticipNameReplacement,
QString argzTreeDataTargetPath, quint16 argzTreePort, bool argPrintLocalReceipts, QString argReceiptsHeader,
QString argzTreeVersion ); QString argzTreeDataTargetPath, quint16 argzTreePort,
QString argzTreeVersion);
private: private:
//! Checks, if the user has administrative rights //! Checks, if the user has administrative rights
/*! /*!
@return Returns true, if the user has administrative rights (If the user is in the 'sudo' group) @return Returns true, if the user has administrative rights (If the user is
*/ in the 'sudo' group)
bool CheckIfUserIsAdmin(); */
//! Disables widgets for functions not available due to lacking devices or settings bool CheckIfUserIsAdmin();
void DisableDisfunctionalWidgets(); //! Disables widgets for functions not available due to lacking devices or
//! Loads all needed client icon QPixmaps //! settings
void LoadIconPixmaps(); void DisableDisfunctionalWidgets();
//! Sets up all used widgets //! Loads all needed client icon QPixmaps
void SetupWidgets(); void LoadIconPixmaps();
//! Sets up all used widgets
QStandardItemModel *clients_view_model = nullptr; //! The view storing all clients data void SetupWidgets();
QTimer *gui_update_timer = nullptr; //! A QTimer triggering updates of the graphical user interface
QVector< QPixmap > icons; //! Vector of pixmaps storing the icons indicating the clients' statuses QStandardItemModel *clients_view_model =
Lablib *lablib = nullptr; //! Accumulator of all program logic being accessed by the GUI nullptr; //! The view storing all clients data
bool localzLeavesAreRunning = false; //! Stores if a local z-Leaf instance is running on the server ('true' if local z-Leaf exists) QTimer *gui_update_timer =
QButtonGroup *userChooseButtonGroup = nullptr; //! Used to group the radio buttons choosing which user shall be used for administrative client actions nullptr; //! A QTimer triggering updates of the graphical user interface
Ui::MainWindow *ui = nullptr; //! Pointer storing all GUI items QVector<QPixmap> icons; //! Vector of pixmaps storing the icons indicating the
QVector<QStandardItem *> *valid_items = nullptr; //! Stores all valid Client instances displayed by the table view, its main use is as iterable object for 'update_clients_table_view()' //! clients' statuses
Lablib *lablib =
nullptr; //! Accumulator of all program logic being accessed by the GUI
bool localzLeavesAreRunning =
false; //! Stores if a local z-Leaf instance is running on the server
//! ('true' if local z-Leaf exists)
QButtonGroup *userChooseButtonGroup =
nullptr; //! Used to group the radio buttons choosing which user shall be
//! used for administrative client actions
Ui::MainWindow *ui = nullptr; //! Pointer storing all GUI items
QVector<QStandardItem *> *valid_items =
nullptr; //! Stores all valid Client instances displayed by the table
//! view, its main use is as iterable object for
//! 'update_clients_table_view()'
private slots: private slots:
void StartReceiptsHandler( QString argzTreeDataTargetPath, void StartReceiptsHandler(QString argzTreeDataTargetPath,
bool argReceiptsForLocalClients, bool argReceiptsForLocalClients,
QString argAnonymousReceiptsPlaceholder, QString argAnonymousReceiptsPlaceholder,
QString argLatexHeaderName, QString argLatexHeaderName, QString argDateString);
QString argDateString ); void on_PBstartBrowser_clicked();
void on_PBstartBrowser_clicked(); void on_PBstopBrowser_clicked();
void on_PBstopBrowser_clicked();
/* Session actions */
/* Session actions */ void on_PBStopZtree_clicked();
void on_PBStopZtree_clicked(); void on_PBRecoverCrashedSession_clicked();
void on_PBRecoverCrashedSession_clicked(); void GetNewDataTargetPath();
void GetNewDataTargetPath(); void on_CBDataTargetPath_activated(int argIndex);
void on_CBDataTargetPath_activated( int argIndex ); void on_CBReceiptsHeader_activated(int argIndex);
void on_CBReceiptsHeader_activated(int argIndex); void on_ChBPrintanonymousreceipts_clicked();
void on_ChBPrintanonymousreceipts_clicked(); void on_PBKillzLeaf_clicked();
void on_PBKillzLeaf_clicked(); void on_PBEnableRMB_clicked();
void on_PBEnableRMB_clicked(); void on_PBDisableRMB_clicked();
void on_PBDisableRMB_clicked();
}; };
} } // namespace lc
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

@ -21,79 +21,80 @@
#include <QFileDialog> #include <QFileDialog>
#include "Lib/settings.h"
#include "manualprintingsetup.h" #include "manualprintingsetup.h"
#include "ui_manualprintingsetup.h" #include "ui_manualprintingsetup.h"
#include "Lib/settings.h"
extern std::unique_ptr< lc::Settings > settings; extern std::unique_ptr<lc::Settings> settings;
lc::ManualPrintingSetup::ManualPrintingSetup( QWidget *argParent ) : lc::ManualPrintingSetup::ManualPrintingSetup(QWidget *argParent)
QWidget{ argParent }, : QWidget{argParent}, ui{new Ui::ManualPrintingSetup} {
ui{ new Ui::ManualPrintingSetup } ui->setupUi(this);
{
ui->setupUi( this );
if ( settings->dvipsCmd.isEmpty() || settings->latexCmd.isEmpty() if (settings->dvipsCmd.isEmpty() || settings->latexCmd.isEmpty() ||
|| settings->lcDataDir.isEmpty() || settings->lprCmd.isEmpty() settings->lcDataDir.isEmpty() || settings->lprCmd.isEmpty() ||
|| settings->postscriptViewer.isEmpty() || settings->ps2pdfCmd.isEmpty() settings->postscriptViewer.isEmpty() || settings->ps2pdfCmd.isEmpty() ||
|| settings->rmCmd.isEmpty() || settings->vncViewer.isEmpty() ) { settings->rmCmd.isEmpty() || settings->vncViewer.isEmpty()) {
ui->VLManualPrintingSetup->setEnabled( false ); ui->VLManualPrintingSetup->setEnabled(false);
QMessageBox::information( this, tr( "Receipts printing will not work" ), QMessageBox::information(
tr( "Some component essential for receipts creation and" this, tr("Receipts printing will not work"),
" printing is missing. No receipts will be created or" tr("Some component essential for receipts creation and"
" printed." ), QMessageBox::Ok ); " printing is missing. No receipts will be created or"
} else { " printed."),
ui->CBReceiptsHeader->addItems( settings->installedLaTeXHeaders ); QMessageBox::Ok);
} else {
ui->CBReceiptsHeader->addItems(settings->installedLaTeXHeaders);
if ( settings->defaultReceiptIndex if (settings->defaultReceiptIndex &&
&& settings->defaultReceiptIndex < ui->CBReceiptsHeader->count() ) { settings->defaultReceiptIndex < ui->CBReceiptsHeader->count()) {
ui->CBReceiptsHeader->setCurrentIndex( settings->defaultReceiptIndex ); ui->CBReceiptsHeader->setCurrentIndex(settings->defaultReceiptIndex);
}
} }
}
} }
lc::ManualPrintingSetup::~ManualPrintingSetup() { lc::ManualPrintingSetup::~ManualPrintingSetup() { delete ui; }
delete ui;
}
void lc::ManualPrintingSetup::on_PBSelectFile_clicked() { void lc::ManualPrintingSetup::on_PBSelectFile_clicked() {
QFileDialog fileDialog{ this, tr( "Please choose a payment file to print." ), QFileDialog fileDialog{this, tr("Please choose a payment file to print."),
QDir::homePath(), "*.pay" }; QDir::homePath(), "*.pay"};
fileDialog.setFileMode( QFileDialog::ExistingFile ); fileDialog.setFileMode(QFileDialog::ExistingFile);
fileDialog.setOption( QFileDialog::ReadOnly, true ); fileDialog.setOption(QFileDialog::ReadOnly, true);
if ( fileDialog.exec() ) { if (fileDialog.exec()) {
ui->PBSelectFile->setStyleSheet( "" ); ui->PBSelectFile->setStyleSheet("");
const QString tmpFileName{ fileDialog.selectedFiles().at( 0 ) }; const QString tmpFileName{fileDialog.selectedFiles().at(0)};
dateString = tmpFileName.split( '/', QString::KeepEmptyParts, dateString =
Qt::CaseInsensitive ).last() tmpFileName.split('/', QString::KeepEmptyParts, Qt::CaseInsensitive)
.split( '.', QString::KeepEmptyParts, .last()
Qt::CaseInsensitive ).first(); .split('.', QString::KeepEmptyParts, Qt::CaseInsensitive)
workPath = tmpFileName; .first();
workPath.truncate( workPath.lastIndexOf( '/' ) ); workPath = tmpFileName;
} workPath.truncate(workPath.lastIndexOf('/'));
}
} }
void lc::ManualPrintingSetup::on_CBReceiptsHeader_activated( int argIndex ) { void lc::ManualPrintingSetup::on_CBReceiptsHeader_activated(int argIndex) {
Q_UNUSED( argIndex ); Q_UNUSED(argIndex);
ui->CBReceiptsHeader->setStyleSheet( "" ); ui->CBReceiptsHeader->setStyleSheet("");
} }
void lc::ManualPrintingSetup::on_ChBPrintAnonymousReceipts_clicked( bool argChecked ) { void lc::ManualPrintingSetup::on_ChBPrintAnonymousReceipts_clicked(
ui->ChBPrintAnonymousReceipts->setStyleSheet( "" ); bool argChecked) {
ui->ChBPrintAnonymousReceipts->setStyleSheet("");
ui->LReplaceParticipantNames->setEnabled( argChecked ); ui->LReplaceParticipantNames->setEnabled(argChecked);
ui->CBReplaceParticipantNames->setEnabled( argChecked ); ui->CBReplaceParticipantNames->setEnabled(argChecked);
} }
void lc::ManualPrintingSetup::on_PBPrint_clicked() { void lc::ManualPrintingSetup::on_PBPrint_clicked() {
QString anonymousReceiptsPlaceholder; QString anonymousReceiptsPlaceholder;
if ( ui->ChBPrintAnonymousReceipts->isChecked() ) { if (ui->ChBPrintAnonymousReceipts->isChecked()) {
anonymousReceiptsPlaceholder = ui->CBReplaceParticipantNames->currentText(); anonymousReceiptsPlaceholder = ui->CBReplaceParticipantNames->currentText();
} }
emit RequestReceiptsHandler( workPath, ui->ChBReceiptsForLocalClients->isChecked(), emit RequestReceiptsHandler(workPath,
anonymousReceiptsPlaceholder, ui->ChBReceiptsForLocalClients->isChecked(),
ui->CBReceiptsHeader->currentText(), dateString ); anonymousReceiptsPlaceholder,
ui->CBReceiptsHeader->currentText(), dateString);
this->deleteLater(); this->deleteLater();
} }

@ -29,31 +29,31 @@ class ManualPrintingSetup;
} }
class ManualPrintingSetup : public QWidget { class ManualPrintingSetup : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit ManualPrintingSetup( QWidget *argParent = nullptr ); explicit ManualPrintingSetup(QWidget *argParent = nullptr);
~ManualPrintingSetup(); ~ManualPrintingSetup();
signals: signals:
void RequestReceiptsHandler( QString argzTreeDataTargetPath, void RequestReceiptsHandler(QString argzTreeDataTargetPath,
bool argReceiptsForLocalClients, bool argReceiptsForLocalClients,
QString argAnonymousReceiptsPlaceholder, QString argAnonymousReceiptsPlaceholder,
QString argLatexHeaderName, QString argLatexHeaderName,
QString argDateString ); QString argDateString);
private: private:
QString dateString; QString dateString;
Ui::ManualPrintingSetup *ui = nullptr; Ui::ManualPrintingSetup *ui = nullptr;
QString workPath; QString workPath;
private slots: private slots:
void on_CBReceiptsHeader_activated( int argIndex ); void on_CBReceiptsHeader_activated(int argIndex);
void on_ChBPrintAnonymousReceipts_clicked( bool argChecked ); void on_ChBPrintAnonymousReceipts_clicked(bool argChecked);
void on_PBPrint_clicked(); void on_PBPrint_clicked();
void on_PBSelectFile_clicked(); void on_PBSelectFile_clicked();
}; };
} } // namespace lc
#endif // MANUALPRINTINGSETUP_H #endif // MANUALPRINTINGSETUP_H

Loading…
Cancel
Save