diff --git a/MiniZincIDE/mainwindow.cpp b/MiniZincIDE/mainwindow.cpp index e8ac8af..932ff85 100644 --- a/MiniZincIDE/mainwindow.cpp +++ b/MiniZincIDE/mainwindow.cpp @@ -3085,17 +3085,19 @@ void MainWindow::startVisualisation(const QString& model, const QStringList& dat QSettings settings; settings.beginGroup("ide"); bool reuseVis = settings.value("reuseVis", false).toBool(); - int port = settings.value("visPort", 3000).toInt(); + int httpPort = settings.value("visPort", 3000).toInt(); + int wsPort = settings.value("visWsPort", 3100).toInt(); bool printUrl = settings.value("printVisUrl", false).toBool(); settings.endGroup(); - if (server == nullptr || server->desiredPort() != port) { - try { - server = new Server(port, this); - } catch (ServerError& e) { - QMessageBox::warning(this, "MiniZinc IDE", e.message(), QMessageBox::Ok); - return; - } + if (server == nullptr) { + server = new Server(this); + } + try { + server->listen(httpPort, wsPort); + } catch (ServerError& e) { + QMessageBox::warning(this, "MiniZinc IDE", e.message(), QMessageBox::Ok); + return; } QFileInfo modelFileInfo(model); diff --git a/MiniZincIDE/preferencesdialog.cpp b/MiniZincIDE/preferencesdialog.cpp index 50e25ab..8380bfb 100644 --- a/MiniZincIDE/preferencesdialog.cpp +++ b/MiniZincIDE/preferencesdialog.cpp @@ -72,6 +72,7 @@ PreferencesDialog::PreferencesDialog(bool addNewSolver, QWidget *parent) : } ui->reuseVis_checkBox->setChecked(settings.value("reuseVis", false).toBool()); ui->visPort_spinBox->setValue(settings.value("visPort", 3000).toInt()); + ui->visWsPort_spinBox->setValue(settings.value("visWsPort", 3100).toInt()); ui->visUrl_checkBox->setChecked(settings.value("printVisUrl", false).toBool()); ui->printCommand_checkBox->setChecked(settings.value("printCommand", false).toBool()); ui->indentSize_spinBox->setValue(settings.value("indentSize", 2).toInt()); @@ -919,6 +920,7 @@ void PreferencesDialog::on_PreferencesDialog_accepted() settings.setValue("printCommand", ui->printCommand_checkBox->isChecked()); settings.setValue("reuseVis", ui->reuseVis_checkBox->isChecked()); settings.setValue("visPort", ui->visPort_spinBox->value()); + settings.setValue("visWsPort", ui->visWsPort_spinBox->value()); settings.setValue("printVisUrl", ui->visUrl_checkBox->isChecked()); settings.setValue("theme", ui->theme_comboBox->currentIndex()); settings.setValue("indentTabs", ui->indentTabs_radioButton->isChecked()); diff --git a/MiniZincIDE/preferencesdialog.ui b/MiniZincIDE/preferencesdialog.ui index b712f84..6d9239c 100644 --- a/MiniZincIDE/preferencesdialog.ui +++ b/MiniZincIDE/preferencesdialog.ui @@ -794,34 +794,52 @@ Visualisation - - - - - Reuse existing visualisation window when starting a new run - - - - - - - Start the visualisation server on this port (0 for auto): - - - - - - - 65535 - - - - - - - Print the visualisation server URL in the output window - - + + + + + + + Reuse existing visualisation window when starting a new run + + + + + + + HTTP server port (0 for auto): + + + + + + + 65535 + + + + + + + WebSocket server port (0 for auto): + + + + + + + 65535 + + + + + + + Print the visualisation server URL in the output window + + + + diff --git a/MiniZincIDE/server.cpp b/MiniZincIDE/server.cpp index caf4eb9..441c23c 100644 --- a/MiniZincIDE/server.cpp +++ b/MiniZincIDE/server.cpp @@ -178,26 +178,11 @@ void VisConnector::webSocketMessageReceived(const QString& message) } } -Server::Server(quint16 port, QObject *parent) : +Server::Server(QObject *parent) : QObject(parent), http(new QTcpServer(this)), ws(new QWebSocketServer("MiniZincIDE", QWebSocketServer::NonSecureMode, this)) { - initialPort = port; - qint16 p = port; - for (int i = 0; i < 10; i++) { - if (http->listen(QHostAddress::LocalHost, p) || p == 0) { - break; - } - p++; - } - if (!http->isListening()) { - throw ServerError("Failed to start HTTP visualisation server"); - } - if (!ws->listen(QHostAddress::LocalHost)) { - throw ServerError("Failed to start WebSocket visualisation server"); - } - connect(http, &QTcpServer::newConnection, this, &Server::newHttpClient); connect(ws, &QWebSocketServer::newConnection, this, &Server::newWebSocketClient); } @@ -209,6 +194,39 @@ Server::~Server() } } +void Server::listen(quint16 httpPort, quint16 wsPort) +{ + if (!http->isListening() || httpPort != initialHttpPort) { + initialHttpPort = httpPort; + qint16 p = httpPort; + http->close(); + for (int i = 0; i < 10; i++) { + if (http->listen(QHostAddress::LocalHost, p) || p == 0) { + break; + } + p++; + } + if (!http->isListening()) { + throw ServerError("Failed to start HTTP visualisation server"); + } + } + + if (!ws->isListening() || wsPort != initialWsPort) { + initialWsPort = wsPort; + quint16 p = wsPort; + ws->close(); + for (int i = 0; i < 10; i++) { + if (ws->listen(QHostAddress::LocalHost, p) || p == 0) { + break; + } + p++; + } + if (!ws->isListening()) { + throw ServerError("Failed to start WebSocket visualisation server"); + } + } +} + VisConnector* Server::addConnector(const QString& label, const QStringList& roots) { auto* c = new VisConnector(this); diff --git a/MiniZincIDE/server.h b/MiniZincIDE/server.h index 9c08001..49711a3 100644 --- a/MiniZincIDE/server.h +++ b/MiniZincIDE/server.h @@ -53,11 +53,15 @@ class Server : public QObject { Q_OBJECT public: - explicit Server(quint16 port = 3000, QObject *parent = nullptr); + explicit Server(QObject *parent = nullptr); ~Server(); + + void listen(quint16 httpPort = 3000, quint16 wsPort = 3100); + QString address() const { return http->serverAddress().toString(); } quint16 port() const { return http->serverPort(); } - quint16 desiredPort() const { return initialPort; } + quint16 desiredHttpPort() const { return initialHttpPort; } + quint16 desiredWsPort() const { return initialWsPort; } VisConnector* addConnector(const QString& label, const QStringList& roots); void clear(); @@ -78,7 +82,8 @@ private slots: QWebSocketServer* ws; QList connectors; QList clients; - quint16 initialPort; + quint16 initialHttpPort; + quint16 initialWsPort; }; #endif // SERVER_H