diff --git a/src/ui/fort_qml.qrc b/src/ui/fort_qml.qrc
index 6a3379b4..4220c19e 100644
--- a/src/ui/fort_qml.qrc
+++ b/src/ui/fort_qml.qrc
@@ -3,10 +3,13 @@
qml/controls/ButtonMenu.qml
qml/controls/ButtonPopup.qml
qml/controls/HSeparator.qml
+ qml/controls/LabelColorRow.qml
+ qml/controls/LabelSpinRow.qml
qml/controls/LinkButton.qml
qml/controls/ListViewControl.qml
qml/controls/RoundButtonTip.qml
qml/controls/ScrollBarControl.qml
+ qml/controls/SpinBoxControl.qml
qml/controls/SpinCombo.qml
qml/controls/SpinComboRow.qml
qml/controls/SpinDouble.qml
@@ -31,6 +34,7 @@
qml/pages/apps/AppsTextColumn.qml
qml/pages/apps/SpeedLimitButton.qml
qml/pages/log/AppListView.qml
+ qml/pages/log/GraphButton.qml
qml/pages/log/IpListView.qml
qml/pages/log/TrafOptionsButton.qml
qml/pages/schedule/TaskRow.qml
diff --git a/src/ui/fortmanager.cpp b/src/ui/fortmanager.cpp
index 26b73a25..35639687 100644
--- a/src/ui/fortmanager.cpp
+++ b/src/ui/fortmanager.cpp
@@ -41,7 +41,6 @@
FortManager::FortManager(FortSettings *fortSettings,
QObject *parent) :
QObject(parent),
- m_exiting(false),
m_trayIcon(new QSystemTrayIcon(this)),
m_engine(nullptr),
m_appWindow(nullptr),
@@ -221,8 +220,7 @@ void FortManager::launch()
{
showTrayIcon();
- if (m_fortSettings->graphWindowEnabled()
- && m_fortSettings->graphWindowVisible()) {
+ if (m_fortSettings->graphWindowVisible()) {
showGraphWindow();
}
}
@@ -285,8 +283,9 @@ void FortManager::showGraphWindow()
m_graphWindowState->install(m_graphWindow);
- connect(m_graphWindow, &GraphWindow::aboutToClose,
- this, &FortManager::closeGraphWindow);
+ connect(m_graphWindow, &GraphWindow::aboutToClose, [this] {
+ closeGraphWindow();
+ });
connect(m_graphWindow, &GraphWindow::mouseRightClick,
this, &FortManager::showTrayMenu);
@@ -302,12 +301,12 @@ void FortManager::showGraphWindow()
restoreGraphWindowState();
}
-void FortManager::closeGraphWindow()
+void FortManager::closeGraphWindow(bool storeVisibility)
{
if (!m_graphWindow)
return;
- saveGraphWindowState();
+ saveGraphWindowState(storeVisibility);
m_graphWindowState->uninstall(m_graphWindow);
@@ -327,11 +326,18 @@ void FortManager::switchGraphWindow()
closeGraphWindow();
}
+void FortManager::updateGraphWindow()
+{
+ if (!m_graphWindow)
+ return;
+
+ m_graphWindow->updateColors();
+ m_graphWindow->updateWindowFlags();
+}
+
void FortManager::exit(int retcode)
{
- m_exiting = true;
-
- closeGraphWindow();
+ closeGraphWindow(true);
closeWindow();
closeEngine();
@@ -538,9 +544,9 @@ void FortManager::restoreWindowState()
m_fortSettings->windowMaximized());
}
-void FortManager::saveGraphWindowState()
+void FortManager::saveGraphWindowState(bool visible)
{
- m_fortSettings->setGraphWindowVisible(m_exiting);
+ m_fortSettings->setGraphWindowVisible(visible);
m_fortSettings->setGraphWindowGeometry(m_graphWindowState->geometry());
m_fortSettings->setGraphWindowMaximized(m_graphWindowState->maximized());
}
@@ -577,16 +583,14 @@ void FortManager::updateTrayMenu()
this, SLOT(showWindow()));
addHotKey(optionsAction, fortSettings()->hotKeyOptions(), hotKeyEnabled);
- if (!conf.hasPassword() && !m_firewallConfToEdit) {
- if (fortSettings()->graphWindowEnabled()) {
- m_graphWindowAction = addAction(
- menu, QIcon(":/images/chart_bar.png"), tr("Traffic Graph"),
- this, SLOT(switchGraphWindow()), true,
- (m_graphWindow != nullptr));
- addHotKey(m_graphWindowAction, fortSettings()->hotKeyGraph(),
- conf.logStat());
- }
+ m_graphWindowAction = addAction(
+ menu, QIcon(":/images/chart_bar.png"), tr("Traffic Graph"),
+ this, SLOT(switchGraphWindow()), true,
+ (m_graphWindow != nullptr));
+ addHotKey(m_graphWindowAction, fortSettings()->hotKeyGraph(),
+ conf.logStat());
+ if (!conf.hasPassword() && !m_firewallConfToEdit) {
menu->addSeparator();
m_filterEnabledAction = addAction(
diff --git a/src/ui/fortmanager.h b/src/ui/fortmanager.h
index 855965f1..00b160e1 100644
--- a/src/ui/fortmanager.h
+++ b/src/ui/fortmanager.h
@@ -57,8 +57,9 @@ public slots:
void closeWindow();
void showGraphWindow();
- void closeGraphWindow();
+ void closeGraphWindow(bool storeVisibility = false);
void switchGraphWindow();
+ void updateGraphWindow();
void exit(int retcode = 0);
@@ -115,7 +116,7 @@ private:
void saveWindowState();
void restoreWindowState();
- void saveGraphWindowState();
+ void saveGraphWindowState(bool visible);
void restoreGraphWindowState();
void updateLogger();
@@ -133,8 +134,6 @@ private:
const QObject *receiver = nullptr, const char *member = nullptr);
private:
- uint m_exiting : 1;
-
MainWindow m_window; // dummy window for tray icon
QSystemTrayIcon *m_trayIcon;
diff --git a/src/ui/fortsettings.cpp b/src/ui/fortsettings.cpp
index b695b5fe..8784c874 100644
--- a/src/ui/fortsettings.cpp
+++ b/src/ui/fortsettings.cpp
@@ -12,7 +12,9 @@
FortSettings::FortSettings(const QStringList &args,
QObject *parent) :
QObject(parent),
- m_hasProvBoot(false)
+ m_hasProvBoot(false),
+ m_bulkUpdating(false),
+ m_bulkUpdatingEmit(false)
{
processArguments(args);
setupIni();
@@ -396,12 +398,39 @@ QVariant FortSettings::iniValue(const QString &key,
void FortSettings::setIniValue(const QString &key, const QVariant &value,
const QVariant &defaultValue)
{
- if (!defaultValue.isNull()
- && m_ini->value(key, defaultValue) == value)
+ const QVariant oldValue = m_ini->value(key, defaultValue);
+ if (oldValue == value)
return;
m_ini->setValue(key, value);
- emit iniChanged();
+
+ if (m_bulkUpdating) {
+ m_bulkUpdatingEmit = true;
+ } else {
+ emit iniChanged();
+ }
+}
+
+void FortSettings::bulkUpdateBegin()
+{
+ Q_ASSERT(!m_bulkUpdating);
+
+ m_bulkUpdating = true;
+ m_bulkUpdatingEmit = false;
+}
+
+void FortSettings::bulkUpdateEnd()
+{
+ Q_ASSERT(m_bulkUpdating);
+
+ m_bulkUpdating = false;
+
+ const bool doEmit = m_bulkUpdatingEmit;
+ m_bulkUpdatingEmit = false;
+
+ if (doEmit) {
+ emit iniChanged();
+ }
}
void FortSettings::removeIniKey(const QString &key)
diff --git a/src/ui/fortsettings.h b/src/ui/fortsettings.h
index eae5d0e1..b40bdf9a 100644
--- a/src/ui/fortsettings.h
+++ b/src/ui/fortsettings.h
@@ -18,6 +18,21 @@ class FortSettings : public QObject
Q_OBJECT
Q_PROPERTY(bool debug READ debug WRITE setDebug NOTIFY iniChanged)
Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY iniChanged)
+ Q_PROPERTY(bool graphWindowVisible READ graphWindowVisible WRITE setGraphWindowVisible NOTIFY iniChanged)
+ Q_PROPERTY(bool graphWindowAlwaysOnTop READ graphWindowAlwaysOnTop WRITE setGraphWindowAlwaysOnTop NOTIFY iniChanged)
+ Q_PROPERTY(bool graphWindowFrameless READ graphWindowFrameless WRITE setGraphWindowFrameless NOTIFY iniChanged)
+ Q_PROPERTY(bool graphWindowClickThrough READ graphWindowClickThrough WRITE setGraphWindowClickThrough NOTIFY iniChanged)
+ Q_PROPERTY(bool graphWindowHideOnHover READ graphWindowHideOnHover WRITE setGraphWindowHideOnHover NOTIFY iniChanged)
+ Q_PROPERTY(int graphWindowOpacity READ graphWindowOpacity WRITE setGraphWindowOpacity NOTIFY iniChanged)
+ Q_PROPERTY(int graphWindowHoverOpacity READ graphWindowHoverOpacity WRITE setGraphWindowHoverOpacity NOTIFY iniChanged)
+ Q_PROPERTY(int graphWindowMaxSeconds READ graphWindowMaxSeconds WRITE setGraphWindowMaxSeconds NOTIFY iniChanged)
+ Q_PROPERTY(QColor graphWindowColor READ graphWindowColor WRITE setGraphWindowColor NOTIFY iniChanged)
+ Q_PROPERTY(QColor graphWindowColorIn READ graphWindowColorIn WRITE setGraphWindowColorIn NOTIFY iniChanged)
+ Q_PROPERTY(QColor graphWindowColorOut READ graphWindowColorOut WRITE setGraphWindowColorOut NOTIFY iniChanged)
+ Q_PROPERTY(QColor graphWindowAxisColor READ graphWindowAxisColor WRITE setGraphWindowAxisColor NOTIFY iniChanged)
+ Q_PROPERTY(QColor graphWindowTickLabelColor READ graphWindowTickLabelColor WRITE setGraphWindowTickLabelColor NOTIFY iniChanged)
+ Q_PROPERTY(QColor graphWindowLabelColor READ graphWindowLabelColor WRITE setGraphWindowLabelColor NOTIFY iniChanged)
+ Q_PROPERTY(QColor graphWindowGridColor READ graphWindowGridColor WRITE setGraphWindowGridColor NOTIFY iniChanged)
Q_PROPERTY(bool startWithWindows READ startWithWindows WRITE setStartWithWindows NOTIFY startWithWindowsChanged)
Q_PROPERTY(bool hotKeyEnabled READ hotKeyEnabled WRITE setHotKeyEnabled NOTIFY iniChanged)
Q_PROPERTY(QString logsPath READ logsPath CONSTANT)
@@ -50,9 +65,6 @@ public:
bool windowMaximized() const { return iniBool("window/maximized"); }
void setWindowMaximized(bool on) { setIniValue("window/maximized", on); }
- bool graphWindowEnabled() const { return iniBool("graphWindow/enabled"); }
- void setGraphWindowEnabled(bool on) { setIniValue("graphWindow/enabled", on); }
-
bool graphWindowVisible() const { return iniBool("graphWindow/visible"); }
void setGraphWindowVisible(bool on) { setIniValue("graphWindow/visible", on); }
@@ -71,6 +83,9 @@ public:
bool graphWindowClickThrough() const { return iniBool("graphWindow/clickThrough"); }
void setGraphWindowClickThrough(bool on) { setIniValue("graphWindow/clickThrough", on); }
+ bool graphWindowHideOnHover() const { return iniBool("graphWindow/hideOnHover"); }
+ void setGraphWindowHideOnHover(bool on) { setIniValue("graphWindow/hideOnHover", on); }
+
int graphWindowOpacity() const { return iniInt("graphWindow/opacity", 10); }
void setGraphWindowOpacity(int v) { setIniValue("graphWindow/opacity", v); }
@@ -151,6 +166,9 @@ public slots:
bool readConfIni(FirewallConf &conf) const;
bool writeConfIni(const FirewallConf &conf);
+ void bulkUpdateBegin();
+ void bulkUpdateEnd();
+
private:
void processArguments(const QStringList &args);
void setupIni();
@@ -190,7 +208,9 @@ private:
static QString startupShortcutPath();
private:
- uint m_hasProvBoot : 1;
+ uint m_hasProvBoot : 1;
+ uint m_bulkUpdating : 1;
+ uint m_bulkUpdatingEmit : 1;
QString m_profilePath;
QString m_statPath;
diff --git a/src/ui/graph/graphwindow.cpp b/src/ui/graph/graphwindow.cpp
index 5073d35d..26ba2c64 100644
--- a/src/ui/graph/graphwindow.cpp
+++ b/src/ui/graph/graphwindow.cpp
@@ -17,14 +17,13 @@ GraphWindow::GraphWindow(FortSettings *fortSettings,
setupUi();
setupTimer();
- setupWindow();
-
- connect(m_fortSettings, &FortSettings::iniChanged, this, &GraphWindow::setupWindow);
+ updateWindowFlags();
+ updateColors();
setMinimumSize(QSize(100, 50));
}
-void GraphWindow::setupWindow()
+void GraphWindow::updateWindowFlags()
{
const bool visible = isVisible();
@@ -38,13 +37,36 @@ void GraphWindow::setupWindow()
? Qt::WindowTransparentForInput : Qt::Widget)
);
+ if (visible) {
+ show(); // setWindowFlags() hides the window
+ }
+}
+
+void GraphWindow::updateColors()
+{
setWindowOpacityPercent(m_fortSettings->graphWindowOpacity());
m_plot->setBackground(QBrush(m_fortSettings->graphWindowColor()));
- if (visible) {
- show(); // setWindowFlags() hides the window
- }
+ // Axis
+ auto yAxis = m_plot->yAxis;
+
+ const QColor axisColor = m_fortSettings->graphWindowAxisColor();
+ yAxis->setBasePen(adjustPen(yAxis->basePen(), axisColor));
+ yAxis->setTickPen(adjustPen(yAxis->tickPen(), axisColor));
+ yAxis->setSubTickPen(adjustPen(yAxis->subTickPen(), axisColor));
+
+ yAxis->setTickLabelColor(m_fortSettings->graphWindowTickLabelColor());
+ yAxis->setLabelColor(m_fortSettings->graphWindowLabelColor());
+
+ yAxis->grid()->setPen(adjustPen(yAxis->grid()->pen(),
+ m_fortSettings->graphWindowGridColor()));
+
+ // Graph Inbound
+ m_graphIn->setPen(QPen(m_fortSettings->graphWindowColorIn()));
+
+ // Graph Outbound
+ m_graphOut->setPen(QPen(m_fortSettings->graphWindowColorOut()));
}
void GraphWindow::setupUi()
@@ -70,17 +92,6 @@ void GraphWindow::setupUi()
yAxis->setPadding(1);
yAxis->setTickLabelPadding(2);
- const QColor axisColor = m_fortSettings->graphWindowAxisColor();
- yAxis->setBasePen(adjustPen(yAxis->basePen(), axisColor));
- yAxis->setTickPen(adjustPen(yAxis->tickPen(), axisColor));
- yAxis->setSubTickPen(adjustPen(yAxis->subTickPen(), axisColor));
-
- yAxis->setTickLabelColor(m_fortSettings->graphWindowTickLabelColor());
- yAxis->setLabelColor(m_fortSettings->graphWindowLabelColor());
-
- yAxis->grid()->setPen(adjustPen(yAxis->grid()->pen(),
- m_fortSettings->graphWindowGridColor()));
-
// Axis Rect
auto axisRect = m_plot->axisRect();
axisRect->setMinimumMargins(QMargins(1, 1, 1, 1));
@@ -92,14 +103,12 @@ void GraphWindow::setupUi()
// Graph Inbound
m_graphIn = new QCPBars(m_plot->xAxis, m_plot->yAxis);
m_graphIn->setAntialiased(false);
- m_graphIn->setPen(QPen(m_fortSettings->graphWindowColorIn()));
m_graphIn->setWidthType(QCPBars::wtAbsolute);
m_graphIn->setWidth(1);
// Graph Outbound
m_graphOut = new QCPBars(m_plot->xAxis, m_plot->yAxis);
m_graphOut->setAntialiased(false);
- m_graphOut->setPen(QPen(m_fortSettings->graphWindowColorOut()));
m_graphOut->setWidthType(QCPBars::wtAbsolute);
m_graphOut->setWidth(1);
@@ -118,9 +127,10 @@ void GraphWindow::setupUi()
void GraphWindow::setupTimer()
{
- connect(&m_timer, &QTimer::timeout, this, &GraphWindow::addEmptyTraffic);
+ connect(&m_hoverTimer, &QTimer::timeout, this, &GraphWindow::checkHoverLeave);
+ connect(&m_updateTimer, &QTimer::timeout, this, &GraphWindow::addEmptyTraffic);
- m_timer.start(1000); // 1 second
+ m_updateTimer.start(1000); // 1 second
}
void GraphWindow::onMouseDoubleClick(QMouseEvent *event)
@@ -161,6 +171,12 @@ void GraphWindow::enterEvent(QEvent *event)
{
Q_UNUSED(event)
+ if (m_fortSettings->graphWindowHideOnHover()) {
+ hide();
+ m_hoverTimer.start(200);
+ return;
+ }
+
setWindowOpacityPercent(m_fortSettings->graphWindowHoverOpacity());
}
@@ -171,6 +187,16 @@ void GraphWindow::leaveEvent(QEvent *event)
setWindowOpacityPercent(m_fortSettings->graphWindowOpacity());
}
+void GraphWindow::checkHoverLeave()
+{
+ const QPoint mousePos = QCursor::pos();
+
+ if (!geometry().contains(mousePos)) {
+ m_hoverTimer.stop();
+ show();
+ }
+}
+
void GraphWindow::addTraffic(qint64 unixTime, quint32 inBytes, quint32 outBytes)
{
const qint64 rangeLower = unixTime - m_fortSettings->graphWindowMaxSeconds();
diff --git a/src/ui/graph/graphwindow.h b/src/ui/graph/graphwindow.h
index f7b689c3..b6f5bc1b 100644
--- a/src/ui/graph/graphwindow.h
+++ b/src/ui/graph/graphwindow.h
@@ -21,10 +21,13 @@ signals:
void mouseRightClick(QMouseEvent *event);
public slots:
+ void updateWindowFlags();
+ void updateColors();
+
void addTraffic(qint64 unixTime, quint32 inBytes, quint32 outBytes);
private slots:
- void setupWindow();
+ void checkHoverLeave();
void addEmptyTraffic();
@@ -59,7 +62,8 @@ private:
QPoint m_mousePressOffset;
- QTimer m_timer;
+ QTimer m_updateTimer;
+ QTimer m_hoverTimer;
};
#endif // GRAPHWINDOW_H
diff --git a/src/ui/i18n/i18n_ru.qm b/src/ui/i18n/i18n_ru.qm
index 2799a5ef..ee4f68f6 100644
Binary files a/src/ui/i18n/i18n_ru.qm and b/src/ui/i18n/i18n_ru.qm differ
diff --git a/src/ui/i18n/i18n_ru.ts b/src/ui/i18n/i18n_ru.ts
index 2bc8ecb7..4ea2504b 100644
--- a/src/ui/i18n/i18n_ru.ts
+++ b/src/ui/i18n/i18n_ru.ts
@@ -50,37 +50,42 @@
FortManager
-
+
Ввод пароля
-
+
Наберите пароль пожалуйста
-
+
Опции
-
+
+
+ График трафика
+
+
+
Фильтр включен
-
+
Остановить трафик
-
+
Остановить Интернет трафик
-
+
Выйти
@@ -88,17 +93,17 @@
FortSettings
-
+
Не удалось записать .ini файл
-
+
Не удалось создать .conf файл
-
+
Не удалось создать бэкап .conf файла
@@ -208,19 +213,19 @@
-
+
Очистить…
-
+
Удалить приложение
-
+
Очистить всё
@@ -245,7 +250,7 @@
Преобразовать адреса
-
+
Показ блокированных приложений
@@ -320,133 +325,133 @@
период, часы
-
+
Блокировать
-
+
Разрешить
-
+
Опции
-
+
Адреса IPv4
-
+
Приложения
-
+
Расписание
-
+
Блокировано
-
-
+
+
Статистика
-
+
Пароль:
-
+
OK
-
+
Применить
-
+
Отмена
-
+
Выйти
-
+
Запускать вместе с Windows
-
+
Блокировать доступ к сети, когда Fort Firewall не запущен
-
+
Фильтр включен
-
+
Фильтр локальных адресов
-
+
Остановить трафик
-
+
Остановить Интернет трафик
-
+
Горячие клавиши
-
+
Установлен
-
+
Не установлен
-
+
Язык:
-
+
Логи
-
+
Профиль
-
+
Релизы
@@ -471,12 +476,12 @@
Отключено
-
+
Ограничение скорости загрузки, KiB/s:
-
+
Ограничение скорости выгрузки, KiB/s:
@@ -521,32 +526,32 @@
Активный период, часы
-
+
Месяц начинается с:
-
+
Хранить дней для 'Почасовая':
-
+
Хранить дней для 'Ежедневная':
-
+
Хранить месяцев для 'Ежемесячная':
-
+
Квота на день
-
+
Квота на месяц
@@ -581,22 +586,22 @@
Каждый месяц
-
+
Наименование
-
+
Интервал, часов
-
+
Последний запуск
-
+
Успешный запуск
@@ -631,71 +636,71 @@
TiB
-
+
Обновить
-
+
Единицы:
-
+
Сбросить общую
-
+
Собирать статистику трафика
-
+
Все
-
+
Stat
Почасовая
-
+
Stat
Ежедневная
-
+
Stat
Ежемесячная
-
+
Stat
Общая
-
+
Дата
-
+
Загрузка
-
+
Выгрузка
-
+
Сумма
@@ -709,5 +714,80 @@
Разрешённые адреса Интернета
+
+
+
+ График…
+
+
+
+
+ Всегда сверху
+
+
+
+
+ Без рамок
+
+
+
+
+ Сквозной режим
+
+
+
+
+ Скрыть при наведении
+
+
+
+
+ Прозрачность
+
+
+
+
+ Прозрачность при наведении
+
+
+
+
+ Количество секунд
+
+
+
+
+ Цвет фона
+
+
+
+
+ Цвет загрузки
+
+
+
+
+ Цвет выгрузки
+
+
+
+
+ Цвет оси
+
+
+
+
+ Цвет метки
+
+
+
+
+ Цвет маркировки
+
+
+
+
+ Цвет сетки
+
diff --git a/src/ui/qml/controls/LabelColorRow.qml b/src/ui/qml/controls/LabelColorRow.qml
new file mode 100644
index 00000000..1c924c57
--- /dev/null
+++ b/src/ui/qml/controls/LabelColorRow.qml
@@ -0,0 +1,51 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import com.fortfirewall 1.0
+
+RowLayout {
+
+ Layout.fillWidth: true
+
+ signal colorEdited()
+
+ readonly property alias label: label
+ readonly property alias button: button
+
+ property real buttonPreferredWidth: 40
+
+ property color defaultColor
+ property color selectedColor: defaultColor
+
+ Label {
+ id: label
+ Layout.fillWidth: true
+ }
+
+ Button {
+ id: button
+ Layout.fillWidth: true
+ Layout.preferredWidth: buttonPreferredWidth
+ Layout.minimumWidth: buttonPreferredWidth
+ Layout.maximumWidth: implicitWidth
+ Layout.preferredHeight: buttonPreferredWidth
+
+ flat: true
+ background: Rectangle {
+ implicitWidth: buttonPreferredWidth
+ implicitHeight: buttonPreferredWidth
+ border.width: 1
+ border.color: button.down ? "gray" : "black"
+ color: selectedColor
+ }
+
+ onClicked: {
+ const color = guiUtil.getColor(selectedColor);
+ if (!guiUtil.isValidColor(color) || color === selectedColor)
+ return;
+
+ selectedColor = color;
+ colorEdited();
+ }
+ }
+}
diff --git a/src/ui/qml/controls/LabelSpinRow.qml b/src/ui/qml/controls/LabelSpinRow.qml
new file mode 100644
index 00000000..8e1da2c9
--- /dev/null
+++ b/src/ui/qml/controls/LabelSpinRow.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import com.fortfirewall 1.0
+
+RowLayout {
+
+ Layout.fillWidth: true
+
+ readonly property alias label: label
+ readonly property alias field: field
+
+ property real fieldPreferredWidth: 140
+
+ Label {
+ id: label
+ Layout.fillWidth: true
+ }
+
+ SpinBoxControl {
+ id: field
+ Layout.fillWidth: true
+ Layout.preferredWidth: fieldPreferredWidth
+ Layout.minimumWidth: fieldPreferredWidth
+ Layout.maximumWidth: implicitWidth
+ }
+}
diff --git a/src/ui/qml/controls/SpinBoxControl.qml b/src/ui/qml/controls/SpinBoxControl.qml
new file mode 100644
index 00000000..eabc613d
--- /dev/null
+++ b/src/ui/qml/controls/SpinBoxControl.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+SpinBox {
+ id: field
+
+ editable: true
+ from: 0
+ to: 9999
+
+ value: defaultValue
+
+ signal valueEdited()
+
+ property int defaultValue
+
+ onValueChanged: {
+ const value = field.value;
+ if (value === defaultValue)
+ return;
+
+ field.valueEdited();
+ }
+}
diff --git a/src/ui/qml/controls/SpinCombo.qml b/src/ui/qml/controls/SpinCombo.qml
index 1bfa27d7..672a9a9e 100644
--- a/src/ui/qml/controls/SpinCombo.qml
+++ b/src/ui/qml/controls/SpinCombo.qml
@@ -12,16 +12,12 @@ RowLayout {
property var names: values
property var values
- SpinBox {
+ SpinBoxControl {
id: field
Layout.fillWidth: true
Layout.preferredWidth: fieldPreferredWidth
Layout.minimumWidth: fieldPreferredWidth
- editable: true
- from: 0
- to: 9999
-
onValueChanged: {
combo.updateIndex(value);
}
diff --git a/src/ui/qml/controls/SpinDouble.qml b/src/ui/qml/controls/SpinDouble.qml
index 7b64aa87..3d43c9e3 100644
--- a/src/ui/qml/controls/SpinDouble.qml
+++ b/src/ui/qml/controls/SpinDouble.qml
@@ -9,25 +9,17 @@ RowLayout {
property real fieldPreferredWidth
- SpinBox {
+ SpinBoxControl {
id: field1
Layout.fillWidth: true
Layout.preferredWidth: fieldPreferredWidth
Layout.minimumWidth: fieldPreferredWidth
-
- editable: true
- from: 0
- to: 9999
}
- SpinBox {
+ SpinBoxControl {
id: field2
Layout.fillWidth: true
Layout.preferredWidth: fieldPreferredWidth
Layout.minimumWidth: fieldPreferredWidth
-
- editable: true
- from: 0
- to: 9999
}
}
diff --git a/src/ui/qml/pages/BasePage.qml b/src/ui/qml/pages/BasePage.qml
index 880bc282..784d429c 100644
--- a/src/ui/qml/pages/BasePage.qml
+++ b/src/ui/qml/pages/BasePage.qml
@@ -6,6 +6,9 @@ Pane {
bottomPadding: 0
+ function onEditResetted() {
+ }
+
function onAboutToSave() {
}
@@ -14,6 +17,7 @@ Pane {
Connections {
target: mainPage
+ onEditResetted: page.onEditResetted()
onAboutToSave: page.onAboutToSave()
onSaved: page.onSaved()
}
diff --git a/src/ui/qml/pages/BlockedPage.qml b/src/ui/qml/pages/BlockedPage.qml
index 60abec84..fa624231 100644
--- a/src/ui/qml/pages/BlockedPage.qml
+++ b/src/ui/qml/pages/BlockedPage.qml
@@ -73,9 +73,6 @@ BasePage {
&& qsTranslate("qml", "Resolve Addresses")
checked: firewallConf.resolveAddress
onToggled: {
- if (firewallConf.resolveAddress === checked)
- return;
-
firewallConf.resolveAddress = checked;
fortManager.applyConfImmediateFlags();
diff --git a/src/ui/qml/pages/MainPage.qml b/src/ui/qml/pages/MainPage.qml
index 84442617..f1db2e93 100644
--- a/src/ui/qml/pages/MainPage.qml
+++ b/src/ui/qml/pages/MainPage.qml
@@ -9,12 +9,13 @@ Page {
signal opened()
signal closed()
+ signal editResetted()
signal aboutToSave()
signal saved()
property bool confFlagsEdited
property bool confEdited
- property bool scheduleEdited
+ property bool othersEdited
function setConfFlagsEdited() {
confFlagsEdited = true;
@@ -24,14 +25,44 @@ Page {
confEdited = true;
}
- function setScheduleEdited() {
- scheduleEdited = true;
+ function setOthersEdited() {
+ othersEdited = true;
}
function resetEdited() {
confFlagsEdited = false;
confEdited = false;
- scheduleEdited = false;
+ othersEdited = false;
+
+ editResetted();
+ }
+
+ function save(closeOnSuccess) {
+ fortSettings.bulkUpdateBegin();
+
+ mainPage.aboutToSave();
+
+ var confSaved = true;
+ if (confFlagsEdited || confEdited) {
+ const confFlagsOnly = confFlagsEdited && !confEdited;
+ confSaved = closeOnSuccess
+ ? fortManager.saveConf(confFlagsOnly)
+ : fortManager.applyConf(confFlagsOnly);
+ }
+
+ if (confSaved) {
+ mainPage.saved();
+ }
+
+ fortSettings.bulkUpdateEnd();
+
+ if (confSaved) {
+ if (closeOnSuccess) {
+ closeWindow();
+ } else {
+ resetEdited();
+ }
+ }
}
onOpened: {
@@ -96,38 +127,18 @@ Page {
anchors.right: parent.right
Button {
- enabled: confFlagsEdited || confEdited || scheduleEdited
+ enabled: confFlagsEdited || confEdited || othersEdited
icon.source: "qrc:/images/tick.png"
text: translationManager.trTrigger
&& qsTranslate("qml", "OK")
- onClicked: {
- mainPage.aboutToSave();
-
- if (confFlagsEdited || confEdited) {
- if (!fortManager.saveConf(confFlagsEdited && !confEdited))
- return;
- }
-
- mainPage.saved();
- closeWindow();
- }
+ onClicked: mainPage.save(true)
}
Button {
- enabled: confFlagsEdited || confEdited || scheduleEdited
+ enabled: confFlagsEdited || confEdited || othersEdited
icon.source: "qrc:/images/accept.png"
text: translationManager.trTrigger
&& qsTranslate("qml", "Apply")
- onClicked: {
- mainPage.aboutToSave();
-
- if (confFlagsEdited || confEdited) {
- if (!fortManager.applyConf(confFlagsEdited && !confEdited))
- return;
- }
-
- mainPage.saved();
- resetEdited();
- }
+ onClicked: mainPage.save(false)
}
Button {
icon.source: "qrc:/images/cancel.png"
diff --git a/src/ui/qml/pages/OptionsPage.qml b/src/ui/qml/pages/OptionsPage.qml
index fd047e45..9adc1eab 100644
--- a/src/ui/qml/pages/OptionsPage.qml
+++ b/src/ui/qml/pages/OptionsPage.qml
@@ -6,6 +6,18 @@ import com.fortfirewall 1.0
BasePage {
+ property bool iniEdited
+
+ function setIniEdited() {
+ iniEdited = true;
+
+ setOthersEdited();
+ }
+
+ function onEditResetted() { // override
+ iniEdited = false;
+ }
+
function onAboutToSave() { // override
const password = editPassword.text;
if (password) {
@@ -15,6 +27,8 @@ BasePage {
}
function onSaved() { // override
+ if (!iniEdited) return;
+
fortSettings.startWithWindows = cbStart.checked;
fortSettings.hotKeyEnabled = cbHotKeys.checked;
}
@@ -31,9 +45,7 @@ BasePage {
text: translationManager.trTrigger
&& qsTranslate("qml", "Start with Windows")
checked: fortSettings.startWithWindows
- onToggled: {
- setConfFlagsEdited();
- }
+ onToggled: setIniEdited()
}
CheckBox {
@@ -104,9 +116,7 @@ BasePage {
text: translationManager.trTrigger
&& qsTranslate("qml", "Hot Keys")
checked: fortSettings.hotKeyEnabled
- onToggled: {
- setConfFlagsEdited();
- }
+ onToggled: setIniEdited()
}
Row {
diff --git a/src/ui/qml/pages/SchedulePage.qml b/src/ui/qml/pages/SchedulePage.qml
index 69bdab0d..68456a17 100644
--- a/src/ui/qml/pages/SchedulePage.qml
+++ b/src/ui/qml/pages/SchedulePage.qml
@@ -37,6 +37,18 @@ BasePage {
qsTranslate("qml", "Monthly")
]
+ property bool scheduleEdited
+
+ function setScheduleEdited() {
+ scheduleEdited = true;
+
+ setOthersEdited();
+ }
+
+ function onEditResetted() { // override
+ scheduleEdited = false;
+ }
+
function onSaved() { // override
if (!scheduleEdited) return;
diff --git a/src/ui/qml/pages/StatisticsPage.qml b/src/ui/qml/pages/StatisticsPage.qml
index 85c2b10c..10df1a32 100644
--- a/src/ui/qml/pages/StatisticsPage.qml
+++ b/src/ui/qml/pages/StatisticsPage.qml
@@ -35,6 +35,26 @@ BasePage {
qsTranslate("qml", "TiB")
]
+ property bool graphEdited
+
+ function setGraphEdited() {
+ graphEdited = true;
+
+ setOthersEdited();
+ }
+
+ function onEditResetted() { // override
+ graphEdited = false;
+ }
+
+ function onSaved() { // override
+ if (!graphEdited) return;
+
+ graphButton.save();
+
+ fortManager.updateGraphWindow();
+ }
+
ColumnLayout {
anchors.fill: parent
spacing: 10
@@ -78,6 +98,10 @@ BasePage {
TrafOptionsButton {}
+ GraphButton {
+ id: graphButton
+ }
+
Row {
spacing: 5
diff --git a/src/ui/qml/pages/apps/AppsColumn.qml b/src/ui/qml/pages/apps/AppsColumn.qml
index e15dd3e0..24f7a4b9 100644
--- a/src/ui/qml/pages/apps/AppsColumn.qml
+++ b/src/ui/qml/pages/apps/AppsColumn.qml
@@ -61,12 +61,8 @@ ColumnLayout {
text: translationManager.trTrigger
&& qsTranslate("qml", "period, hours:")
checked: appGroup.periodEnabled
- onCheckedChanged: {
- const value = checkBox.checked;
- if (appGroup.periodEnabled == value)
- return;
-
- appGroup.periodEnabled = value;
+ onToggled: {
+ appGroup.periodEnabled = checkBox.checked;
setConfEdited();
}
@@ -74,13 +70,9 @@ ColumnLayout {
field1 {
from: 0
to: 24
- value: appGroup.periodFrom
- onValueChanged: {
- const value = field1.value;
- if (appGroup.periodFrom == value)
- return;
-
- appGroup.periodFrom = value;
+ defaultValue: appGroup.periodFrom
+ onValueEdited: {
+ appGroup.periodFrom = field1.value;
setConfEdited();
}
@@ -88,13 +80,9 @@ ColumnLayout {
field2 {
from: 0
to: 24
- value: appGroup.periodTo
- onValueChanged: {
- const value = field2.value;
- if (appGroup.periodTo == value)
- return;
-
- appGroup.periodTo = value;
+ defaultValue: appGroup.periodTo
+ onValueEdited: {
+ appGroup.periodTo = field2.value;
setConfEdited();
}
diff --git a/src/ui/qml/pages/apps/SpeedLimitButton.qml b/src/ui/qml/pages/apps/SpeedLimitButton.qml
index db109de0..63efdfba 100644
--- a/src/ui/qml/pages/apps/SpeedLimitButton.qml
+++ b/src/ui/qml/pages/apps/SpeedLimitButton.qml
@@ -66,12 +66,8 @@ ButtonPopup {
text: translationManager.trTrigger
&& qsTranslate("qml", "Download speed limit, KiB/s:")
checked: appGroup.limitInEnabled
- onCheckedChanged: {
- const value = checkBox.checked;
- if (appGroup.limitInEnabled == value)
- return;
-
- appGroup.limitInEnabled = value;
+ onToggled: {
+ appGroup.limitInEnabled = checkBox.checked;
setConfEdited();
}
@@ -79,13 +75,9 @@ ButtonPopup {
field {
from: 0
to: 99999
- value: appGroup.speedLimitIn
- onValueChanged: {
- const value = field.value;
- if (appGroup.speedLimitIn == value)
- return;
-
- appGroup.speedLimitIn = value;
+ defaultValue: appGroup.speedLimitIn
+ onValueEdited: {
+ appGroup.speedLimitIn = field.value;
setConfEdited();
}
@@ -99,12 +91,8 @@ ButtonPopup {
text: translationManager.trTrigger
&& qsTranslate("qml", "Upload speed limit, KiB/s:")
checked: appGroup.limitOutEnabled
- onCheckedChanged: {
- const value = checkBox.checked;
- if (appGroup.limitOutEnabled == value)
- return;
-
- appGroup.limitOutEnabled = value;
+ onToggled: {
+ appGroup.limitOutEnabled = checkBox.checked;
setConfEdited();
}
@@ -112,13 +100,9 @@ ButtonPopup {
field {
from: 0
to: 99999
- value: appGroup.speedLimitOut
- onValueChanged: {
- const value = field.value;
- if (appGroup.speedLimitOut == value)
- return;
-
- appGroup.speedLimitOut = value;
+ defaultValue: appGroup.speedLimitOut
+ onValueEdited: {
+ appGroup.speedLimitOut = field.value;
setConfEdited();
}
diff --git a/src/ui/qml/pages/log/GraphButton.qml b/src/ui/qml/pages/log/GraphButton.qml
new file mode 100644
index 00000000..ecdd4106
--- /dev/null
+++ b/src/ui/qml/pages/log/GraphButton.qml
@@ -0,0 +1,175 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import "../../controls"
+import com.fortfirewall 1.0
+
+ButtonPopup {
+
+ icon.source: "qrc:/images/chart_bar.png"
+ text: translationManager.trTrigger
+ && qsTranslate("qml", "Graph…")
+
+ function save() {
+ fortSettings.graphWindowAlwaysOnTop = cbAlwaysOnTop.checked;
+ fortSettings.graphWindowFrameless = cbFrameless.checked;
+ fortSettings.graphWindowClickThrough = cbClickThrough.checked;
+ fortSettings.graphWindowHideOnHover = cbHideOnHover.checked;
+
+ fortSettings.graphWindowOpacity = rowOpacity.field.value;
+ fortSettings.graphWindowHoverOpacity = rowHoverOpacity.field.value;
+ fortSettings.graphWindowMaxSeconds = rowMaxSeconds.field.value;
+
+ fortSettings.graphWindowColor = rowColor.selectedColor;
+ fortSettings.graphWindowColorIn = rowColorIn.selectedColor;
+ fortSettings.graphWindowColorOut = rowColorOut.selectedColor;
+ fortSettings.graphWindowAxisColor = rowAxisColor.selectedColor;
+ fortSettings.graphWindowTickLabelColor = rowTickLabelColor.selectedColor;
+ fortSettings.graphWindowLabelColor = rowLabelColor.selectedColor;
+ fortSettings.graphWindowGridColor = rowGridColor.selectedColor;
+ }
+
+ RowLayout {
+ spacing: 10
+
+ ColumnLayout {
+ CheckBox {
+ id: cbAlwaysOnTop
+ text: translationManager.trTrigger
+ && qsTranslate("qml", "Always on top")
+ checked: fortSettings.graphWindowAlwaysOnTop
+ onToggled: setGraphEdited()
+ }
+
+ CheckBox {
+ id: cbFrameless
+ text: translationManager.trTrigger
+ && qsTranslate("qml", "Frameless")
+ checked: fortSettings.graphWindowFrameless
+ onToggled: setGraphEdited()
+ }
+
+ CheckBox {
+ id: cbClickThrough
+ text: translationManager.trTrigger
+ && qsTranslate("qml", "Click through")
+ checked: fortSettings.graphWindowClickThrough
+ onToggled: setGraphEdited()
+ }
+
+ CheckBox {
+ id: cbHideOnHover
+ text: translationManager.trTrigger
+ && qsTranslate("qml", "Hide on hover")
+ checked: fortSettings.graphWindowHideOnHover
+ onToggled: setGraphEdited()
+ }
+
+ HSeparator {}
+
+ LabelSpinRow {
+ id: rowOpacity
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Opacity")) + ":"
+ field {
+ from: 0
+ to: 100
+ defaultValue: fortSettings.graphWindowOpacity
+ onValueEdited: setGraphEdited()
+ }
+ }
+
+ LabelSpinRow {
+ id: rowHoverOpacity
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Hover opacity")) + ":"
+ field {
+ from: 0
+ to: 100
+ defaultValue: fortSettings.graphWindowHoverOpacity
+ onValueEdited: setGraphEdited()
+ }
+ }
+
+ LabelSpinRow {
+ id: rowMaxSeconds
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Max seconds")) + ":"
+ field {
+ from: 0
+ to: 9999
+ defaultValue: fortSettings.graphWindowMaxSeconds
+ onValueEdited: setGraphEdited()
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+
+ VSeparator {}
+
+ ColumnLayout {
+ LabelColorRow {
+ id: rowColor
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Background color")) + ":"
+ defaultColor: fortSettings.graphWindowColor
+ onColorEdited: setGraphEdited()
+ }
+
+ LabelColorRow {
+ id: rowColorIn
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Download color")) + ":"
+ defaultColor: fortSettings.graphWindowColorIn
+ onColorEdited: setGraphEdited()
+ }
+
+ LabelColorRow {
+ id: rowColorOut
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Upload color")) + ":"
+ defaultColor: fortSettings.graphWindowColorOut
+ onColorEdited: setGraphEdited()
+ }
+
+ LabelColorRow {
+ id: rowAxisColor
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Axis color")) + ":"
+ defaultColor: fortSettings.graphWindowAxisColor
+ onColorEdited: setGraphEdited()
+ }
+
+ LabelColorRow {
+ id: rowTickLabelColor
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Tick label color")) + ":"
+ defaultColor: fortSettings.graphWindowTickLabelColor
+ onColorEdited: setGraphEdited()
+ }
+
+ LabelColorRow {
+ id: rowLabelColor
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Label color")) + ":"
+ defaultColor: fortSettings.graphWindowLabelColor
+ onColorEdited: setGraphEdited()
+ }
+
+ LabelColorRow {
+ id: rowGridColor
+ label.text: (translationManager.trTrigger
+ && qsTranslate("qml", "Grid color")) + ":"
+ defaultColor: fortSettings.graphWindowGridColor
+ onColorEdited: setGraphEdited()
+ }
+
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+ }
+}
diff --git a/src/ui/qml/pages/log/TrafOptionsButton.qml b/src/ui/qml/pages/log/TrafOptionsButton.qml
index ee9e5097..37e7f758 100644
--- a/src/ui/qml/pages/log/TrafOptionsButton.qml
+++ b/src/ui/qml/pages/log/TrafOptionsButton.qml
@@ -67,12 +67,8 @@ ButtonPopup {
text: translationManager.trTrigger
&& qsTranslate("qml", "Active period, hours:")
checked: firewallConf.activePeriodEnabled
- onCheckedChanged: {
- const value = checkBox.checked;
- if (firewallConf.activePeriodEnabled == value)
- return;
-
- firewallConf.activePeriodEnabled = value;
+ onToggled: {
+ firewallConf.activePeriodEnabled = checkBox.checked;
setConfFlagsEdited();
}
@@ -80,13 +76,9 @@ ButtonPopup {
field1 {
from: 0
to: 24
- value: firewallConf.activePeriodFrom
- onValueChanged: {
- const value = field1.value;
- if (firewallConf.activePeriodFrom == value)
- return;
-
- firewallConf.activePeriodFrom = value;
+ defaultValue: firewallConf.activePeriodFrom
+ onValueEdited: {
+ firewallConf.activePeriodFrom = field1.value;
setConfFlagsEdited();
}
@@ -94,13 +86,9 @@ ButtonPopup {
field2 {
from: 0
to: 24
- value: firewallConf.activePeriodTo
- onValueChanged: {
- const value = field2.value;
- if (firewallConf.activePeriodTo == value)
- return;
-
- firewallConf.activePeriodTo = value;
+ defaultValue: firewallConf.activePeriodTo
+ onValueEdited: {
+ firewallConf.activePeriodTo = field2.value;
setConfFlagsEdited();
}
@@ -123,13 +111,9 @@ ButtonPopup {
field {
from: 1
to: 31
- value: firewallConf.monthStart
- onValueChanged: {
- const value = field.value;
- if (firewallConf.monthStart == value)
- return;
-
- firewallConf.monthStart = value;
+ defaultValue: firewallConf.monthStart
+ onValueEdited: {
+ firewallConf.monthStart = field.value;
setConfFlagsEdited();
}
@@ -148,13 +132,9 @@ ButtonPopup {
}
field {
from: -1
- value: firewallConf.trafHourKeepDays
- onValueChanged: {
- const value = field.value;
- if (firewallConf.trafHourKeepDays == value)
- return;
-
- firewallConf.trafHourKeepDays = value;
+ defaultValue: firewallConf.trafHourKeepDays
+ onValueEdited: {
+ firewallConf.trafHourKeepDays = field.value;
setConfFlagsEdited();
}
@@ -171,13 +151,9 @@ ButtonPopup {
}
field {
from: -1
- value: firewallConf.trafDayKeepDays
- onValueChanged: {
- const value = field.value;
- if (firewallConf.trafDayKeepDays == value)
- return;
-
- firewallConf.trafDayKeepDays = value;
+ defaultValue: firewallConf.trafDayKeepDays
+ onValueEdited: {
+ firewallConf.trafDayKeepDays = field.value;
setConfFlagsEdited();
}
@@ -194,13 +170,9 @@ ButtonPopup {
}
field {
from: -1
- value: firewallConf.trafMonthKeepMonths
- onValueChanged: {
- const value = field.value;
- if (firewallConf.trafMonthKeepMonths == value)
- return;
-
- firewallConf.trafMonthKeepMonths = value;
+ defaultValue: firewallConf.trafMonthKeepMonths
+ onValueEdited: {
+ firewallConf.trafMonthKeepMonths = field.value;
setConfFlagsEdited();
}
@@ -220,13 +192,9 @@ ButtonPopup {
field {
from: 0
to: 999 * 1024
- value: firewallConf.quotaDayMb
- onValueChanged: {
- const value = field.value;
- if (firewallConf.quotaDayMb == value)
- return;
-
- firewallConf.quotaDayMb = value;
+ defaultValue: firewallConf.quotaDayMb
+ onValueEdited: {
+ firewallConf.quotaDayMb = field.value;
setConfFlagsEdited();
}
@@ -244,13 +212,9 @@ ButtonPopup {
field {
from: 0
to: 999 * 1024
- value: firewallConf.quotaMonthMb
- onValueChanged: {
- const value = field.value;
- if (firewallConf.quotaMonthMb == value)
- return;
-
- firewallConf.quotaMonthMb = value;
+ defaultValue: firewallConf.quotaMonthMb
+ onValueEdited: {
+ firewallConf.quotaMonthMb = field.value;
setConfFlagsEdited();
}
diff --git a/src/ui/qml/pages/schedule/TaskRow.qml b/src/ui/qml/pages/schedule/TaskRow.qml
index 64b90a9b..c3870d1f 100644
--- a/src/ui/qml/pages/schedule/TaskRow.qml
+++ b/src/ui/qml/pages/schedule/TaskRow.qml
@@ -51,14 +51,8 @@ Row {
field {
from: 1
to: 24 * 30 * 12 // ~Year
- value: taskInfo.intervalHours
-
- onValueChanged: {
- const value = field.value;
- if (value != taskInfo.intervalHours) {
- setScheduleEdited();
- }
- }
+ defaultValue: taskInfo.intervalHours
+ onValueEdited: setScheduleEdited()
}
}
diff --git a/src/ui/util/guiutil.cpp b/src/ui/util/guiutil.cpp
index a6c728f1..f1f88fe0 100644
--- a/src/ui/util/guiutil.cpp
+++ b/src/ui/util/guiutil.cpp
@@ -1,6 +1,7 @@
#include "guiutil.h"
#include
+#include
#include
#include
#include
@@ -25,3 +26,13 @@ void GuiUtil::setClipboardData(const QVariant &data)
clipboard->setText(data.toString());
}
}
+
+QColor GuiUtil::getColor(const QColor &initial)
+{
+ return QColorDialog::getColor(initial);
+}
+
+bool GuiUtil::isValidColor(const QColor &color)
+{
+ return color.isValid();
+}
diff --git a/src/ui/util/guiutil.h b/src/ui/util/guiutil.h
index c976602a..73dceda3 100644
--- a/src/ui/util/guiutil.h
+++ b/src/ui/util/guiutil.h
@@ -1,6 +1,7 @@
#ifndef GUIUTIL_H
#define GUIUTIL_H
+#include
#include
#include
@@ -12,6 +13,9 @@ public:
explicit GuiUtil(QObject *parent = nullptr);
Q_INVOKABLE static void setClipboardData(const QVariant &data);
+
+ Q_INVOKABLE static QColor getColor(const QColor &initial = Qt::white);
+ Q_INVOKABLE static bool isValidColor(const QColor &color);
};
#endif // GUIUTIL_H