Skip to content

Commit c9002d8

Browse files
committed
feat: Add TODO list and regime state management
Adds a TODO list to the README.md file. Implements a state management system for regimes, allowing for real-time updates and a more dynamic user interface.
1 parent b09fb2b commit c9002d8

14 files changed

Lines changed: 280 additions & 90 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ qt6_add_qml_module(${EXECUTABLE_NAME}
4242
QML_FILES
4343
ConditionCell.qml
4444
ControlDelegate.qml
45+
StateDelegate.qml
4546
SOURCES
4647
prototablemodel.h
4748
regime.h

README.md

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,108 @@
1+
### TODO for Friday, August 8, 2025
2+
3+
1. **QML Module API:**
4+
* Provide a QML API to return the `Regime` class object by row number (id) from `ProtoTableModel`.
5+
* Provide a signal for the Button delegate in `tableView` (column 0) so that external QML components can react to button clicks, passing the corresponding `Regime` data.
6+
2. **Default Repeat Count:**
7+
* Grouping and ungrouping should set the default repeat count to 1.
8+
3. **Save Changes to JSON:**
9+
* Ensure that all changes, including grouping, ungrouping, and reordering, are correctly saved back to the `regime_a.json` file.
10+
4. **Synchronize Scroll Views:**
11+
* The vertical scroll position of `tableView` and `controlsView` should be synchronized.
12+
13+
### План работ на пятницу, 8 августа 2025 г.
14+
15+
1. **API модуля QML:**
16+
* Предоставить API QML для возврата объекта класса `Regime` по номеру строки (id) из `ProtoTableModel`.
17+
* Предоставить сигнал для делегата `Button` в `tableView` (столбец 0), чтобы внешние компоненты QML могли реагировать на нажатия кнопок, передавая соответствующие данные `Regime`.
18+
2. **Количество повторений по умолчанию:**
19+
* Группировка и разгруппировка должны устанавливать количество повторений по умолчанию равным 1.
20+
3. **Сохранение изменений в JSON:**
21+
* Убедиться, что все изменения, включая группировку, разгруппировку и изменение порядка, корректно сохраняются обратно в файл `regime_a.json`.
22+
4. **Синхронизация полос прокрутки:**
23+
* Положение вертикальной полосы прокрутки `tableView` и `controlsView` должно совпадать.
24+
25+
---
26+
27+
## Daily Report for 2025-08-07
28+
29+
Today's session focused on implementing a "state" property for regimes, allowing for real-time updates and a more dynamic user interface.
30+
31+
### C++ Changes:
32+
33+
* **`regime.h`:**
34+
* Introduced a `RegimeEnums::State` enum with the following states: `Waiting`, `Stopped`, `Running`, `Paused`, `Skipped`, `Done`, and `Error`.
35+
* Added `m_state` and `m_timePassedInSeconds` members to the `Regime` struct.
36+
* **`prototablemodel.h` & `prototablemodel.cpp`:**
37+
* Added a `StateRole` and `TimePassedInSecondsRole` to the model's roles.
38+
* Updated the `data()` and `setData()` methods to handle the new roles.
39+
* **`regimemanager.h` & `regimemanager.cpp`:**
40+
* Added a `stateChanged` signal and an `onStateChanged` slot to the `RegimeManager` class to allow for external state updates.
41+
* The `onStateChanged` slot now accepts the regime index, state, and time passed in seconds.
42+
* **`main.cpp`:**
43+
* Registered the `RegimeEnums::State` enum with the QML type system.
44+
45+
### QML Changes:
46+
47+
* **`StateDelegate.qml`:**
48+
* Created a new `StateDelegate.qml` file to display the regime state.
49+
* The delegate is a `TextField` that displays the state as text with different colors based on the current state.
50+
* The delegate now calculates and displays the time passed, time left, and total running time based on the state and the `max_time` value.
51+
* **`Main.qml`:**
52+
* Added a new "State" column to the `TableView`.
53+
* The new column uses the `StateDelegate` to display the state of each regime.
54+
* **`Utils.js`:**
55+
* Updated the `formatTime` function to work with seconds.
56+
57+
### Build System Changes:
58+
59+
* **`CMakeLists.txt`:**
60+
* Added the new `StateDelegate.qml` file to the list of QML files.
61+
62+
### Testing Changes:
63+
64+
* **`tests/test_regimemanager.cpp`:**
65+
* Updated the tests to reflect the changes in the `RegimeManager` class.
66+
67+
## Ежедневный отчет за 2025-08-07
68+
69+
Сегодняшняя сессия была посвящена реализации свойства «состояние» для режимов, что обеспечивает обновления в реальном времени и более динамичный пользовательский интерфейс.
70+
71+
### Изменения в C++:
72+
73+
* **`regime.h`:**
74+
* Введено перечисление `RegimeEnums::State` со следующими состояниями: `Waiting`, `Stopped`, `Running`, `Paused`, `Skipped`, `Done` и `Error`.
75+
* В структуру `Regime` добавлены члены `m_state` и `m_timePassedInSeconds`.
76+
* **`prototablemodel.h` и `prototablemodel.cpp`:**
77+
* В роли модели добавлены `StateRole` и `TimePassedInSecondsRole`.
78+
* Обновлены методы `data()` и `setData()` для обработки новых ролей.
79+
* **`regimemanager.h` и `regimemanager.cpp`:**
80+
* В класс `RegimeManager` добавлены сигнал `stateChanged` и слот `onStateChanged` для обеспечения возможности обновления состояния извне.
81+
* Слот `onStateChanged` теперь принимает индекс режима, состояние и прошедшее время в секундах.
82+
* **`main.cpp`:**
83+
* Зарегистрировано перечисление `RegimeEnums::State` в системе типов QML.
84+
85+
### Изменения в QML:
86+
87+
* **`StateDelegate.qml`:**
88+
* Создан новый файл `StateDelegate.qml` для отображения состояния режима.
89+
* Делегат представляет собой `TextField`, который отображает состояние в виде текста с разными цветами в зависимости от текущего состояния.
90+
* Делегат теперь вычисляет и отображает прошедшее время, оставшееся время и общее время работы в зависимости от состояния и значения `max_time`.
91+
* **`Main.qml`:**
92+
* В `TableView` добавлена новая колонка «Состояние».
93+
* Новая колонка использует `StateDelegate` для отображения состояния каждого режима.
94+
* **`Utils.js`:**
95+
* Обновлена функция `formatTime` для работы с секундами.
96+
97+
### Изменения в системе сборки:
98+
99+
* **`CMakeLists.txt`:**
100+
* Новый файл `StateDelegate.qml` добавлен в список файлов QML.
101+
102+
### Изменения в тестировании:
103+
104+
* **`tests/test_regimemanager.cpp`:**
105+
* Обновлены тесты для отражения изменений в классе `RegimeManager`.
1106

2107
### TODO for Thursday, August 7, 2025
3108

@@ -447,4 +552,4 @@ Overall, today's changes have made the application more robust and feature-rich,
447552
- Изменена модель `ProtoTableModel` для предоставления данных `condition` из `regime_a.json` в качестве пользовательской роли.
448553
- Обновлен `ConditionDelegateA.qml` для использования данных `condition` из модели, заполняя `ComboBox` и `TextField` правильными значениями.
449554
- Добавлен новый файл `ConditionDelegateA.qml` в `CMakeLists.txt` для включения его в сборку.
450-
- Отлажены и исправлены различные ошибки сборки и выполнения, возникшие в ходе разработки.
555+
- Отлажены и исправлены различные ошибки сборки и выполнения, возникшие в ходе разработки.

StateDelegate.qml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import QtQuick
2+
import QtQuick.Controls
3+
import com.grams.prototable
4+
5+
TextField {
6+
id: stateDelegate
7+
function toHHMMSS(secs) { // seems working
8+
9+
let newDate = new Date(secs * 1000).toISOString().slice(11, 19);
10+
// debug if need, Date use 1970 thing
11+
return newDate
12+
}
13+
function fromHHMMSS(str){
14+
// let date = new Date(str);
15+
let a = str.split(':'); // split it at the colons
16+
// minutes are worth 60 seconds. Hours are worth 60 minutes.
17+
let seconds = (+a[0]) * 60 * 60 + (+a[1]) * 60 + (+a[2]);
18+
return seconds; //
19+
}
20+
readOnly: true
21+
color: "black"
22+
text: {
23+
switch (model.state) {
24+
case RegimeState.Running:
25+
return toHHMMSS(model.time_passed_in_seconds);
26+
case RegimeState.Paused:
27+
return toHHMMSS((model.max_time*60 - model.time_passed_in_seconds));
28+
case RegimeState.Skipped:
29+
case RegimeState.Done:
30+
return toHHMMSS(model.max_time*60);
31+
case RegimeState.Error:
32+
return "Error";
33+
case RegimeState.Stopped:
34+
default:
35+
return "Ожидание";
36+
}
37+
}
38+
39+
background: Rectangle {
40+
color: {
41+
switch (model.state) {
42+
case RegimeState.Running:
43+
return "#C8E6C9"; // Pastel Green
44+
case RegimeState.Paused:
45+
return "#BBDEFB"; // Pastel Blue
46+
case RegimeState.Error:
47+
return "#FFCDD2"; // Pastel Red
48+
case RegimeState.Skipped:
49+
case RegimeState.Done:
50+
return "white";
51+
case RegimeState.Stopped:
52+
default:
53+
return "transparent";
54+
}
55+
}
56+
}
57+
}

main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ int main(int argc, char *argv[])
1010
QGuiApplication app(argc, argv);
1111

1212
qRegisterMetaType<Condition>();
13+
qmlRegisterUncreatableMetaObject(RegimeEnums::staticMetaObject, "com.grams.prototable", 1, 0, "RegimeState", "Error: only enums");
1314

1415
QQmlApplicationEngine engine;
1516
RegimeManager regimeManager;
@@ -21,6 +22,5 @@ int main(int argc, char *argv[])
2122
QCoreApplication::exit(-1);
2223
}, Qt::QueuedConnection);
2324
engine.load(url);
24-
2525
return app.exec();
2626
}

profile/regime_a.json

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,10 @@
66
"time": 0,
77
"type": "temp"
88
},
9-
"max_time": 0,
9+
"max_time": 60,
1010
"note": "",
1111
"repeat": 1,
12-
"cycle": null,
13-
"state": {
14-
"active": false,
15-
"error": false,
16-
"message": ""
17-
}
12+
"cycle": null
1813
},
1914
{
2015
"name": "Режим а",
@@ -29,11 +24,6 @@
2924
"cycle": {
3025
"id": 1,
3126
"cycleRepeat": 2
32-
},
33-
"state": {
34-
"active": false,
35-
"error": false,
36-
"message": ""
3727
}
3828
},
3929
{
@@ -49,11 +39,6 @@
4939
"cycle": {
5040
"id": 1,
5141
"cycleRepeat": 2
52-
},
53-
"state": {
54-
"active": false,
55-
"error": false,
56-
"message": ""
5742
}
5843
},
5944
{
@@ -66,11 +51,6 @@
6651
"max_time": 120,
6752
"note": "",
6853
"repeat": 1,
69-
"cycle": null,
70-
"state": {
71-
"active": false,
72-
"error": false,
73-
"message": ""
74-
}
54+
"cycle": null
7555
}
7656
]

prototablemodel.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ void ProtoTableModel::updateCycleIds()
1818
ProtoTableModel::ProtoTableModel(QObject *parent)
1919
: QAbstractTableModel(parent)
2020
{
21-
m_columnNames << "Режим" << "Условие" << "Макс. время";
21+
m_columnNames << "Режим" << "Условие" << "Макс. время" << "Состояние";
2222
}
2323

2424
int ProtoTableModel::rowCount(const QModelIndex &parent) const
@@ -49,6 +49,7 @@ QVariant ProtoTableModel::data(const QModelIndex &index, int role) const
4949
case 0: return regime.m_name;
5050
case 1: return QVariant::fromValue(regime.m_condition);
5151
case 2: return regime.m_maxTime;
52+
case 3: return QVariant::fromValue(regime.m_state);
5253
default: return QVariant();
5354
}
5455
}
@@ -72,7 +73,7 @@ QVariant ProtoTableModel::data(const QModelIndex &index, int role) const
7273
return QVariant::fromValue(regime);
7374
}
7475

75-
if (role == SpanRole) {
76+
if (role == CycleRowCountRole) {
7677
if (regime.m_cycleId == -1) {
7778
return 1;
7879
}
@@ -112,8 +113,12 @@ QVariant ProtoTableModel::data(const QModelIndex &index, int role) const
112113
return regime.m_cycleRepeat;
113114
}
114115

115-
if (role == StatusRole) {
116-
return regime.m_status;
116+
if (role == StateRole) {
117+
return QVariant::fromValue(regime.m_state);
118+
}
119+
120+
if (role == TimePassedInSecondsRole) {
121+
return regime.m_timePassedInSeconds;
117122
}
118123

119124
return QVariant();
@@ -170,8 +175,14 @@ bool ProtoTableModel::setData(const QModelIndex &index, const QVariant &value, i
170175
return true;
171176
}
172177

173-
if (role == StatusRole) {
174-
regime.m_status = value.toInt();
178+
if (role == StateRole) {
179+
regime.m_state = value.value<RegimeEnums::State>();
180+
emit dataChanged(index, index, {role});
181+
return true;
182+
}
183+
184+
if (role == TimePassedInSecondsRole) {
185+
regime.m_timePassedInSeconds = value.toInt();
175186
emit dataChanged(index, index, {role});
176187
return true;
177188
}
@@ -223,10 +234,11 @@ QHash<int, QByteArray> ProtoTableModel::roleNames() const
223234
{ ConditionRole, "condition" },
224235
{ RepeatRole, "repeat" },
225236
{ MaxTimeRole, "max_time" },
226-
{ SpanRole, "span" },
237+
{ CycleRowCountRole, "cycle_row_count" },
227238
{ CycleStatusRole, "cycle_status" },
228239
{ CycleRepeatRole, "cycle_repeat" },
229-
{ StatusRole, "status" }
240+
{ StateRole, "state" },
241+
{ TimePassedInSecondsRole, "time_passed_in_seconds" }
230242
};
231243
}
232244

@@ -273,7 +285,7 @@ void ProtoTableModel::groupRows(QVariantList rows)
273285
}
274286

275287
updateCycleIds();
276-
emit dataChanged(index(0, 0), index(m_regimes.count() - 1, columnCount() - 1), {CycleStatusRole, SpanRole});
288+
emit dataChanged(index(0, 0), index(m_regimes.count() - 1, columnCount() - 1), {CycleStatusRole, CycleRowCountRole});
277289
emit selectionShouldBeCleared();
278290
}
279291

@@ -306,7 +318,7 @@ void ProtoTableModel::ungroupRows(QVariantList rows)
306318
}
307319

308320
updateCycleIds();
309-
emit dataChanged(index(0, 0), index(m_regimes.count() - 1, columnCount() - 1), {SpanRole, RepeatRole, CycleRepeatRole, CycleStatusRole});
321+
emit dataChanged(index(0, 0), index(m_regimes.count() - 1, columnCount() - 1), {CycleRowCountRole, RepeatRole, CycleRepeatRole, CycleStatusRole});
310322
emit selectionShouldBeCleared();
311323
}
312324

@@ -354,7 +366,7 @@ void ProtoTableModel::addRow(const QString &regimeName)
354366
m_regimes.append(newRegime);
355367
endInsertRows();
356368
if (rowCount() > 1) {
357-
emit dataChanged(index(0, 0), index(rowCount() - 2, columnCount() - 1), {CycleStatusRole, SpanRole});
369+
emit dataChanged(index(0, 0), index(rowCount() - 2, columnCount() - 1), {CycleStatusRole, CycleRowCountRole});
358370
}
359371
}
360372

@@ -403,7 +415,7 @@ void ProtoTableModel::deleteRows(QVariantList rows)
403415

404416
updateCycleIds();
405417
if (rowCount() > 0) {
406-
emit dataChanged(index(0, 0), index(m_regimes.count() - 1, columnCount() - 1), {CycleStatusRole, SpanRole});
418+
emit dataChanged(index(0, 0), index(m_regimes.count() - 1, columnCount() - 1), {CycleStatusRole, CycleRowCountRole});
407419
}
408420
}
409421

prototablemodel.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ class ProtoTableModel : public QAbstractTableModel
2222
ConditionRole,
2323
RepeatRole,
2424
MaxTimeRole,
25-
SpanRole,
25+
CycleRowCountRole,
2626
CycleStatusRole,
2727
CycleRepeatRole,
28-
StatusRole
28+
StateRole,
29+
TimePassedInSecondsRole
2930
};
3031

3132
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -61,8 +62,6 @@ public slots:
6162
Q_INVOKABLE int getRowCount() { return m_regimes.count(); }
6263

6364
signals:
64-
void regimeButtonClicked(QVariant regime);
65-
Q_INVOKABLE void updateRow(int row);
6665
void selectionShouldBeCleared();
6766

6867
private:

0 commit comments

Comments
 (0)