Skip to content

Commit 4ca7199

Browse files
committed
add widgets and tests
1 parent 7f4ed64 commit 4ca7199

22 files changed

+382
-41
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "qt-async-lib/widgets/QtWaitingSpinner"]
2+
path = qt-async-lib/widgets/QtWaitingSpinner
3+
url = https://github.com/lexxmark/QtWaitingSpinner.git

demo/MainWindow.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#include <QDesktopWidget>
44
#include <thread>
55
#include "widgets/AsyncWidget.h"
6+
#include "widgets/AsyncWidgetProgressSpinner.h"
67
#include "values/AsyncValueObtain.h"
8+
#include "widgets/QtWaitingSpinner/waitingspinnerwidget.h"
79

810
MainWindow::MainWindow(QWidget *parent) :
911
QMainWindow(parent),
@@ -14,9 +16,21 @@ MainWindow::MainWindow(QWidget *parent) :
1416
move(QApplication::desktop()->availableGeometry().center() - rect().center());
1517

1618
auto valueWidget = new AsyncWidgetFn<QString>(ui->widget);
19+
1720
valueWidget->createValueWidget = [](QString& value, QWidget* parent) {
1821
return AsyncWidgetProxy::createLabel(value, parent);
1922
};
23+
24+
valueWidget->createProgressWidget = [this](AsyncProgress& progress, QWidget* parent)->QWidget* {
25+
switch (m_progressWidgetMode) {
26+
case PROGRESS_MODE::SPINNER_LINES:
27+
return new AsyncWidgetProgressSpinner(progress, parent);
28+
29+
default:
30+
return new AsyncWidgetProgressBar(progress, parent);
31+
}
32+
};
33+
2034
valueWidget->setValue(&m_value);
2135

2236
ui->widget->setContentWidget(valueWidget);
@@ -70,6 +84,7 @@ void MainWindow::on_startBttn_clicked()
7084

7185
QString val = "Loaded value is 42";
7286
value.emplaceValue(std::move(val));
87+
7388
}, "Loading...", ASYNC_CAN_REQUEST_STOP::YES);
7489
}
7590

@@ -80,3 +95,13 @@ void MainWindow::on_stopBttn_clicked()
8095
progress.requestStop();
8196
});
8297
}
98+
99+
void MainWindow::on_radioButtonProgressBar_clicked()
100+
{
101+
m_progressWidgetMode = PROGRESS_MODE::PROGRESS_BAR;
102+
}
103+
104+
void MainWindow::on_radioButtonSpinnerLines_clicked()
105+
{
106+
m_progressWidgetMode = PROGRESS_MODE::SPINNER_LINES;
107+
}

demo/MainWindow.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ class MainWindow;
1010

1111
using AsyncQString = AsyncValue<QString>;
1212

13-
1413
class MainWindow : public QMainWindow
1514
{
1615
Q_OBJECT
@@ -27,10 +26,20 @@ private slots:
2726

2827
void on_stopBttn_clicked();
2928

29+
void on_radioButtonProgressBar_clicked();
30+
31+
void on_radioButtonSpinnerLines_clicked();
32+
3033
private:
3134
Ui::MainWindow *ui;
3235

3336
AsyncQString m_value;
37+
38+
enum class PROGRESS_MODE
39+
{
40+
PROGRESS_BAR,
41+
SPINNER_LINES,
42+
} m_progressWidgetMode = PROGRESS_MODE::PROGRESS_BAR;
3443
};
3544

3645
#endif // MAINWINDOW_H

demo/MainWindow.ui

+46
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,52 @@
9292
</property>
9393
</widget>
9494
</item>
95+
<item>
96+
<widget class="QGroupBox" name="groupBox">
97+
<property name="title">
98+
<string>Progress UI</string>
99+
</property>
100+
<layout class="QVBoxLayout" name="verticalLayout_2">
101+
<item>
102+
<widget class="QRadioButton" name="radioButtonProgressBar">
103+
<property name="text">
104+
<string>Progress Bar</string>
105+
</property>
106+
<property name="checked">
107+
<bool>true</bool>
108+
</property>
109+
</widget>
110+
</item>
111+
<item>
112+
<widget class="QRadioButton" name="radioButtonSpinnerLines">
113+
<property name="text">
114+
<string>Spinner Lines</string>
115+
</property>
116+
</widget>
117+
</item>
118+
<item>
119+
<widget class="QRadioButton" name="radioButtonSpinnerDots">
120+
<property name="enabled">
121+
<bool>false</bool>
122+
</property>
123+
<property name="text">
124+
<string>Spinner Dots</string>
125+
</property>
126+
</widget>
127+
</item>
128+
<item>
129+
<widget class="QRadioButton" name="radioButtonFlyDots">
130+
<property name="enabled">
131+
<bool>false</bool>
132+
</property>
133+
<property name="text">
134+
<string>Flying Dots</string>
135+
</property>
136+
</widget>
137+
</item>
138+
</layout>
139+
</widget>
140+
</item>
95141
<item>
96142
<spacer name="verticalSpacer">
97143
<property name="orientation">

demo/main.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
#include "MainWindow.h"
22
#include <QApplication>
3+
#include <widgets/AsyncWidgetError.h>
4+
5+
static QString asyncStyleSheet = R"(
6+
AsyncWidgetError,
7+
AsyncWidgetProgressBar,
8+
AsyncWidgetProgressSpinner,
9+
QLabel#AsyncLabel {
10+
background: white;
11+
border: 1px solid black;
12+
}
13+
)";
314

415
int main(int argc, char *argv[])
516
{
617
QApplication a(argc, argv);
18+
19+
a.setStyleSheet(asyncStyleSheet);
720
MainWindow w;
821
w.show();
922

qt-async-lib/Config.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
Copyright (c) 2018 Alex Zhondin <lexxmark.dev@gmail.com>
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#ifndef ASYNC_CONFIG_H
18+
#define ASYNC_CONFIG_H
19+
20+
#if !defined(QT_NO_DEBUG)
21+
#define ASYNC_TRACK_DEADLOCK
22+
#endif
23+
24+
#define ASYNC_PROGRESS_WIDGET_UPDATE_TIMEOUT 200
25+
26+
#endif // ASYNC_CONFIG_H

qt-async-lib/qt-async-lib.pro

+7-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ SOURCES += \
1212
values/AsyncValueBase.cpp \
1313
widgets/AsyncWidgetProxy.cpp \
1414
widgets/AsyncWidgetError.cpp \
15-
widgets/AsyncWidgetProgress.cpp
15+
widgets/QtWaitingSpinner/waitingspinnerwidget.cpp \
16+
widgets/AsyncWidgetProgressBar.cpp \
17+
widgets/AsyncWidgetProgressSpinner.cpp
1618

1719
HEADERS += \
1820
values/AsyncValueBase.h \
@@ -25,6 +27,9 @@ HEADERS += \
2527
widgets/AsyncWidgetBase.h \
2628
widgets/AsyncWidget.h \
2729
widgets/AsyncWidgetError.h \
28-
widgets/AsyncWidgetProgress.h
30+
widgets/QtWaitingSpinner/waitingspinnerwidget.h \
31+
Config.h \
32+
widgets/AsyncWidgetProgressBar.h \
33+
widgets/AsyncWidgetProgressSpinner.h
2934

3035
DEFINES += QT_DEPRECATED_WARNINGS

qt-async-lib/values/AsyncValueBase.h

+13
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <QMutex>
2222
#include <QReadWriteLock>
2323
#include <QWaitCondition>
24+
#include <QThread>
2425

2526
enum class ASYNC_VALUE_STATE
2627
{
@@ -43,6 +44,14 @@ class AsyncValueBase : public QObject
4344

4445
void emitStateChanged()
4546
{
47+
#if defined(ASYNC_TRACK_DEADLOCK)
48+
Q_ASSERT(!m_emitThread && "This function is not reenterant");
49+
m_emitThread = QThread::currentThread();
50+
auto atExit = makeAtExitOp([this]{
51+
m_emitThread = nullptr;
52+
});
53+
#endif
54+
4655
emit stateChanged(m_state);
4756
}
4857

@@ -59,6 +68,10 @@ class AsyncValueBase : public QObject
5968
};
6069
Waiter* m_waiter = nullptr;
6170

71+
#if defined(ASYNC_TRACK_DEADLOCK)
72+
QThread* m_emitThread = nullptr;
73+
#endif
74+
6275
template <typename AtExit>
6376
struct AtExitOp
6477
{

qt-async-lib/values/AsyncValueTemplate.h

+12
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ class AsyncValueTemplate : public AsyncValueBase
5656

5757
void moveValue(std::unique_ptr<ValueType> value)
5858
{
59+
#if defined(ASYNC_TRACK_DEADLOCK)
60+
Q_ASSERT(m_emitThread != QThread::currentThread() && "Changing async value from emitted state changed signal is forbidden. Deadlock will happen.");
61+
#endif
62+
5963
Content oldContent;
6064

6165
QMutexLocker writeLocker(&m_writeLock);
@@ -89,6 +93,10 @@ class AsyncValueTemplate : public AsyncValueBase
8993

9094
void moveError(std::unique_ptr<ErrorType> error)
9195
{
96+
#if defined(ASYNC_TRACK_DEADLOCK)
97+
Q_ASSERT(m_emitThread != QThread::currentThread() && "Changing async value from emitted state changed signal is forbidden. Deadlock will happen.");
98+
#endif
99+
92100
Content oldContent;
93101

94102
QMutexLocker writeLocker(&m_writeLock);
@@ -115,6 +123,10 @@ class AsyncValueTemplate : public AsyncValueBase
115123

116124
ProgressType* startProgressMove(std::unique_ptr<ProgressType> progress)
117125
{
126+
#if defined(ASYNC_TRACK_DEADLOCK)
127+
Q_ASSERT(m_emitThread != QThread::currentThread() && "Changing async value from emitted state changed signal is forbidden. Deadlock will happen.");
128+
#endif
129+
118130
Content oldContent;
119131

120132
QMutexLocker writeLocker(&m_writeLock);

qt-async-lib/widgets/AsyncWidget.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "values/AsyncValue.h"
2222
#include "AsyncWidgetBase.h"
2323
#include "AsyncWidgetError.h"
24-
#include "AsyncWidgetProgress.h"
24+
#include "AsyncWidgetProgressBar.h"
2525

2626
template <typename ValueType>
2727
class AsyncWidget : public AsyncWidgetBase<AsyncValue<ValueType>>
@@ -42,7 +42,7 @@ class AsyncWidget : public AsyncWidgetBase<AsyncValue<ValueType>>
4242

4343
QWidget* createProgressWidgetImpl(AsyncProgress& progress, QWidget* parent) override
4444
{
45-
return new AsyncWidgetProgress(progress, parent);
45+
return new AsyncWidgetProgressBar(progress, parent);
4646
}
4747
};
4848

qt-async-lib/widgets/AsyncWidgetError.cpp

-7
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,7 @@ AsyncWidgetError::AsyncWidgetError(const AsyncError& error, QWidget* parent)
2020
: QLabel(parent),
2121
m_error(error)
2222
{
23-
setAutoFillBackground(true);
24-
setFrameStyle(QFrame::Panel | QFrame::Plain);
25-
setLineWidth(1);
2623
setWordWrap(true);
27-
auto _palette = palette();
28-
_palette.setColor(QPalette::Normal, QPalette::Window, Qt::white);
29-
setPalette(_palette);
3024
setAlignment(Qt::AlignCenter);
31-
3225
setText(m_error.text());
3326
}

qt-async-lib/widgets/AsyncWidgetProgress.cpp renamed to qt-async-lib/widgets/AsyncWidgetProgressBar.cpp

+9-15
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
limitations under the License.
1515
*/
1616

17-
#include "AsyncWidgetProgress.h"
17+
#include "AsyncWidgetProgressBar.h"
18+
#include "../Config.h"
1819
#include <QLabel>
1920
#include <QProgressBar>
2021
#include <QPushButton>
@@ -23,17 +24,10 @@
2324
#include <QTimer>
2425
#include <QTimeLine>
2526

26-
AsyncWidgetProgress::AsyncWidgetProgress(AsyncProgress& progress, QWidget* parent)
27+
AsyncWidgetProgressBar::AsyncWidgetProgressBar(AsyncProgress& progress, QWidget* parent)
2728
: QFrame(parent),
2829
m_progress(progress)
2930
{
30-
setAutoFillBackground(true);
31-
setFrameStyle(QFrame::Panel | QFrame::Plain);
32-
setLineWidth(1);
33-
auto _palette = palette();
34-
_palette.setColor(QPalette::Normal, QPalette::Window, Qt::white);
35-
setPalette(_palette);
36-
3731
auto layout = new QVBoxLayout(this);
3832
layout->setSpacing(6);
3933
layout->setContentsMargins(11, 11, 11, 11);
@@ -72,7 +66,7 @@ AsyncWidgetProgress::AsyncWidgetProgress(AsyncProgress& progress, QWidget* paren
7266
m_stop = new QPushButton(this);
7367
m_stop->setText("Stop");
7468
subLayout->addWidget(m_stop);
75-
QObject::connect(m_stop, &QPushButton::clicked, this, &AsyncWidgetProgress::onStopClicked);
69+
QObject::connect(m_stop, &QPushButton::clicked, this, &AsyncWidgetProgressBar::onStopClicked);
7670
}
7771

7872
layout->addLayout(subLayout);
@@ -86,18 +80,18 @@ AsyncWidgetProgress::AsyncWidgetProgress(AsyncProgress& progress, QWidget* paren
8680
}
8781

8882
auto timer = new QTimer(this);
89-
connect(timer, &QTimer::timeout, this, &AsyncWidgetProgress::update);
90-
timer->start(200);
83+
connect(timer, &QTimer::timeout, this, &AsyncWidgetProgressBar::updateContent);
84+
timer->start(ASYNC_PROGRESS_WIDGET_UPDATE_TIMEOUT);
9185

92-
update();
86+
updateContent();
9387
}
9488

95-
void AsyncWidgetProgress::onStopClicked(bool /*checked*/)
89+
void AsyncWidgetProgressBar::onStopClicked(bool /*checked*/)
9690
{
9791
m_progress.requestStop();
9892
}
9993

100-
void AsyncWidgetProgress::update()
94+
void AsyncWidgetProgressBar::updateContent()
10195
{
10296
if (m_progress.isStopRequested())
10397
m_message->setText(m_progress.message()+"(Stopping...)");

0 commit comments

Comments
 (0)