Browse Source

Merge pull request #1184 from mewmew-i2p/openssl

closes #1164 (i.e. added a log viewer to qt), + misc cosmetic
pull/1188/merge
orignal 7 years ago committed by GitHub
parent
commit
d289aa71eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      daemon/Daemon.cpp
  2. 2
      daemon/Daemon.h
  3. 16
      libi2pd/Log.cpp
  4. 27
      qt/i2pd_qt/DaemonQT.cpp
  5. 2
      qt/i2pd_qt/DaemonQT.h
  6. 2
      qt/i2pd_qt/SignatureTypeComboboxFactory.h
  7. 15
      qt/i2pd_qt/i2pd_qt.pro
  8. 45
      qt/i2pd_qt/logviewermanager.cpp
  9. 130
      qt/i2pd_qt/logviewermanager.h
  10. 24
      qt/i2pd_qt/mainwindow.cpp
  11. 24
      qt/i2pd_qt/mainwindow.h
  12. 80
      qt/i2pd_qt/mainwindow.ui

11
daemon/Daemon.cpp

@ -60,7 +60,11 @@ namespace i2p @@ -60,7 +60,11 @@ namespace i2p
return service;
}
bool Daemon_Singleton::init(int argc, char* argv[])
bool Daemon_Singleton::init(int argc, char* argv[]) {
return init(argc, argv, nullptr);
}
bool Daemon_Singleton::init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream)
{
i2p::config::Init();
i2p::config::ParseCmdline(argc, argv);
@ -104,7 +108,10 @@ namespace i2p @@ -104,7 +108,10 @@ namespace i2p
logs = "file";
i2p::log::Logger().SetLogLevel(loglevel);
if (logs == "file") {
if (logstream) {
LogPrint(eLogInfo, "Log: will send messages to std::ostream");
i2p::log::Logger().SendTo (logstream);
} else if (logs == "file") {
if (logfile == "")
logfile = i2p::fs::DataDirPath("i2pd.log");
LogPrint(eLogInfo, "Log: will send messages to ", logfile);

2
daemon/Daemon.h

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
#include <memory>
#include <string>
#include <ostream>
namespace i2p
{
@ -12,6 +13,7 @@ namespace util @@ -12,6 +13,7 @@ namespace util
class Daemon_Singleton
{
public:
virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
virtual bool init(int argc, char* argv[]);
virtual bool start();
virtual bool stop();

16
libi2pd/Log.cpp

@ -8,6 +8,9 @@ @@ -8,6 +8,9 @@
#include "Log.h"
//for std::transform
#include <algorithm>
namespace i2p {
namespace log {
static Log logger;
@ -107,7 +110,18 @@ namespace log { @@ -107,7 +110,18 @@ namespace log {
}
}
void Log::SetLogLevel (const std::string& level) {
std::string str_tolower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
// static_cast<int(*)(int)>(std::tolower) // wrong
// [](int c){ return std::tolower(c); } // wrong
// [](char c){ return std::tolower(c); } // wrong
[](unsigned char c){ return std::tolower(c); } // correct
);
return s;
}
void Log::SetLogLevel (const std::string& level_) {
std::string level=str_tolower(level_);
if (level == "none") { m_MinLevel = eLogNone; }
else if (level == "error") { m_MinLevel = eLogError; }
else if (level == "warn") { m_MinLevel = eLogWarning; }

27
qt/i2pd_qt/DaemonQT.cpp

@ -1,6 +1,11 @@ @@ -1,6 +1,11 @@
#include <memory>
#include "DaemonQT.h"
#include "Daemon.h"
#include "mainwindow.h"
#include "Log.h"
#include <QMessageBox>
#include <QApplication>
#include <QMutexLocker>
@ -90,12 +95,12 @@ namespace qt @@ -90,12 +95,12 @@ namespace qt
delete mutex;
}
bool DaemonQTImpl::init(int argc, char* argv[])
bool DaemonQTImpl::init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream)
{
mutex=new QMutex(QMutex::Recursive);
setRunningCallback(0);
m_IsRunning=false;
return Daemon.init(argc,argv);
return Daemon.init(argc,argv,logstream);
}
void DaemonQTImpl::start()
@ -146,33 +151,35 @@ namespace qt @@ -146,33 +151,35 @@ namespace qt
int result;
{
std::shared_ptr<std::iostream> logstreamptr=std::make_shared<std::stringstream>();
//TODO move daemon init deinit to a bg thread
DaemonQTImpl daemon;
qDebug("Initialising the daemon...");
bool daemonInitSuccess = daemon.init(argc, argv);
(*logstreamptr) << "Initialising the daemon..." << std::endl;
bool daemonInitSuccess = daemon.init(argc, argv, logstreamptr);
if(!daemonInitSuccess)
{
QMessageBox::critical(0, "Error", "Daemon init failed");
return 1;
}
qDebug("Initialised, creating the main window...");
MainWindow w;
qDebug("Before main window.show()...");
LogPrint(eLogDebug, "Initialised, creating the main window...");
MainWindow w(logstreamptr);
LogPrint(eLogDebug, "Before main window.show()...");
w.show ();
{
i2p::qt::Controller daemonQtController(daemon);
w.setI2PController(&daemonQtController);
qDebug("Starting the daemon...");
LogPrint(eLogDebug, "Starting the daemon...");
emit daemonQtController.startDaemon();
//daemon.start ();
qDebug("Starting GUI event loop...");
LogPrint(eLogDebug, "Starting GUI event loop...");
result = app.exec();
//daemon.stop ();
}
}
//QMessageBox::information(&w, "Debug", "demon stopped");
qDebug("Exiting the application");
LogPrint(eLogDebug, "Exiting the application");
return result;
}
}

2
qt/i2pd_qt/DaemonQT.h

@ -25,7 +25,7 @@ namespace qt @@ -25,7 +25,7 @@ namespace qt
* @param argv
* @return success
*/
bool init(int argc, char* argv[]);
bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
void start();
void stop();
void restart();

2
qt/i2pd_qt/SignatureTypeComboboxFactory.h

@ -18,7 +18,7 @@ class SignatureTypeComboBoxFactory @@ -18,7 +18,7 @@ class SignatureTypeComboBoxFactory
}
public:
static const uint16_t getSigType(const QVariant& var) {
static uint16_t getSigType(const QVariant& var) {
return (uint16_t)var.toInt();
}

15
qt/i2pd_qt/i2pd_qt.pro

@ -4,7 +4,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -4,7 +4,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = i2pd_qt
TEMPLATE = app
QMAKE_CXXFLAGS *= -std=c++11
QMAKE_CXXFLAGS *= -std=c++11 -ggdb
DEFINES += USE_UPNP
# change to your own path, where you will store all needed libraries with 'git clone' commands below.
@ -93,7 +93,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ @@ -93,7 +93,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
textbrowsertweaked1.cpp \
pagewithbackbutton.cpp \
widgetlock.cpp \
widgetlockregistry.cpp
widgetlockregistry.cpp \
logviewermanager.cpp
#qt creator does not handle this well
#SOURCES += $$files(../../libi2pd/*.cpp)
@ -179,7 +180,8 @@ HEADERS += DaemonQT.h mainwindow.h \ @@ -179,7 +180,8 @@ HEADERS += DaemonQT.h mainwindow.h \
widgetlock.h \
widgetlockregistry.h \
i2pd.rc \
i2pd.rc
i2pd.rc \
logviewermanager.h
INCLUDEPATH += ../../libi2pd
INCLUDEPATH += ../../libi2pd_client
@ -280,8 +282,11 @@ windows { @@ -280,8 +282,11 @@ windows {
DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB
DEFINES -= UNICODE _UNICODE
BOOST_SUFFIX = -mt
QMAKE_CXXFLAGS = -Os
QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows
QMAKE_CXXFLAGS_RELEASE = -Os
QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows
#linker's -s means "strip"
QMAKE_LFLAGS_RELEASE += -s
LIBS = -lminiupnpc \
-lboost_system$$BOOST_SUFFIX \

45
qt/i2pd_qt/logviewermanager.cpp

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
#include "logviewermanager.h"
LogViewerManager::LogViewerManager(std::shared_ptr<std::iostream> logStream_,
QPlainTextEdit* logTextEdit_,
QObject *parent) :
QObject(parent),
logStream(logStream_),
logTextEdit(logTextEdit_),
controllerForBgThread(nullptr)
{
assert(logTextEdit!=nullptr);
controllerForBgThread=new i2pd::qt::logviewer::Controller(*this);
}
namespace i2pd {
namespace qt {
namespace logviewer {
QString Worker::pollAndShootATimerForInfiniteRetries() {
std::shared_ptr<std::iostream> logStream=logViewerManager.getLogStream();
assert(logStream!=nullptr);
std::streamsize MAX_SZ=64*1024;
char*buf=(char*)malloc(MAX_SZ*sizeof(char));
if(buf==nullptr)return "";
std::streamsize read=logStream->readsome(buf, MAX_SZ);
if(read<0)read=0;
QString ret=QString::fromUtf8(buf, read);
free(buf);
return ret;
}
Controller::Controller(LogViewerManager &parameter1):logViewerManager(parameter1) {
Worker *worker = new Worker(parameter1);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate1, worker, &Worker::doWork1);
connect(worker, &Worker::resultReady,
&parameter1, &LogViewerManager::appendPlainText_atGuiThread);
workerThread.start();
timerId=startTimer(100/*millis*/);
}
}
}
}

130
qt/i2pd_qt/logviewermanager.h

@ -0,0 +1,130 @@ @@ -0,0 +1,130 @@
#ifndef LOGVIEWERMANAGER_H
#define LOGVIEWERMANAGER_H
#include <QObject>
#include <QString>
#include <QPlainTextEdit>
#include <QScrollBar>
#include <QComboBox>
#include <QTimer>
#include <QThread>
#include <assert.h>
#include <string>
#include "FS.h"
#include "Log.h"
class LogViewerManager;
namespace i2pd {
namespace qt {
namespace logviewer {
class Worker : public QObject
{
Q_OBJECT
private:
LogViewerManager &logViewerManager;
public:
Worker(LogViewerManager &parameter1):logViewerManager(parameter1){}
private:
QString pollAndShootATimerForInfiniteRetries();
public slots:
void doWork1() {
/* ... here is the expensive or blocking operation ... */
QString read=pollAndShootATimerForInfiniteRetries();
emit resultReady(read);
}
signals:
void resultReady(QString read);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
LogViewerManager& logViewerManager;
int timerId;
public:
Controller(LogViewerManager &parameter1);
~Controller() {
if(timerId!=0)killTimer(timerId);
workerThread.quit();
workerThread.wait();
}
signals:
void operate1();
protected:
void timerEvent(QTimerEvent */*event*/) {
emit operate1();
}
};
}
}
}
class LogViewerManager : public QObject
{
Q_OBJECT
private:
std::shared_ptr<std::iostream> logStream;
QPlainTextEdit* logTextEdit;
i2pd::qt::logviewer::Controller* controllerForBgThread;
public:
//also starts a bg thread (QTimer) polling logStream->readsome(buf, n)
explicit LogViewerManager(std::shared_ptr<std::iostream> logStream_,
QPlainTextEdit* logTextEdit_,
QObject *parent);
//also deallocs the bg thread (QTimer)
virtual ~LogViewerManager(){}
const i2pd::qt::logviewer::Controller& getControllerForBgThread() {
assert(controllerForBgThread!=nullptr);
return *controllerForBgThread;
}
const QPlainTextEdit* getLogTextEdit(){ return logTextEdit; }
const std::shared_ptr<std::iostream> getLogStream(){ return logStream; }
signals:
public slots:
//void appendFromNonGuiThread(std::string read) {
//}
public slots:
void appendPlainText_atGuiThread(QString plainText) {
if(plainText.length()==0)return;
assert(logTextEdit!=nullptr);
int scrollPosVert =logTextEdit->verticalScrollBar()->value();
int scrollPosHoriz=logTextEdit->horizontalScrollBar()->value();
int scrollPosVertMax =logTextEdit->verticalScrollBar()->maximum();
const int MAX_LINES=10*1024;
logTextEdit->setMaximumBlockCount(MAX_LINES);
//logTextEdit->appendPlainText(plainText);
//navigate the window to the end
//QTextCursor cursor = logTextEdit->textCursor();
//cursor.movePosition(QTextCursor::MoveOperation::End);
//logTextEdit->setTextCursor(cursor);
//QTextCursor prev_cursor = logTextEdit->textCursor();
logTextEdit->moveCursor(QTextCursor::End);
logTextEdit->insertPlainText(plainText);
if(/*prev_cursor.atEnd()*/scrollPosVert==scrollPosVertMax){
//logTextEdit->moveCursor(QTextCursor::End);
scrollPosVert =logTextEdit->verticalScrollBar()->maximum();
scrollPosHoriz=logTextEdit->horizontalScrollBar()->minimum();
}
//else
// logTextEdit->setTextCursor(prev_cursor);
logTextEdit->verticalScrollBar()->setValue(scrollPosVert);
logTextEdit->horizontalScrollBar()->setValue(scrollPosHoriz);
}
/*
void replaceText_atGuiThread() {
assert(logTextEdit!=nullptr);
logTextEdit->setText(QString::fromStdString(nav.getContent()));
}
*/
};
#endif // LOGVIEWERMANAGER_H

24
qt/i2pd_qt/mainwindow.cpp

@ -27,15 +27,19 @@ @@ -27,15 +27,19 @@
#include "DaemonQT.h"
#include "SignatureTypeComboboxFactory.h"
#include "logviewermanager.h"
std::string programOptionsWriterCurrentSection;
MainWindow::MainWindow(QWidget *parent) :
MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *parent) :
QMainWindow(parent)
,logStream(logStream_)
#ifndef ANDROID
,quitting(false)
#endif
,wasSelectingAtStatusMainPage(false)
,showHiddenInfoStatusMainPage(false)
,logViewerManagerPtr(nullptr)
,ui(new Ui::MainWindow)
,statusButtonsUI(new Ui::StatusButtonsForm)
,routerCommandsUI(new Ui::routerCommandsWidget)
@ -132,6 +136,8 @@ MainWindow::MainWindow(QWidget *parent) : @@ -132,6 +136,8 @@ MainWindow::MainWindow(QWidget *parent) :
QObject::connect(routerCommandsUI->acceptTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(enableTransit()));
QObject::connect(routerCommandsUI->declineTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(disableTransit()));
QObject::connect(ui->logViewerPushButton, SIGNAL(released()), this, SLOT(showLogViewerPage()));
QObject::connect(ui->settingsPagePushButton, SIGNAL(released()), this, SLOT(showSettingsPage()));
QObject::connect(ui->tunnelsPagePushButton, SIGNAL(released()), this, SLOT(showTunnelsPage()));
@ -299,6 +305,9 @@ MainWindow::MainWindow(QWidget *parent) : @@ -299,6 +305,9 @@ MainWindow::MainWindow(QWidget *parent) :
trayIcon->show();
#endif
logViewerManagerPtr=new LogViewerManager(logStream_,ui->logViewerTextEdit,this);
assert(logViewerManagerPtr!=nullptr);
onLoggingOptionsChange();
//QMetaObject::connectSlotsByName(this);
}
@ -333,10 +342,11 @@ void MainWindow::showStatusPage(StatusPage newStatusPage){ @@ -333,10 +342,11 @@ void MainWindow::showStatusPage(StatusPage newStatusPage){
}
wasSelectingAtStatusMainPage=false;
}
void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);}
void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);}
void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);}
void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(4);setStatusButtonsVisible(false);}
void MainWindow::showLogViewerPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);}
void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);}
void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);}
void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(4);setStatusButtonsVisible(false);}
void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(5);setStatusButtonsVisible(false);}
void MainWindow::setStatusButtonsVisible(bool visible) {
ui->statusButtonsPane->setVisible(visible);
@ -631,6 +641,8 @@ void MainWindow::loadAllConfigs(){ @@ -631,6 +641,8 @@ void MainWindow::loadAllConfigs(){
}
ReadTunnelsConfig();
onLoggingOptionsChange();
}
/** returns false iff not valid items present and save was aborted */
bool MainWindow::saveAllConfigs(){
@ -668,6 +680,8 @@ bool MainWindow::saveAllConfigs(){ @@ -668,6 +680,8 @@ bool MainWindow::saveAllConfigs(){
SaveTunnelsConfig();
onLoggingOptionsChange();
return true;
}

24
qt/i2pd_qt/mainwindow.h

@ -62,6 +62,8 @@ @@ -62,6 +62,8 @@
#include "widgetlockregistry.h"
#include "widgetlock.h"
class LogViewerManager;
template<typename ValueType>
bool isType(boost::any& a) {
return
@ -215,7 +217,8 @@ public: @@ -215,7 +217,8 @@ public:
};
class LogDestinationComboBoxItem : public ComboBoxItem {
public:
LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {};
LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) :
ComboBoxItem(option_, comboBox_) {}
virtual ~LogDestinationComboBoxItem(){}
virtual void loadFromConfigOption(){
MainWindowItem::loadFromConfigOption();
@ -228,6 +231,8 @@ public: @@ -228,6 +231,8 @@ public:
MainWindowItem::saveToStringStream(out);
}
virtual bool isValid() { return true; }
Q_OBJECT
};
class LogLevelComboBoxItem : public ComboBoxItem {
public:
@ -370,9 +375,10 @@ class Controller; @@ -370,9 +375,10 @@ class Controller;
class MainWindow : public QMainWindow {
Q_OBJECT
private:
std::shared_ptr<std::iostream> logStream;
public:
explicit MainWindow(QWidget *parent=0);
explicit MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *parent=nullptr);
~MainWindow();
void setI2PController(i2p::qt::Controller* controller_);
@ -419,6 +425,7 @@ public slots: @@ -419,6 +425,7 @@ public slots:
void showStatus_i2p_tunnels_Page();
void showStatus_sam_sessions_Page();
void showLogViewerPage();
void showSettingsPage();
void showTunnelsPage();
void showRestartPage();
@ -430,6 +437,8 @@ private: @@ -430,6 +437,8 @@ private:
bool wasSelectingAtStatusMainPage;
bool showHiddenInfoStatusMainPage;
LogViewerManager *logViewerManagerPtr;
void showStatusPage(StatusPage newStatusPage);
#ifndef ANDROID
void createActions();
@ -522,13 +531,6 @@ private: @@ -522,13 +531,6 @@ private:
void appendTunnelForms(std::string tunnelNameToFocus);
void deleteTunnelForms();
/*
TODO signaturetype
*/
template<typename Section, typename Type>
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
{
@ -790,6 +792,8 @@ private: @@ -790,6 +792,8 @@ private:
};
TunnelsPageUpdateListenerMainWindowImpl tunnelsPageUpdateListener;
void onLoggingOptionsChange() {}
};
#endif // MAINWINDOW_H

80
qt/i2pd_qt/mainwindow.ui

@ -58,7 +58,7 @@ @@ -58,7 +58,7 @@
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,0,0,0,0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,0,0,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
@ -96,6 +96,13 @@ @@ -96,6 +96,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="logViewerPushButton">
<property name="text">
<string>Log</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="settingsPagePushButton">
<property name="enabled">
@ -596,7 +603,7 @@ @@ -596,7 +603,7 @@
</palette>
</property>
<property name="text">
<string>TextLabel</string>
<string>wrongInputMessageLabel</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -627,7 +634,7 @@ @@ -627,7 +634,7 @@
</size>
</property>
<property name="currentIndex">
<number>2</number>
<number>1</number>
</property>
<widget class="QWidget" name="statusPage">
<property name="sizePolicy">
@ -671,6 +678,69 @@ @@ -671,6 +678,69 @@
</layout>
</widget>
</widget>
<widget class="QWidget" name="logViewerPage">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<widget class="QWidget" name="verticalLayoutWidget_4_logViewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>711</width>
<height>531</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4_logViewer">
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
</property>
<item>
<widget class="QLabel" name="logViewerTitleLabel">
<property name="font">
<font>
<pointsize>15</pointsize>
</font>
</property>
<property name="text">
<string>Log</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="logViewerTextEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="maximumBlockCount">
<number>10000</number>
</property>
<property name="acceptRichText" stdset="0">
<bool>false</bool>
</property>
<property name="widgetResizable" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="settingsPage">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -728,8 +798,8 @@ @@ -728,8 +798,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>689</width>
<height>496</height>
<width>81</width>
<height>28</height>
</rect>
</property>
<property name="sizePolicy">

Loading…
Cancel
Save