Skip to content

Commit

Permalink
Merge branch 'release/2.1.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
guidotack committed Feb 6, 2017
2 parents 72d8998 + 9b71947 commit f156542
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 49 deletions.
10 changes: 10 additions & 0 deletions MiniZincIDE/CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
2017-02-06
v2.1.3
- Update to MiniZinc 2.1.3.
- Avoid crashes and print error messages when mzn2fzn subprocess crashes.
- Changed meaning of "User-defined behavior" options, to have a clear
distinction between optimisation and satisfaction problems.
- Fix buffering of error output from mzn2fzn process (which would sometimes
not be printed to the output window).
- Suppress output after configurable number of solutions (to avoid
overloading the IDE output box).
2016-12-20
v2.1.2
- Update to MiniZinc 2.1.2.
Expand Down
2 changes: 1 addition & 1 deletion MiniZincIDE/MiniZincIDE.pro
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ greaterThan(QT_MAJOR_VERSION, 4): {
TARGET = MiniZincIDE
TEMPLATE = app

VERSION = 2.1.2
VERSION = 2.1.3
DEFINES += MINIZINC_IDE_VERSION=\\\"$$VERSION\\\"

bundled {
Expand Down
136 changes: 100 additions & 36 deletions MiniZincIDE/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1190,7 +1190,7 @@ void MainWindow::closeEvent(QCloseEvent* e) {
}
if (process) {
disconnect(process, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(procError(QProcess::ProcessError)));
this, 0);
process->kill();
}
for (int i=0; i<ui->tabWidget->count(); i++) {
Expand Down Expand Up @@ -1374,21 +1374,37 @@ QStringList MainWindow::parseConf(bool compileOnly, bool useDataFile)
}
if (compileOnly && useDataFile && project.currentDataFile()!="None")
ret << "-d" << project.currentDataFile();
if (!compileOnly && project.defaultBehaviour()) {
bool isOptimisationProblem = true;
{
QFile fznFile(currentFznTarget);
if (fznFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
int seekSize = strlen("satisfy;\n\n");
if (fznFile.size() >= seekSize) {
fznFile.seek(fznFile.size()-seekSize);
QString line = fznFile.readLine();
if (!line.contains("satisfy;"))
if (line.contains("satisfy;"))
isOptimisationProblem = false;
}
}
}

if (!compileOnly) {
if (project.defaultBehaviour()) {
if (isOptimisationProblem)
ret << "-a";
} else {
if (isOptimisationProblem) {
if (project.printAll())
ret << "-a";
} else {
if (project.n_solutions() == 0)
ret << "-a";
else if (project.n_solutions() > 1)
ret << "-n" << QString::number(project.n_solutions());
}
}
} else {
if (!compileOnly && project.printAll())
ret << "-a";
}

if (!compileOnly && project.printStats())
ret << "-s";
if (!compileOnly && project.n_threads() > 1)
Expand All @@ -1400,8 +1416,6 @@ QStringList MainWindow::parseConf(bool compileOnly, bool useDataFile)
project.solverFlags().split(" ", QString::SkipEmptyParts);
ret << solverArgs;
}
if (!compileOnly && !project.defaultBehaviour() && project.n_solutions() != 1)
ret << "-n" << QString::number(project.n_solutions());
Solver s = solvers[ui->conf_solver->itemData(ui->conf_solver->currentIndex()).toInt()];
if (compileOnly && !s.mznlib.isEmpty())
ret << s.mznlib;
Expand Down Expand Up @@ -1445,9 +1459,9 @@ QString MainWindow::getMznDistribPath(void) const {
return mznDistribPath;
}

void MainWindow::checkArgsFinished(int exitcode)
void MainWindow::checkArgsFinished(int exitcode, QProcess::ExitStatus exitstatus)
{
if (processWasStopped)
if (processWasStopped || exitstatus==QProcess::CrashExit)
return;
QString additionalCmdlineParams;
QString additionalDataFile;
Expand Down Expand Up @@ -1499,14 +1513,15 @@ void MainWindow::checkArgs(QString filepath)
process->setWorkingDirectory(QFileInfo(filepath).absolutePath());
process->setProcessChannelMode(QProcess::MergedChannels);
connect(process, SIGNAL(readyRead()), this, SLOT(checkArgsOutput()));
connect(process, SIGNAL(finished(int)), this, SLOT(checkArgsFinished(int)));
connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(checkArgsFinished(int,QProcess::ExitStatus)));
connect(process, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(procError(QProcess::ProcessError)));
this, SLOT(checkArgsError(QProcess::ProcessError)));

QStringList args = parseConf(true, true);
args << "--instance-check-only" << "--output-to-stdout";
args << filepath;
compileErrors = "";
elapsedTime.start();
process->start(mzn2fzn_executable,args,getMznDistribPath());
}

Expand Down Expand Up @@ -1550,7 +1565,7 @@ void MainWindow::on_actionRun_triggered()
if (curEditor->filepath.endsWith(".fzn")) {
currentFznTarget = curEditor->filepath;
runSolns2Out = false;
runCompiledFzn(0);
runCompiledFzn(0,QProcess::NormalExit);
} else {
compileOnly = false;
checkArgs(curEditor->filepath);
Expand All @@ -1574,7 +1589,6 @@ QString MainWindow::setElapsedTime()
elapsed += QString().number(seconds)+"s";
if (hours==0 && minutes==0)
elapsed += " "+QString().number(msec)+"msec";

QString timeLimit;
if (project.timeLimit() > 0) {
timeLimit += " / ";
Expand Down Expand Up @@ -1632,6 +1646,19 @@ void MainWindow::readOutput()
}
JSONOutput.append(sl);
} else {
if (l.trimmed() == "----------") {
solutionCount++;
if ( solutionCount > solutionLimit || !hiddenSolutions.isEmpty()) {
if (hiddenSolutions.isEmpty()) {
solutionCount = 0;
if (!curJSONHandler || hadNonJSONOutput)
addOutput(l,false);
}
else
hiddenSolutions.back() += l;
hiddenSolutions.append("");
}
}
if (curJSONHandler > 0 && l.trimmed() == "----------") {
openJSONViewer();
JSONOutput.clear();
Expand All @@ -1645,7 +1672,26 @@ void MainWindow::readOutput()
} else {
if (outputBuffer)
(*outputBuffer) << l;
addOutput(l,false);
if (!hiddenSolutions.isEmpty()) {
if (l.trimmed() != "----------") {
hiddenSolutions.back() += l;
}
if (solutionCount == solutionLimit) {
addOutput("<div style='color:blue;'>[ "+QString().number(solutionLimit)+" more solutions ]</div><br>");
solutionCount = 0;
solutionLimit *= 2;
}
} else {
addOutput(l,false);
}
if (!hiddenSolutions.isEmpty() && l.trimmed() == "==========") {
if (solutionCount!=solutionLimit && solutionCount > 1) {
addOutput("<div style='color:blue;'>[ "+QString().number(solutionCount-1)+" more solutions ]</div><br>");
}
for (int i=hiddenSolutions.size()-2; i<hiddenSolutions.size(); i++) {
addOutput(hiddenSolutions[i], false);
}
}
hadNonJSONOutput = true;
}
}
Expand Down Expand Up @@ -1757,7 +1803,7 @@ void MainWindow::compileAndRun(const QString& modelPath, const QString& addition
} else if (standalone) {
connect(process, SIGNAL(finished(int)), this, SLOT(procFinished(int)));
} else {
connect(process, SIGNAL(finished(int)), this, SLOT(runCompiledFzn(int)));
connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(runCompiledFzn(int,QProcess::ExitStatus)));
}
connect(process, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(procError(QProcess::ProcessError)));
Expand Down Expand Up @@ -1802,10 +1848,10 @@ void MainWindow::compileAndRun(const QString& modelPath, const QString& addition
compiling += ", additional arguments " + additionalCmdlineParams;
}
addOutput("<div style='color:blue;'>"+compiling+"</div><br>");
process->start(processName,args,getMznDistribPath());
time = 0;
timer->start(500);
elapsedTime.start();
process->start(processName,args,getMznDistribPath());
}
}

Expand Down Expand Up @@ -1859,11 +1905,6 @@ void MainWindow::selectJSONSolution(HTMLPage* source, int n)
}
}

void MainWindow::pipeOutput()
{
outputProcess->write(process->readAllStandardOutput());
}

void MainWindow::outputProcFinished(int, bool showTime) {
readOutput();
updateUiProcessRunning(false);
Expand All @@ -1887,8 +1928,6 @@ void MainWindow::outputProcFinished(int, bool showTime) {
void MainWindow::procFinished(int, bool showTime) {
if (outputProcess) {
connect(outputProcess, SIGNAL(finished(int)), this, SLOT(outputProcFinished(int)));
if (process)
pipeOutput();
outputProcess->closeWriteChannel();
return;
}
Expand All @@ -1903,25 +1942,42 @@ void MainWindow::procFinished(int, bool showTime) {
delete tmpDir;
tmpDir = NULL;
outputBuffer = NULL;
compileErrors = "";
emit(finished());
}

void MainWindow::procError(QProcess::ProcessError e) {
if (!compileErrors.isEmpty()) {
addOutput(compileErrors,false);
}
procFinished(1);
if (e==QProcess::FailedToStart) {
QMessageBox::critical(this, "MiniZinc IDE", "Failed to start '"+processName+"'. Check your path settings.");
} else {
QMessageBox::critical(this, "MiniZinc IDE", "Unknown error while executing the MiniZinc interpreter `"+processName+"': error code "+QString().number(e));
}
}

void MainWindow::checkArgsError(QProcess::ProcessError e) {
checkArgsOutput();
if (!compileErrors.isEmpty()) {
addOutput(compileErrors,false);
}
procFinished(1);
if (e==QProcess::FailedToStart) {
QMessageBox::critical(this, "MiniZinc IDE", "Failed to start '"+processName+"'. Check your path settings.");
} else {
QMessageBox::critical(this, "MiniZinc IDE", "Unknown error while executing the MiniZinc interpreter `"+processName+"': error code "+QString().number(e));
}
procFinished(0);
}

void MainWindow::outputProcError(QProcess::ProcessError e) {
procFinished(1);
if (e==QProcess::FailedToStart) {
QMessageBox::critical(this, "MiniZinc IDE", "Failed to start 'solns2out'. Check your path settings.");
} else {
QMessageBox::critical(this, "MiniZinc IDE", "Unknown error while executing the MiniZinc solution processor.");
}
procFinished(0);
}

void MainWindow::saveFile(CodeEditor* ce, const QString& f)
Expand Down Expand Up @@ -2023,11 +2079,9 @@ void MainWindow::on_actionStop_triggered()
{
ui->actionStop->setEnabled(false);
if (process) {
if (outputProcess)
pipeOutput();
disconnect(process, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(procError(QProcess::ProcessError)));
disconnect(process, SIGNAL(finished(int)), this, SLOT(procFinished(int)));
this, 0);
disconnect(process, SIGNAL(finished(int)), this, 0);
processWasStopped = true;

#ifdef Q_OS_WIN
Expand Down Expand Up @@ -2097,11 +2151,11 @@ void MainWindow::openCompiledFzn(int exitcode)
procFinished(exitcode);
}

void MainWindow::runCompiledFzn(int exitcode)
void MainWindow::runCompiledFzn(int exitcode, QProcess::ExitStatus exitstatus)
{
if (processWasStopped)
return;
if (exitcode==0) {
if (exitcode==0 && exitstatus==QProcess::NormalExit) {
readOutput();
QStringList args = parseConf(false,true);
Solver s = solvers[ui->conf_solver->itemData(ui->conf_solver->currentIndex()).toInt()];
Expand Down Expand Up @@ -2135,6 +2189,9 @@ void MainWindow::runCompiledFzn(int exitcode)
tmpDir = NULL;
procFinished(exitcode);
} else {
solutionCount = 0;
solutionLimit = project.defaultBehaviour() ? 100 : project.n_compress_solutions();
hiddenSolutions.clear();
if (runSolns2Out) {
outputProcess = new MznProcess(this);
inJSONHandler = false;
Expand All @@ -2151,16 +2208,13 @@ void MainWindow::runCompiledFzn(int exitcode)
connect(outputProcess, SIGNAL(readyReadStandardError()), this, SLOT(readOutput()));
connect(outputProcess, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(outputProcError(QProcess::ProcessError)));
QStringList outargs;
outargs << currentFznTarget.left(currentFznTarget.length()-4)+".ozn";
outputProcess->start("solns2out",outargs,getMznDistribPath());
}
process = new MznProcess(this);
processName = s.executable;
processWasStopped = false;
process->setWorkingDirectory(QFileInfo(curFilePath).absolutePath());
if (runSolns2Out) {
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(pipeOutput()));
process->setStandardOutputProcess(outputProcess);
} else {
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
}
Expand Down Expand Up @@ -2190,6 +2244,11 @@ void MainWindow::runCompiledFzn(int exitcode)
addOutput("<div>"+cmdline+"</div><br>");
}
process->start(executable,args,getMznDistribPath());
if (runSolns2Out) {
QStringList outargs;
outargs << currentFznTarget.left(currentFznTarget.length()-4)+".ozn";
outputProcess->start("solns2out",outargs,getMznDistribPath());
}
time = 0;
timer->start(500);
}
Expand Down Expand Up @@ -2635,6 +2694,7 @@ void MainWindow::saveProject(const QString& f)
out << projectFilesRelPath;
out << project.defaultBehaviour();
out << project.mzn2fznPrintStats();
out << project.n_compress_solutions();
project.setModified(false, true);

} else {
Expand Down Expand Up @@ -2745,6 +2805,10 @@ void MainWindow::loadProject(const QString& filepath)
in >> p_b;
project.mzn2fznPrintStats(p_b, true);
}
if (version==104 && !in.atEnd()) {
in >> p_i;
project.n_compress_solutions(p_i, true);
}
for (int i=0; i<projectFilesRelPath.size(); i++) {
QFileInfo fi(basePath+projectFilesRelPath[i]);
if (fi.exists()) {
Expand Down
11 changes: 7 additions & 4 deletions MiniZincIDE/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,16 @@ private slots:

void checkArgs(QString filepath);
void checkArgsOutput();
void checkArgsFinished(int exitcode);
void checkArgsFinished(int exitcode, QProcess::ExitStatus exitstatus);

void readOutput();

void pipeOutput();

void procFinished(int, bool showTime=true);

void outputProcFinished(int, bool showTime=true);

void procError(QProcess::ProcessError);
void checkArgsError(QProcess::ProcessError);
void outputProcError(QProcess::ProcessError);

void on_actionSave_triggered();
Expand All @@ -179,7 +178,7 @@ private slots:

void openCompiledFzn(int);

void runCompiledFzn(int);
void runCompiledFzn(int,QProcess::ExitStatus);

void on_actionSave_as_triggered();

Expand Down Expand Up @@ -303,6 +302,10 @@ private slots:
QString processName;
MznProcess* outputProcess;
bool processWasStopped;
int solutionCount;
int solutionLimit;
QTimer solutionLimitTimer;
QVector<QString> hiddenSolutions;
int curJSONHandler;
bool inJSONHandler;
bool hadNonJSONOutput;
Expand Down
Loading

0 comments on commit f156542

Please sign in to comment.