diff --git a/qt/i2pd_qt/ClientTunnelPane.cpp b/qt/i2pd_qt/ClientTunnelPane.cpp index 537abb1c..256d0510 100644 --- a/qt/i2pd_qt/ClientTunnelPane.cpp +++ b/qt/i2pd_qt/ClientTunnelPane.cpp @@ -3,14 +3,15 @@ #include "SignatureTypeComboboxFactory.h" #include "QVBoxLayout" -ClientTunnelPane::ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf): - TunnelPane(tunnelsPageUpdateListener, tunconf) {} +ClientTunnelPane::ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow): + TunnelPane(tunnelsPageUpdateListener, tunconf, wrongInputPane_, wrongInputLabel_, mainWindow) {} void ClientTunnelPane::setGroupBoxTitle(const QString & title) { clientTunnelNameGroupBox->setTitle(title); } void ClientTunnelPane::deleteClientTunnelForm() { + TunnelPane::deleteTunnelForm(); delete clientTunnelNameGroupBox; clientTunnelNameGroupBox=nullptr; diff --git a/qt/i2pd_qt/ClientTunnelPane.h b/qt/i2pd_qt/ClientTunnelPane.h index 511209e5..c2e076b7 100644 --- a/qt/i2pd_qt/ClientTunnelPane.h +++ b/qt/i2pd_qt/ClientTunnelPane.h @@ -14,7 +14,7 @@ class TunnelPane; class ClientTunnelPane : public TunnelPane { Q_OBJECT public: - ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf); + ClientTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ClientTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow); virtual ~ClientTunnelPane(){} virtual ServerTunnelPane* asServerTunnelPane(); virtual ClientTunnelPane* asClientTunnelPane(); @@ -68,6 +68,7 @@ private: } protected: virtual bool applyDataFromUIToTunnelConfig() { + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); bool ok=TunnelPane::applyDataFromUIToTunnelConfig(); if(!ok)return false; ClientTunnelConfig* ctc=tunnelConfig->asClientTunnelConfig(); @@ -78,7 +79,11 @@ protected: auto portStr=portLineEdit->text(); int portInt=portStr.toInt(&ok); - if(!ok)return false; + + if(!ok){ + highlightWrongInput(QApplication::tr("Bad port, must be int.")+" "+cannotSaveSettings,portLineEdit); + return false; + } ctc->setport(portInt); ctc->setkeys(keysLineEdit->text().toStdString()); @@ -87,7 +92,10 @@ protected: auto dportStr=destinationPortLineEdit->text(); int dportInt=dportStr.toInt(&ok); - if(!ok)return false; + if(!ok){ + highlightWrongInput(QApplication::tr("Bad destinationPort, must be int.")+" "+cannotSaveSettings,destinationPortLineEdit); + return false; + } ctc->setdestinationPort(dportInt); ctc->setsigType(readSigTypeComboboxUI(sigTypeComboBox)); diff --git a/qt/i2pd_qt/ServerTunnelPane.cpp b/qt/i2pd_qt/ServerTunnelPane.cpp index cc024386..029a3ea2 100644 --- a/qt/i2pd_qt/ServerTunnelPane.cpp +++ b/qt/i2pd_qt/ServerTunnelPane.cpp @@ -2,8 +2,8 @@ #include "ClientContext.h" #include "SignatureTypeComboboxFactory.h" -ServerTunnelPane::ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf): - TunnelPane(tunnelsPageUpdateListener, tunconf) {} +ServerTunnelPane::ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow): + TunnelPane(tunnelsPageUpdateListener, tunconf, wrongInputPane_, wrongInputLabel_, mainWindow) {} void ServerTunnelPane::setGroupBoxTitle(const QString & title) { serverTunnelNameGroupBox->setTitle(title); @@ -266,6 +266,7 @@ int ServerTunnelPane::appendServerTunnelForm( } void ServerTunnelPane::deleteServerTunnelForm() { + TunnelPane::deleteTunnelForm(); delete serverTunnelNameGroupBox;//->deleteLater(); serverTunnelNameGroupBox=nullptr; diff --git a/qt/i2pd_qt/ServerTunnelPane.h b/qt/i2pd_qt/ServerTunnelPane.h index 4069e339..556c8473 100644 --- a/qt/i2pd_qt/ServerTunnelPane.h +++ b/qt/i2pd_qt/ServerTunnelPane.h @@ -1,9 +1,6 @@ #ifndef SERVERTUNNELPANE_H #define SERVERTUNNELPANE_H -#include "TunnelPane.h" -#include "TunnelsPageUpdateListener.h" - #include #include #include @@ -23,6 +20,9 @@ #include "assert.h" +#include "TunnelPane.h" +#include "TunnelsPageUpdateListener.h" + class ServerTunnelConfig; class ClientTunnelPane; @@ -31,7 +31,7 @@ class ServerTunnelPane : public TunnelPane { Q_OBJECT public: - ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf); + ServerTunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener, ServerTunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow); virtual ~ServerTunnelPane(){} virtual ServerTunnelPane* asServerTunnelPane(); @@ -119,6 +119,7 @@ private: protected: virtual bool applyDataFromUIToTunnelConfig() { + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); bool ok=TunnelPane::applyDataFromUIToTunnelConfig(); if(!ok)return false; ServerTunnelConfig* stc=tunnelConfig->asServerTunnelConfig(); @@ -127,14 +128,20 @@ protected: auto portStr=portLineEdit->text(); int portInt=portStr.toInt(&ok); - if(!ok)return false; + if(!ok){ + highlightWrongInput(QApplication::tr("Bad port, must be int.")+" "+cannotSaveSettings,portLineEdit); + return false; + } stc->setport(portInt); stc->setkeys(keysLineEdit->text().toStdString()); auto str=inPortLineEdit->text(); int inPortInt=str.toInt(&ok); - if(!ok)return false; + if(!ok){ + highlightWrongInput(QApplication::tr("Bad inPort, must be int.")+" "+cannotSaveSettings,inPortLineEdit); + return false; + } stc->setinPort(inPortInt); stc->setaccessList(accessListLineEdit->text().toStdString()); @@ -147,7 +154,10 @@ protected: auto mcStr=maxConnsLineEdit->text(); uint32_t mcInt=(uint32_t)mcStr.toInt(&ok); - if(!ok)return false; + if(!ok){ + highlightWrongInput(QApplication::tr("Bad maxConns, must be int.")+" "+cannotSaveSettings,maxConnsLineEdit); + return false; + } stc->setmaxConns(mcInt); stc->setgzip(gzipCheckBox->isChecked()); diff --git a/qt/i2pd_qt/TunnelConfig.cpp b/qt/i2pd_qt/TunnelConfig.cpp index 8cf86d14..81216c0b 100644 --- a/qt/i2pd_qt/TunnelConfig.cpp +++ b/qt/i2pd_qt/TunnelConfig.cpp @@ -6,24 +6,24 @@ void TunnelConfig::saveHeaderToStringStream(std::stringstream& out) { } void TunnelConfig::saveI2CPParametersToStringStream(std::stringstream& out) { - if (i2cpParameters.getInbound_length().toUShort() != i2p::client::DEFAULT_INBOUND_TUNNEL_LENGTH) - out << i2p::client::I2CP_PARAM_INBOUND_TUNNEL_LENGTH << "=" - << i2cpParameters.getInbound_length().toStdString() << "\n"; - if (i2cpParameters.getOutbound_length().toUShort() != i2p::client::DEFAULT_OUTBOUND_TUNNEL_LENGTH) - out << i2p::client::I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH << "=" - << i2cpParameters.getOutbound_length().toStdString() << "\n"; - if (i2cpParameters.getInbound_quantity().toUShort() != i2p::client::DEFAULT_INBOUND_TUNNELS_QUANTITY) - out << i2p::client::I2CP_PARAM_INBOUND_TUNNELS_QUANTITY << "=" - << i2cpParameters.getInbound_quantity().toStdString() << "\n"; - if (i2cpParameters.getOutbound_quantity().toUShort() != i2p::client::DEFAULT_OUTBOUND_TUNNELS_QUANTITY) - out << i2p::client::I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY << "=" - << i2cpParameters.getOutbound_quantity().toStdString() << "\n"; - if (i2cpParameters.getCrypto_tagsToSend().toUShort() != i2p::client::DEFAULT_TAGS_TO_SEND) - out << i2p::client::I2CP_PARAM_TAGS_TO_SEND << "=" - << i2cpParameters.getCrypto_tagsToSend().toStdString() << "\n"; - if (!i2cpParameters.getExplicitPeers().isEmpty()) - out << i2p::client::I2CP_PARAM_EXPLICIT_PEERS << "=" - << i2cpParameters.getExplicitPeers().toStdString() << "\n"; + if (i2cpParameters.getInbound_length().toUShort() != i2p::client::DEFAULT_INBOUND_TUNNEL_LENGTH) + out << i2p::client::I2CP_PARAM_INBOUND_TUNNEL_LENGTH << "=" + << i2cpParameters.getInbound_length().toStdString() << "\n"; + if (i2cpParameters.getOutbound_length().toUShort() != i2p::client::DEFAULT_OUTBOUND_TUNNEL_LENGTH) + out << i2p::client::I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH << "=" + << i2cpParameters.getOutbound_length().toStdString() << "\n"; + if (i2cpParameters.getInbound_quantity().toUShort() != i2p::client::DEFAULT_INBOUND_TUNNELS_QUANTITY) + out << i2p::client::I2CP_PARAM_INBOUND_TUNNELS_QUANTITY << "=" + << i2cpParameters.getInbound_quantity().toStdString() << "\n"; + if (i2cpParameters.getOutbound_quantity().toUShort() != i2p::client::DEFAULT_OUTBOUND_TUNNELS_QUANTITY) + out << i2p::client::I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY << "=" + << i2cpParameters.getOutbound_quantity().toStdString() << "\n"; + if (i2cpParameters.getCrypto_tagsToSend().toUShort() != i2p::client::DEFAULT_TAGS_TO_SEND) + out << i2p::client::I2CP_PARAM_TAGS_TO_SEND << "=" + << i2cpParameters.getCrypto_tagsToSend().toStdString() << "\n"; + if (!i2cpParameters.getExplicitPeers().isEmpty()) //todo #947 + out << i2p::client::I2CP_PARAM_EXPLICIT_PEERS << "=" + << i2cpParameters.getExplicitPeers().toStdString() << "\n"; out << "\n"; } diff --git a/qt/i2pd_qt/TunnelPane.cpp b/qt/i2pd_qt/TunnelPane.cpp index 84e8aed0..48adcf78 100644 --- a/qt/i2pd_qt/TunnelPane.cpp +++ b/qt/i2pd_qt/TunnelPane.cpp @@ -1,8 +1,13 @@ #include "TunnelPane.h" + #include "QMessageBox" +#include "mainwindow.h" -TunnelPane::TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunnelConfig_): +TunnelPane::TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunnelConfig_, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow_): QObject(), + mainWindow(mainWindow_), + wrongInputPane(wrongInputPane_), + wrongInputLabel(wrongInputLabel_), tunnelConfig(tunnelConfig_), tunnelsPageUpdateListener(tunnelsPageUpdateListener_), gridLayoutWidget_2(nullptr) {} @@ -179,7 +184,7 @@ void TunnelPane::appendControlsForI2CPParameters(I2CPParameters& i2cpParameters, void TunnelPane::updated() { std::string oldName=tunnelConfig->getName(); - if(!applyDataFromUIToTunnelConfig())return;//TODO visualise bad input + if(!applyDataFromUIToTunnelConfig())return; tunnelsPageUpdateListener->updated(oldName, tunnelConfig); } @@ -218,3 +223,14 @@ QString TunnelPane::readTunnelTypeComboboxData() { i2p::data::SigningKeyType TunnelPane::readSigTypeComboboxUI(QComboBox* sigTypeComboBox) { return (i2p::data::SigningKeyType) sigTypeComboBox->currentData().toInt(); } + +void TunnelPane::deleteTunnelForm() { + widgetlocks.deleteListeners(); +} + +void TunnelPane::highlightWrongInput(QString warningText, QWidget* controlWithWrongInput) { + wrongInputPane->setVisible(true); + wrongInputLabel->setText(warningText); + if(controlWithWrongInput)controlWithWrongInput->setFocus(); + mainWindow->showTunnelsPage(); +} diff --git a/qt/i2pd_qt/TunnelPane.h b/qt/i2pd_qt/TunnelPane.h index f306e9dc..3a647635 100644 --- a/qt/i2pd_qt/TunnelPane.h +++ b/qt/i2pd_qt/TunnelPane.h @@ -23,18 +23,28 @@ class ClientTunnelPane; class TunnelConfig; class I2CPParameters; +class MainWindow; + class TunnelPane : public QObject { Q_OBJECT public: - TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunconf); + TunnelPane(TunnelsPageUpdateListener* tunnelsPageUpdateListener_, TunnelConfig* tunconf, QWidget* wrongInputPane_, QLabel* wrongInputLabel_, MainWindow* mainWindow_); virtual ~TunnelPane(){} + void deleteTunnelForm(); + + void hideWrongInputLabel() const { wrongInputPane->setVisible(false); } + void highlightWrongInput(QString warningText, QWidget* controlWithWrongInput); + virtual ServerTunnelPane* asServerTunnelPane()=0; virtual ClientTunnelPane* asClientTunnelPane()=0; protected: + MainWindow* mainWindow; + QWidget * wrongInputPane; + QLabel* wrongInputLabel; TunnelConfig* tunnelConfig; widgetlockregistry widgetlocks; TunnelsPageUpdateListener* tunnelsPageUpdateListener; @@ -82,8 +92,10 @@ protected: //should be created by factory i2p::data::SigningKeyType readSigTypeComboboxUI(QComboBox* sigTypeComboBox); +public: //returns false when invalid data at UI virtual bool applyDataFromUIToTunnelConfig() { + hideWrongInputLabel(); tunnelConfig->setName(nameLineEdit->text().toStdString()); tunnelConfig->setType(readTunnelTypeComboboxData()); I2CPParameters& i2cpParams=tunnelConfig->getI2cpParameters(); @@ -94,7 +106,7 @@ protected: i2cpParams.setCrypto_tagsToSend(crypto_tagsToSendLineEdit->text()); return true; } - +protected: void setupTunnelPane( TunnelConfig* tunnelConfig, QGroupBox *tunnelGroupBox, diff --git a/qt/i2pd_qt/generalsettingswidget.ui b/qt/i2pd_qt/generalsettingswidget.ui index 6af16ecf..a7f07e5d 100644 --- a/qt/i2pd_qt/generalsettingswidget.ui +++ b/qt/i2pd_qt/generalsettingswidget.ui @@ -929,7 +929,7 @@ - Port (leave empty to auto-assign): + Port (leave 0 to auto-assign): @@ -1500,7 +1500,7 @@ - Bandwidth limit (integer): + Bandwidth limit (integer or a letter): diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index 71d7dca7..7f9810cc 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -82,6 +82,11 @@ MainWindow::MainWindow(QWidget *parent) : ui->settingsContents->setAutoFillBackground(true); ui->settingsContents->setPalette(pal); */ + QPalette pal(palette()); + pal.setColor(QPalette::Background, Qt::red); + ui->wrongInputLabel->setAutoFillBackground(true); + ui->wrongInputLabel->setPalette(pal); + ui->wrongInputLabel->setVisible(false); #ifndef ANDROID createActions(); @@ -565,7 +570,7 @@ void MainWindow::initUInt16Box(ConfigOption option, QLineEdit* numberLineEdit, Q configItems.append(new UInt16StringItem(option, numberLineEdit, fieldNameTranslated)); } void MainWindow::initStringBox(ConfigOption option, QLineEdit* lineEdit){ - configItems.append(new BaseStringItem(option, lineEdit)); + configItems.append(new BaseStringItem(option, lineEdit, QString())); } NonGUIOptionItem* MainWindow::initNonGUIOption(ConfigOption option) { NonGUIOptionItem * retValue; @@ -623,6 +628,9 @@ void MainWindow::loadAllConfigs(){ } /** returns false iff not valid items present and save was aborted */ bool MainWindow::saveAllConfigs(){ + QString cannotSaveSettings = QApplication::tr("Cannot save settings."); + ui->wrongInputLabel->setVisible(false); + programOptionsWriterCurrentSection=""; /*if(!logFileNameOption->lineEdit->text().trimmed().isEmpty())logOption->optionValue=boost::any(std::string("file")); else logOption->optionValue=boost::any(std::string("stdout"));*/ @@ -632,7 +640,10 @@ bool MainWindow::saveAllConfigs(){ std::stringstream out; for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { MainWindowItem* item = *it; - if(!item->isValid()) return false; + if(!item->isValid()){ + highlightWrongInput(QApplication::tr("Invalid value for")+" "+item->getConfigOption().section+"::"+item->getConfigOption().option+". "+item->getRequirementToBeValid()+" "+cannotSaveSettings, item->getWidgetToFocus()); + return false; + } } for(QList::iterator it = configItems.begin(); it!= configItems.end(); ++it) { @@ -688,27 +699,33 @@ void MainWindow::appendTunnelForms(std::string tunnelNameToFocus) { TunnelConfig* tunconf = it->second; ServerTunnelConfig* stc = tunconf->asServerTunnelConfig(); if(stc){ - ServerTunnelPane * tunnelPane=new ServerTunnelPane(&tunnelsPageUpdateListener, stc); + ServerTunnelPane * tunnelPane=new ServerTunnelPane(&tunnelsPageUpdateListener, stc, ui->wrongInputLabel, ui->wrongInputLabel, this); int h=tunnelPane->appendServerTunnelForm(stc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); height+=h; - qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + //qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); tunnelPanes.push_back(tunnelPane); - if(name==tunnelNameToFocus)tunnelPane->getNameLineEdit()->setFocus(); + if(name==tunnelNameToFocus){ + tunnelPane->getNameLineEdit()->setFocus(); + //todo ui->settingsScrollArea->###scroll + } continue; } ClientTunnelConfig* ctc = tunconf->asClientTunnelConfig(); if(ctc){ - ClientTunnelPane * tunnelPane=new ClientTunnelPane(&tunnelsPageUpdateListener, ctc); + ClientTunnelPane * tunnelPane=new ClientTunnelPane(&tunnelsPageUpdateListener, ctc, ui->wrongInputLabel, ui->wrongInputLabel, this); int h=tunnelPane->appendClientTunnelForm(ctc, ui->tunnelsScrollAreaWidgetContents, tunnelPanes.size(), height); height+=h; - qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); + //qDebug() << "tun.height:" << height << "sz:" << tunnelPanes.size(); tunnelPanes.push_back(tunnelPane); - if(name==tunnelNameToFocus)tunnelPane->getNameLineEdit()->setFocus(); + if(name==tunnelNameToFocus){ + tunnelPane->getNameLineEdit()->setFocus(); + //todo ui->settingsScrollArea->###scroll + } continue; } throw "unknown TunnelConfig subtype"; } - qDebug() << "tun.setting height:" << height; + //qDebug() << "tun.setting height:" << height; ui->tunnelsScrollAreaWidgetContents->setGeometry(QRect(0, 0, 621, height)); QList childWidgets = ui->tunnelsScrollAreaWidgetContents->findChildren(); foreach(QWidget* widget, childWidgets) @@ -748,6 +765,15 @@ void MainWindow::reloadTunnelsConfigAndUI(std::string tunnelNameToFocus) { void MainWindow::SaveTunnelsConfig() { std::stringstream out; + //validate and show red if wrong + for (std::list::iterator it=tunnelPanes.begin(); it!=tunnelPanes.end(); ++it) { + TunnelPane* tunpane = *it; + if(!tunpane->applyDataFromUIToTunnelConfig()) { + //!valid + return; + } + } + for (std::map::iterator it=tunnelConfigs.begin(); it!=tunnelConfigs.end(); ++it) { const std::string& name = it->first; TunnelConfig* tunconf = it->second; @@ -777,7 +803,7 @@ void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::updated(std::string ol if(it!=mainWindow->tunnelConfigs.end())mainWindow->tunnelConfigs.erase(it); mainWindow->tunnelConfigs[tunConf->getName()]=tunConf; } - mainWindow->SaveTunnelsConfig(); + mainWindow->saveAllConfigs(); } void MainWindow::TunnelsPageUpdateListenerMainWindowImpl::needsDeleting(std::string oldName){ @@ -833,3 +859,10 @@ void MainWindow::anchorClickedHandler(const QUrl & link) { void MainWindow::backClickedFromChild() { showStatusPage(statusPage); } + +void MainWindow::highlightWrongInput(QString warningText, QWidget* widgetToFocus) { + ui->wrongInputLabel->setVisible(true); + ui->wrongInputLabel->setText(warningText); + if(widgetToFocus)widgetToFocus->setFocus(); + showSettingsPage(); +} diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index c0286d03..831ce7b5 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -93,8 +93,13 @@ class MainWindow; class MainWindowItem : public QObject { Q_OBJECT ConfigOption option; + QWidget* widgetToFocus; + QString requirementToBeValid; public: - MainWindowItem(ConfigOption option_) : option(option_) {} + MainWindowItem(ConfigOption option_, QWidget* widgetToFocus_, QString requirementToBeValid_) : option(option_), widgetToFocus(widgetToFocus_), requirementToBeValid(requirementToBeValid_) {} + QWidget* getWidgetToFocus(){return widgetToFocus;} + QString& getRequirementToBeValid() { return requirementToBeValid; } + ConfigOption& getConfigOption() { return option; } boost::any optionValue; virtual ~MainWindowItem(){} virtual void installListeners(MainWindow *mainWindow); @@ -145,7 +150,7 @@ public: }; class NonGUIOptionItem : public MainWindowItem { public: - NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_) {}; + NonGUIOptionItem(ConfigOption option_) : MainWindowItem(option_, nullptr, QString()) {}; virtual ~NonGUIOptionItem(){} virtual bool isValid() { return true; } }; @@ -153,7 +158,7 @@ class BaseStringItem : public MainWindowItem { Q_OBJECT public: QLineEdit* lineEdit; - BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_) : MainWindowItem(option_), lineEdit(lineEdit_){}; + BaseStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString requirementToBeValid_) : MainWindowItem(option_, lineEdit_, requirementToBeValid_), lineEdit(lineEdit_){}; virtual ~BaseStringItem(){} virtual void installListeners(MainWindow *mainWindow); virtual QString toString(){ @@ -175,7 +180,7 @@ class FileOrFolderChooserItem : public BaseStringItem { public: QPushButton* browsePushButton; FileOrFolderChooserItem(ConfigOption option_, QLineEdit* lineEdit_, QPushButton* browsePushButton_) : - BaseStringItem(option_, lineEdit_), browsePushButton(browsePushButton_) {} + BaseStringItem(option_, lineEdit_, QString()), browsePushButton(browsePushButton_) {} virtual ~FileOrFolderChooserItem(){} }; class FileChooserItem : public FileOrFolderChooserItem { @@ -201,7 +206,7 @@ public: class ComboBoxItem : public MainWindowItem { public: QComboBox* comboBox; - ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_), comboBox(comboBox_){}; + ComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : MainWindowItem(option_,comboBox_,QString()), comboBox(comboBox_){}; virtual ~ComboBoxItem(){} virtual void installListeners(MainWindow *mainWindow); virtual void loadFromConfigOption()=0; @@ -260,7 +265,7 @@ public: class CheckBoxItem : public MainWindowItem { public: QCheckBox* checkBox; - CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_), checkBox(checkBox_){}; + CheckBoxItem(ConfigOption option_, QCheckBox* checkBox_) : MainWindowItem(option_,checkBox_,QString()), checkBox(checkBox_){}; virtual ~CheckBoxItem(){} virtual void installListeners(MainWindow *mainWindow); virtual void loadFromConfigOption(){ @@ -276,58 +281,77 @@ public: class BaseFormattedStringItem : public BaseStringItem { public: QString fieldNameTranslated; - BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseStringItem(option_, lineEdit_), fieldNameTranslated(fieldNameTranslated_) {}; + BaseFormattedStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_, QString requirementToBeValid_) : + BaseStringItem(option_, lineEdit_, requirementToBeValid_), fieldNameTranslated(fieldNameTranslated_) {}; virtual ~BaseFormattedStringItem(){} virtual bool isValid()=0; }; class IntegerStringItem : public BaseFormattedStringItem { public: IntegerStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be a valid integer.")) {}; virtual ~IntegerStringItem(){} - virtual bool isValid(){return true;} + virtual bool isValid(){ + auto str=lineEdit->text(); + bool ok; + str.toInt(&ok); + return ok; + } virtual QString toString(){return QString::number(boost::any_cast(optionValue));} virtual boost::any fromString(QString s){return boost::any(std::stoi(s.toStdString()));} }; class UShortStringItem : public BaseFormattedStringItem { public: UShortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned short integer.")) {}; virtual ~UShortStringItem(){} - virtual bool isValid(){return true;} + virtual bool isValid(){ + auto str=lineEdit->text(); + bool ok; + str.toUShort(&ok); + return ok; + } virtual QString toString(){return QString::number(boost::any_cast(optionValue));} virtual boost::any fromString(QString s){return boost::any((unsigned short)std::stoi(s.toStdString()));} }; class UInt32StringItem : public BaseFormattedStringItem { public: UInt32StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 32-bit integer.")) {}; virtual ~UInt32StringItem(){} - virtual bool isValid(){return true;} + virtual bool isValid(){ + auto str=lineEdit->text(); + bool ok; + str.toUInt(&ok); + return ok; + } virtual QString toString(){return QString::number(boost::any_cast(optionValue));} virtual boost::any fromString(QString s){return boost::any((uint32_t)std::stoi(s.toStdString()));} }; class UInt16StringItem : public BaseFormattedStringItem { public: UInt16StringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be unsigned 16-bit integer.")) {}; virtual ~UInt16StringItem(){} - virtual bool isValid(){return true;} + virtual bool isValid(){ + auto str=lineEdit->text(); + bool ok; + str.toUShort(&ok); + return ok; + } virtual QString toString(){return QString::number(boost::any_cast(optionValue));} virtual boost::any fromString(QString s){return boost::any((uint16_t)std::stoi(s.toStdString()));} }; class IPAddressStringItem : public BaseFormattedStringItem { public: IPAddressStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : - BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_) {}; - virtual bool isValid(){return true;} + BaseFormattedStringItem(option_, lineEdit_, fieldNameTranslated_, QApplication::tr("Must be an IPv4 address")) {}; + virtual bool isValid(){return true;}//todo }; class TCPPortStringItem : public UShortStringItem { public: TCPPortStringItem(ConfigOption option_, QLineEdit* lineEdit_, QString fieldNameTranslated_) : UShortStringItem(option_, lineEdit_, fieldNameTranslated_) {}; - virtual bool isValid(){return true;} }; namespace Ui { @@ -354,6 +378,8 @@ public: void setI2PController(i2p::qt::Controller* controller_); + void highlightWrongInput(QString warningText, QWidget* widgetToFocus); + //typedef std::function DefaultValueGetter; //#ifndef ANDROID @@ -385,7 +411,7 @@ private slots: void runPeerTest(); void enableTransit(); void disableTransit(); - +public slots: void showStatus_local_destinations_Page(); void showStatus_leasesets_Page(); void showStatus_tunnels_Page(); @@ -546,9 +572,9 @@ private: TunnelConfig* tc=it->second; tunnelConfigs.erase(it); delete tc; - SaveTunnelsConfig(); - reloadTunnelsConfigAndUI(""); } + saveAllConfigs(); + reloadTunnelsConfigAndUI(""); } std::string GenerateNewTunnelName() { @@ -583,7 +609,7 @@ private: destinationPort, sigType); - SaveTunnelsConfig(); + saveAllConfigs(); reloadTunnelsConfigAndUI(name); } @@ -622,7 +648,7 @@ private: isUniqueLocal); - SaveTunnelsConfig(); + saveAllConfigs(); reloadTunnelsConfigAndUI(name); } diff --git a/qt/i2pd_qt/mainwindow.ui b/qt/i2pd_qt/mainwindow.ui index cf15155b..bdd4693d 100644 --- a/qt/i2pd_qt/mainwindow.ui +++ b/qt/i2pd_qt/mainwindow.ui @@ -50,7 +50,7 @@ 10 10 888 - 530 + 555 @@ -168,332 +168,770 @@ - - - - 0 - 0 - - - - - 0 - 528 - - - - - 713 - 713 - - - - 1 - - - - - 0 - 0 - - - - - - 0 - 0 + + + + + + 0 + 30 + + + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 127 + 127 + + + + + + + 255 + 63 + 63 + + + + + + + 127 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 127 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + TextLabel + + + true + + + 10 + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + 713 - 531 - + 713 + - - - QLayout::SetMaximumSize + + 1 + + + + + 0 + 0 + - - - - - 15 - - - - Status - - - - - + + + + 0 + 0 + 713 + 531 + + + QLayout::SetMaximumSize + + + + + 15 + + + + Status + + + + + + + QLayout::SetMaximumSize + + + - - - - - - - - 0 - 0 - - - - - - 0 - 0 - 711 - 531 - - - - - QLayout::SetMaximumSize + + + + + + 0 + 0 + - - - - - 15 - - - - General settings - - - - - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAsNeeded - - - QAbstractScrollArea::AdjustIgnored - - - true + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMaximumSize - - - - 0 - 0 - 689 - 496 - - - - - 0 - 0 - - - - - - - - - - - - - 0 - 0 - 711 - 531 - - - - - QLayout::SetMinAndMaxSize - - - - - - 15 - + + + + + 15 + + + + General settings + + + + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + true + + + + + 0 + 0 + 689 + 496 + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize - - Tunnels settings + + + + + 15 + + + + Tunnels settings + + + + + + + + + Add Client Tunnel + + + + + + + Add Server Tunnel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::ScrollBarAlwaysOn + + + false + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 699 + 425 + + + + + + + + + + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize - - - - - + + + + 15 + + - Add Client Tunnel + Restart - + - Add Server Tunnel + Restart i2pd - + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 20 + 40 - - - - - Qt::ScrollBarAlwaysOn - - - false - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - 0 - 0 - 699 - 425 - - - - - - - - - - - - - 0 - 0 - 711 - 531 - - - - - QLayout::SetMinAndMaxSize - - - - - - 15 - - - - Restart - - - - - - - Restart i2pd - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - 0 - 0 - - - - - - 0 - 0 - 711 - 531 - - - - - QLayout::SetMinAndMaxSize + + + + + + 0 + 0 + - - - - - 15 - - - - Quit - - - - - - - Quit Now - - - - - - - Graceful Quit - - - - - - - Qt::Vertical - - - - 20 - 40 - + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize - - - + + + + + 15 + + + + Quit + + + + + + + Quit Now + + + + + + + Graceful Quit + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + - - + + diff --git a/qt/i2pd_qt/widgetlock.h b/qt/i2pd_qt/widgetlock.h index 513f328a..5b21125c 100644 --- a/qt/i2pd_qt/widgetlock.h +++ b/qt/i2pd_qt/widgetlock.h @@ -12,6 +12,7 @@ class widgetlock : public QObject { private: QWidget* widget; QPushButton* lockButton; + public slots: void lockButtonClicked(bool) { bool wasEnabled = widget->isEnabled(); @@ -25,7 +26,8 @@ public: lockButton->setText(lockButton->tr("Edit")); QObject::connect(lockButton,SIGNAL(clicked(bool)), this, SLOT(lockButtonClicked(bool))); } - virtual ~widgetlock() { + virtual ~widgetlock() {} + void deleteListener() { QObject::disconnect(lockButton,SIGNAL(clicked(bool)), this, SLOT(lockButtonClicked(bool))); } }; diff --git a/qt/i2pd_qt/widgetlockregistry.h b/qt/i2pd_qt/widgetlockregistry.h index 1091af43..78ee142a 100644 --- a/qt/i2pd_qt/widgetlockregistry.h +++ b/qt/i2pd_qt/widgetlockregistry.h @@ -9,15 +9,19 @@ class widgetlockregistry { public: widgetlockregistry() : locks() {} - virtual ~widgetlockregistry() { + virtual ~widgetlockregistry() {} + void add(widgetlock* lock) { + locks.push_back(lock); + } + + void deleteListeners() { while(!locks.empty()) { - delete locks.back(); + widgetlock* lock = locks.back(); + lock->deleteListener(); + delete lock; locks.pop_back(); } } - void add(widgetlock* lock) { - locks.push_back(lock); - } }; #endif // WIDGETLOCKREGISTRY_H