Skip to content

Commit dd86c8d

Browse files
committed
Changes for v0.2
1 parent 5890c0a commit dd86c8d

21 files changed

+2824
-413
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.5)
22

3-
project(parpargui VERSION 0.1 LANGUAGES CXX)
3+
project(parpargui VERSION 0.2 LANGUAGES CXX)
44

55
set(CMAKE_INCLUDE_CURRENT_DIR ON)
66

@@ -44,6 +44,7 @@ set(PROJECT_SOURCES
4444
sourcefile.h sourcefile.cpp
4545
sourcefileframe.h sourcefileframe.cpp
4646
clientinfo.h clientinfo.cpp
47+
parparclient.h parparclient.cpp
4748
res.qrc
4849
${TS_FILES}
4950
)

clientinfo.cpp

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,15 @@
33
#include <QJsonDocument>
44
#include <QJsonObject>
55

6-
ClientInfo::ClientInfo(QObject* parent) : QObject(parent)
6+
ClientInfo::ClientInfo(QObject* parent) : QObject(parent), parpar(parent)
77
{
8-
connect(&parpar, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &ClientInfo::finished);
8+
connect(&parpar, &ParParClient::failed, this, &ClientInfo::failed);
99
// treat failing to start, like a crash
10-
connect(&parpar, &QProcess::errorOccurred, this, [this](QProcess::ProcessError err) {
11-
if(err == QProcess::FailedToStart) {
12-
this->finished(0, QProcess::ExitStatus::CrashExit);
13-
}
14-
// let other handler handle other errors
15-
});
16-
isRunning = false;
17-
timer.setInterval(10000);
18-
timer.setSingleShot(true);
19-
connect(&timer, &QTimer::timeout, this, [this]() {
20-
this->parpar.kill();
10+
connect(&parpar, &ParParClient::output, this, [this](const QJsonObject& doc) {
11+
_version = doc.value("version").toString();
12+
_creator = doc.value("creator").toString();
13+
14+
emit updated();
2115
});
2216

2317
// default values
@@ -27,34 +21,6 @@ ClientInfo::ClientInfo(QObject* parent) : QObject(parent)
2721

2822
void ClientInfo::refresh()
2923
{
30-
// create process
31-
auto cmd = Settings::getInstance().parparBin();
32-
QStringList args{"--client-info"};
33-
if(cmd.length() > 1)
34-
args.prepend(cmd[1]);
35-
isRunning = true;
36-
parpar.start(cmd[0], args);
37-
timer.start();
38-
}
39-
40-
void ClientInfo::finished(int exitCode, QProcess::ExitStatus exitStatus)
41-
{
42-
timer.stop();
43-
isRunning = false;
44-
if(exitStatus != QProcess::ExitStatus::NormalExit || exitCode != 0) {
45-
emit failed(); // TODO: pass back diagnostic info to help see what's wrong
46-
} else {
47-
const auto data = QJsonDocument::fromJson(parpar.readAllStandardOutput());
48-
49-
if(data.isNull() || !data.isObject())
50-
emit failed();
51-
else {
52-
const auto doc = data.object();
53-
_version = doc.value("version").toString();
54-
_creator = doc.value("creator").toString();
55-
56-
emit updated();
57-
}
58-
}
24+
parpar.run({"--version"});
5925
}
6026

clientinfo.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,20 @@
11
#ifndef CLIENTINFO_H
22
#define CLIENTINFO_H
33

4-
#include <QProcess>
5-
#include <QTimer>
4+
#include "parparclient.h"
65

76
class ClientInfo : public QObject
87
{
98
Q_OBJECT
109

1110
ClientInfo(QObject* parent = nullptr);
12-
QProcess parpar;
13-
QTimer timer;
14-
bool isRunning;
11+
ParParClient parpar;
1512
QString _version;
1613
QString _creator;
1714

18-
private slots:
19-
void finished(int exitCode, QProcess::ExitStatus exitStatus);
20-
2115
signals:
2216
void updated();
23-
void failed();
17+
void failed(const QString& error);
2418

2519
public:
2620
static ClientInfo& getInstance()

createprogress.cpp

Lines changed: 103 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "settings.h"
44
#include <QDir>
55
#include <QMessageBox>
6+
#include <QJsonDocument>
7+
#include <QJsonObject>
68

79
#ifdef Q_OS_WINDOWS
810
#define WIN32_LEAN_AND_MEAN
@@ -89,7 +91,7 @@ CreateProgress::CreateProgress(QWidget *parent) :
8991
// TODO: consider adding decimal percentage bar: https://www.qtcentre.org/threads/70885-QProgressBar-with-in-decimal?s=bdfd413197898978b8ef6ea933c3e67e&p=307578#post307578
9092
}
9193

92-
void CreateProgress::run(QStringList args, const QByteArray& inFiles, const QString& baseOutput_, const QString& outDir_, const QStringList& outFiles_)
94+
void CreateProgress::run(QStringList args, const QHash<QString, QString>& env, const QByteArray& inFiles, const QString& baseOutput_, const QString& outDir_, const QStringList& outFiles_)
9395
{
9496
baseOutput = baseOutput_;
9597
outDir = outDir_;
@@ -100,17 +102,25 @@ void CreateProgress::run(QStringList args, const QByteArray& inFiles, const QStr
100102
if(cmd.length() > 1)
101103
args.prepend(cmd[1]);
102104

103-
args << "--quiet" << "--progress" << "stdout" << "--input-file0" << "-";
105+
args << "--quiet" << "--json" << "--progress" << "stdout" << "--input-file0" << "-";
104106
parpar.setArguments(args);
105107

108+
if(!env.empty()) {
109+
auto procEnv = QProcessEnvironment::systemEnvironment();
110+
auto it = QHashIterator<QString, QString>(env);
111+
while(it.hasNext()) {
112+
it.next();
113+
procEnv.insert(it.key(), it.value());
114+
}
115+
parpar.setProcessEnvironment(procEnv);
116+
}
117+
106118
this->setWindowTitle(tr("ParPar - Creating %2")
107119
.arg(baseOutput));
108120

109121
// send stdin when process starts
110122
connect(&parpar, &QProcess::started, this, [=]() {
111123
ui->lblStatus->setText("");
112-
ui->btnBackground->setEnabled(true);
113-
ui->btnNotify->setEnabled(true);
114124
ui->btnPause->setEnabled(true);
115125

116126
if(ui->btnBackground->isChecked())
@@ -142,36 +152,32 @@ void CreateProgress::run(QStringList args, const QByteArray& inFiles, const QStr
142152

143153
void CreateProgress::gotStdout()
144154
{
145-
stdoutBuffer += QString::fromUtf8(parpar.readAllStandardOutput());
146-
147-
// find last % and update display
148-
int p = stdoutBuffer.lastIndexOf('%');
149-
if(p > 0) {
150-
// extract percentage
151-
int i = p;
152-
while(i--) {
153-
auto c = stdoutBuffer.at(i);
154-
if(c != '.' && !c.isDigit())
155-
break;
155+
stdoutBuffer.append(parpar.readAllStandardOutput());
156+
157+
// find end of JSON message
158+
int p = stdoutBuffer.indexOf("\n}");
159+
while(p > 0) {
160+
// extract message
161+
const auto doc = QJsonDocument::fromJson(stdoutBuffer.left(p + 2));
162+
stdoutBuffer = stdoutBuffer.mid(p + 2);
163+
p = stdoutBuffer.indexOf("\n}");
164+
165+
if(!doc.isNull() && !doc.isEmpty()) {
166+
const auto msg = doc.object().toVariantHash();
167+
const auto type = msg.value("type", "").toString();
168+
if(type == "progress") {
169+
bool ok;
170+
float progress = msg.value("progress_percent", -1).toFloat(&ok);
171+
if(progress >= 0 && ok) {
172+
ui->progressBar->setMaximum(10000);
173+
ui->progressBar->setValue(progress * 100);
174+
WIN_PROGRESS(SetProgressState, TBPF_NORMAL);
175+
WIN_PROGRESS(SetProgressValue, progress, 10000);
176+
177+
updateTitlePerc();
178+
}
179+
}
156180
}
157-
i++;
158-
if(i == p) return; // got a % without a preceeding number
159-
160-
bool ok;
161-
#if QT_VERSION >= 0x060000
162-
int progress = QStringView{stdoutBuffer}.mid(i, p-i).toFloat(&ok) * 100;
163-
#else
164-
int progress = stdoutBuffer.midRef(i, p-i).toFloat(&ok) * 100;
165-
#endif
166-
if(!ok) return; // why oh why???
167-
168-
ui->progressBar->setMaximum(10000);
169-
ui->progressBar->setValue(progress);
170-
WIN_PROGRESS(SetProgressState, TBPF_NORMAL);
171-
WIN_PROGRESS(SetProgressValue, progress, 10000);
172-
173-
updateTitlePerc();
174-
stdoutBuffer = stdoutBuffer.mid(p+1);
175181
}
176182
}
177183

@@ -202,20 +208,22 @@ void CreateProgress::finished(int exitCode, QProcess::ExitStatus exitStatus)
202208
} else if(exitCode != 0) {
203209
ended(tr("PAR2 creation failed (exit code: %1)").arg(exitCode), true);
204210
} else {
205-
ended("", false);
211+
ended("", true);
206212
}
207213
}
208214

209215
void CreateProgress::ended(const QString &error, bool showOutput)
210216
{
217+
//gotStdout(); // flush remaining stdout
218+
211219
bool success = error.isEmpty();
212220
ui->progressBar->setEnabled(false);
213221
ui->lblTime->setEnabled(false);
214-
ui->btnBackground->setEnabled(false);
215-
ui->btnNotify->setEnabled(false);
216222
ui->btnPause->setEnabled(false);
217223
if(success) {
218224
ui->lblStatus->setText(tr("PAR2 successfully created"));
225+
ui->progressBar->setMaximum(10000);
226+
ui->progressBar->setValue(10000);
219227
this->setWindowTitle(tr("ParPar - Finished creating %1").arg(baseOutput));
220228
WIN_PROGRESS(SetProgressState, TBPF_NOPROGRESS);
221229
} else {
@@ -246,9 +254,11 @@ void CreateProgress::ended(const QString &error, bool showOutput)
246254

247255
if(isCancelled) return;
248256

257+
bool hasOutput = false;
249258
if(showOutput) {
250259
auto output = QString::fromUtf8(parpar.readAllStandardError()).trimmed();
251260
if(!output.isEmpty()) {
261+
hasOutput = true;
252262
ui->txtMessage->setPlainText(output);
253263
ui->txtMessage->show();
254264

@@ -257,6 +267,9 @@ void CreateProgress::ended(const QString &error, bool showOutput)
257267
this->resize(this->width(), this->layout()->sizeHint().height());
258268

259269
this->setSizeGripEnabled(true);
270+
271+
if(success)
272+
ui->lblStatus->setText(tr("PAR2 created with warnings"));
260273
}
261274
}
262275

@@ -272,6 +285,9 @@ void CreateProgress::ended(const QString &error, bool showOutput)
272285
}
273286
QApplication::alert(this);
274287
}
288+
289+
if(!hasOutput && success && Settings::getInstance().runClose())
290+
this->close();
275291
}
276292

277293
void CreateProgress::deleteOutput()
@@ -308,6 +324,9 @@ void CreateProgress::on_CreateProgress_rejected()
308324
ended(tr("Cancelled"), false);
309325
parpar.waitForFinished(1000); // try to avoid warning of destroying QProcess whilst still active
310326
deleteOutput();
327+
328+
if(Settings::getInstance().runClose())
329+
this->close();
311330
}
312331
}
313332

@@ -316,61 +335,63 @@ void CreateProgress::on_btnBackground_clicked()
316335
{
317336
bool isBackground = ui->btnBackground->isChecked();
318337

338+
if(parpar.state() == QProcess::Running) {
319339
#ifdef Q_OS_WINDOWS
320-
static DWORD normPrio = 0x7fff;
321-
HANDLE hPP = OpenProcess(PROCESS_SET_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, parpar.processId());
322-
if(hPP == NULL) {
323-
ui->btnBackground->setEnabled(false);
324-
ui->btnBackground->setChecked(!isBackground);
325-
return;
326-
}
327-
if(normPrio == 0x7fff) {
328-
normPrio = GetPriorityClass(hPP);
329-
if(!normPrio) {
330-
// failed to retrieve, disable option
340+
static DWORD normPrio = 0x7fff;
341+
HANDLE hPP = OpenProcess(PROCESS_SET_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, parpar.processId());
342+
if(hPP == NULL) {
331343
ui->btnBackground->setEnabled(false);
332-
ui->btnBackground->setChecked(false);
333-
CloseHandle(hPP);
344+
ui->btnBackground->setChecked(!isBackground);
334345
return;
335346
}
336-
if(normPrio == IDLE_PRIORITY_CLASS) {
337-
// already at low priority
338-
ui->btnBackground->setEnabled(false);
339-
ui->btnBackground->setChecked(true);
340-
CloseHandle(hPP);
341-
return;
347+
if(normPrio == 0x7fff) {
348+
normPrio = GetPriorityClass(hPP);
349+
if(!normPrio) {
350+
// failed to retrieve, disable option
351+
ui->btnBackground->setEnabled(false);
352+
ui->btnBackground->setChecked(false);
353+
CloseHandle(hPP);
354+
return;
355+
}
356+
if(normPrio == IDLE_PRIORITY_CLASS) {
357+
// already at low priority
358+
ui->btnBackground->setEnabled(false);
359+
ui->btnBackground->setChecked(true);
360+
CloseHandle(hPP);
361+
return;
362+
}
342363
}
343-
}
344-
if(!SetPriorityClass(hPP, isBackground ? IDLE_PRIORITY_CLASS : normPrio)) {
345-
ui->btnBackground->setChecked(!isBackground);
346-
}
347-
CloseHandle(hPP);
348-
#elif defined(Q_OS_UNIX)
349-
static int normPrio = 0x7fff;
350-
if(normPrio == 0x7fff) {
351-
// get the normal priority level (assume we start there)
352-
errno = 0;
353-
normPrio = getpriority(PRIO_PROCESS, parpar.processId());
354-
if(normPrio == -1 && errno) {
355-
// failed to retrieve, disable option
356-
ui->btnBackground->setEnabled(false);
357-
ui->btnBackground->setChecked(false);
358-
return;
364+
if(!SetPriorityClass(hPP, isBackground ? IDLE_PRIORITY_CLASS : normPrio)) {
365+
ui->btnBackground->setChecked(!isBackground);
359366
}
360-
if(normPrio >= 19) {
361-
// already at low priority
362-
ui->btnBackground->setEnabled(false);
363-
ui->btnBackground->setChecked(true);
364-
return;
367+
CloseHandle(hPP);
368+
#elif defined(Q_OS_UNIX)
369+
static int normPrio = 0x7fff;
370+
if(normPrio == 0x7fff) {
371+
// get the normal priority level (assume we start there)
372+
errno = 0;
373+
normPrio = getpriority(PRIO_PROCESS, parpar.processId());
374+
if(normPrio == -1 && errno) {
375+
// failed to retrieve, disable option
376+
ui->btnBackground->setEnabled(false);
377+
ui->btnBackground->setChecked(false);
378+
return;
379+
}
380+
if(normPrio >= 19) {
381+
// already at low priority
382+
ui->btnBackground->setEnabled(false);
383+
ui->btnBackground->setChecked(true);
384+
return;
385+
}
365386
}
366-
}
367387

368-
if(setpriority(PRIO_PROCESS, parpar.processId(), isBackground ? 19 : normPrio)) {
369-
ui->btnBackground->setChecked(!isBackground);
370-
// TODO: it seems like you can't increase priority back to normal on Linux
371-
// TODO: if failed, the settings change is still persisted
372-
}
388+
if(setpriority(PRIO_PROCESS, parpar.processId(), isBackground ? 19 : normPrio)) {
389+
ui->btnBackground->setChecked(!isBackground);
390+
// TODO: it seems like you can't increase priority back to normal on Linux
391+
// TODO: if failed, the settings change is still persisted
392+
}
373393
#endif
394+
}
374395

375396
Settings::getInstance().setRunBackground(isBackground);
376397
}

0 commit comments

Comments
 (0)