diff --git a/.github/workflows/build_on_pull_request.yml b/.github/workflows/build_on_pull_request.yml
new file mode 100644
index 00000000..047c9458
--- /dev/null
+++ b/.github/workflows/build_on_pull_request.yml
@@ -0,0 +1,64 @@
+# This workflow will run on pull requests
+name: Build on Pull Requests
+on:
+ workflow_dispatch:
+ branches: [main, dev]
+
+ pull_request:
+ branches: [dev, main]
+
+jobs:
+ build:
+ runs-on: windows-2019
+ steps:
+
+ - name: Install Qt
+ uses: jurplel/install-qt-action@v3.3.0
+ with:
+ version: '6.5.3'
+ host: 'windows'
+ target: 'desktop'
+ arch: 'win64_msvc2019_64'
+ dir: 'C:\'
+ install-deps: 'true'
+ modules: 'all'
+ #archives: 'qtbase qtsvg'
+ cache: 'false'
+ cache-key-prefix: 'install-qt-action'
+ setup-python: 'false'
+ tools: 'tools_ninja'
+ set-env: 'true'
+ tools-only: 'false'
+ aqtversion: '==3.1.*'
+ py7zrversion: '==0.20.*'
+ extra: '--external 7z'
+
+ - name: Checkout files
+ uses: actions/checkout@v3
+ with:
+ submodules: recursive
+
+ - name: List current files
+ run: |
+ dir
+
+ - name: Create build directory
+ run: mkdir build
+
+ - name: List Qt directory
+ working-directory: ${{env.Qt6_DIR}}
+ run: |
+ dir
+
+ - uses: TheMrMilchmann/setup-msvc-dev@v3
+ with:
+ arch: x64
+
+ - name: Build
+ env:
+ CMAKE_MODULE_PATH : ${{env.Qt6_Dir}}/lib/cmake/Qt6
+ working-directory: build
+ run: |
+ cmake ../ -DCMAKE_BUILD_TYPE=Release -DQT6_DIR=${{env.Qt6_Dir}} -G CodeBlocks
+ cmake --build .
+
diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml
index 3283c134..e6959164 100644
--- a/.github/workflows/docs_deploy.yml
+++ b/.github/workflows/docs_deploy.yml
@@ -8,18 +8,6 @@ on:
workflow_dispatch:
branches: ["main", "dev"]
-# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
-permissions:
- contents: read
- pages: write
- id-token: write
-
-# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
-# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
-concurrency:
- group: "pages"
- cancel-in-progress: false
-
jobs:
# Build job
build:
diff --git a/.gitignore b/.gitignore
index a6c78627..8f3b334a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,9 @@
/client/resources/translations/*.qm
deploy
+/build-*
+*.user
+
+html
+venv
+doctrees
+CMakeLists.txt.user
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c6a696bb..3556fa78 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,23 +1,23 @@
if (APPLE)
- set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version")
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version")
endif(APPLE)
project(OpenTeraPlus)
-include(CTest)
-enable_testing()
+#include(CTest)
+#enable_testing()
#include(CheckFunctionExists)
#Look for minimum cmake version
-cmake_minimum_required(VERSION 3.0.2)
+cmake_minimum_required(VERSION 3.21)
#DEFINITIONS POLICY, NEW SINCE 3.0.2
cmake_policy(SET CMP0043 NEW)
# Software version
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
-SET(CPACK_PACKAGE_VERSION_MINOR "1")
-SET(CPACK_PACKAGE_VERSION_PATCH "3")
+SET(CPACK_PACKAGE_VERSION_MINOR "2")
+SET(CPACK_PACKAGE_VERSION_PATCH "0")
SET(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
add_definitions(-DOPENTERAPLUS_VERSION="${CPACK_PACKAGE_VERSION}" )
add_definitions(-DOPENTERAPLUS_VERSION_MAJOR="${CPACK_PACKAGE_VERSION_MAJOR}" )
@@ -48,7 +48,7 @@ endif(UNIX AND NOT APPLE)
set(CMAKE_VERBOSE_MAKEFILE ON)
-set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD 17)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
message(STATUS "Using QMAKE: ${QT_QMAKE_EXECUTABLE}")
@@ -67,7 +67,7 @@ add_subdirectory(shared)
add_subdirectory(client)
# Tests
-add_subdirectory(tests)
+#add_subdirectory(tests)
# Readme and other files
add_custom_target(readme SOURCES README.md LICENSE.TXT)
diff --git a/README.md b/README.md
index e2c1f00f..a098ff6f 100755
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ OpenTeraPlus is a client that works with [OpenTera Server](https://github.com/in
## Publication(s)
+* [![DOI](https://joss.theoj.org/papers/10.21105/joss.05497/status.svg)](https://doi.org/10.21105/joss.05497) Létourneau, D., Brière , S., et al., [OpenTera: A Framework for Telehealth Applications](https://doi.org/10.21105/joss.05497), Journal of Open Source Software, vol. 8, no 91, p. 5497 (2023)
* Panchea, A.M., Létourneau, D., Brière, S. et al., [OpenTera: A microservice architecture solution for rapid prototyping of robotic solutions to COVID-19 challenges in care facilities](https://rdcu.be/cHzmf), Health Technol. 12, 583–596 (2022)
## Current Features
diff --git a/README_fr.md b/README_fr.md
new file mode 100644
index 00000000..8bc4230e
--- /dev/null
+++ b/README_fr.md
@@ -0,0 +1,66 @@
+
+
+# OpenTeraPlus
+OpenTeraPlus est un client pour le [Serveur OpenTera](https://github.com/introlab/opentera). Son rôle est d'agir comme un outil général pour gérer une instance d'OpenTera et de fournir certaines fonctionnalités spécifiques à certains services, telles que la Téléréadaptation.
+
+## Auteurs
+
+* Simon Brière, ing. M.Sc.A., Centre de recherche sur le Vieillissement (CDRV), CIUSSS de l'Estrie-CHUS (@sbriere)
+* Dominic Létourneau, ing. M.Sc.A., IntRoLab, Université de Sherbrooke (@doumdi)
+* François Michaud, ing. Ph.D., IntRoLab, Université de Sherbrooke
+* Michel Tousignant, pht, Ph.D., CDRV, Université de Sherbrooke
+
+## Publication(s)
+
+* [![DOI](https://joss.theoj.org/papers/10.21105/joss.05497/status.svg)](https://doi.org/10.21105/joss.05497) Létourneau, D., Brière , S., et al., [OpenTera: A Framework for Telehealth Applications](https://doi.org/10.21105/joss.05497), Journal of Open Source Software, vol. 8, no 91, p. 5497 (2023)
+* Panchea, A.M., Létourneau, D., Brière, S. et al., [OpenTera: A microservice architecture solution for rapid prototyping of robotic solutions to COVID-19 challenges in care facilities](https://rdcu.be/cHzmf), Health Technol. 12, 583–596 (2022)
+
+## Fonctionnalités actuelles
+
+### Aperçu des fonctionnalités
+* Gestion globale du système, incluant les accès utilisateurs - rôles pour sites, projets, appareils, types de séances et services
+* Gestion des participants (patients), incluant l'activation/désactivation, regroupements et tableaux de bord des séances
+* Intégration spécifique pour les services de téléréadaptation et toutes les activités cliniques demandant une séance audio-vidéo adaptée au contexte
+* Gestion des séances, incluant fichiers / données attachées et tests / questionnaires
+
+### Fonctionnalités détaillées
+* Connexion en tant qu'utilisateur
+ * Implémentation de l'accès selon les groupes utilisateurs
+* Gestion des projets et sites
+ * Accès des groupes utilisateurs
+ * Appareils, types de séances et évaluations liées
+ * Services associés
+* Gestion des participants (patients)
+ * Regroupement des participants
+ * Activation / désactivation des participants, liens webs et connexion traditionnelle
+ * Ajout / suppression
+* Gestion des séances
+ * Création de nouvelle séance et édition de séances existantes
+ * Vue calendrier des séances réalisées et planifiées
+ * Affichage des événements de séance
+ * Téléchargement et gestion des fichiers attachés aux séances
+ * Affichage des évaluations attachées aux séances
+* Gestion des appareils
+ * Association d'appareils aux participants
+ * Activation / désactivation d'appareils
+ * Configuration des appareils
+* Gestion des services OpenTera
+ * Édition de la configuration
+* Séances de téléréadaptation
+ * Création et gestion de séances vidéos axées sur la télésanté
+* ... et plus!
+
+# Captures d'écran
+
+
+# Vidéo
+[![OpenTera+ Logiciel Clinique de Télésanté](https://img.youtube.com/vi/FathjoDGlZ0/maxresdefault.jpg)](https://youtu.be/FathjoDGlZ0)
+
+# Licence
+OpenTeraPlus est licencé sous [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html)
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index be3b1957..d1697fd5 100755
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -1,4 +1,4 @@
-find_package(Qt5Core REQUIRED)
+find_package(Qt6Core REQUIRED)
add_subdirectory(resources)
add_subdirectory(src)
diff --git a/client/resources/TeraClient.qrc b/client/resources/TeraClient.qrc
index eb9767a4..21e19d1f 100755
--- a/client/resources/TeraClient.qrc
+++ b/client/resources/TeraClient.qrc
@@ -148,5 +148,6 @@
icons/logs/os_mac.png
icons/logs/os_windows.png
icons/pause.png
+ icons/project_disabled.png
diff --git a/client/resources/icons.txt b/client/resources/icons.txt
index 3d8fa63b..b55b0b3c 100644
--- a/client/resources/icons.txt
+++ b/client/resources/icons.txt
@@ -1,3 +1,13 @@
Logos icons created by Pixel perfect - Flaticon
Logotype icons created by Freepik - Flaticon
-Chrome icons created by Pixel perfect - Flaticon
\ No newline at end of file
+Chrome icons created by Pixel perfect - Flaticon
+Book icons created by max.icons - Flaticon
+Search icons created by Vector Stall - Flaticon
+Filter icons created by designhub - Flaticon
+Loading arrow icons created by Laisa Islam Ani - Flaticon
+Files and folders icons created by riajulislam - Flaticon
+Ui icons created by berkahicon - Flaticon
+Output icons created by Laisa Islam Ani - Flaticon
+Company icons created by Dragon Icons - Flaticon
+Work icons created by Pixel perfect - Flaticon
+Folder icons created by Freepik - Flaticon
\ No newline at end of file
diff --git a/client/resources/icons/config.png b/client/resources/icons/config.png
index df031b75..609880f7 100644
Binary files a/client/resources/icons/config.png and b/client/resources/icons/config.png differ
diff --git a/client/resources/icons/filter.png b/client/resources/icons/filter.png
index 4cd8db61..7f294da9 100755
Binary files a/client/resources/icons/filter.png and b/client/resources/icons/filter.png differ
diff --git a/client/resources/icons/group.png b/client/resources/icons/group.png
index f986d0ad..e0f553c7 100644
Binary files a/client/resources/icons/group.png and b/client/resources/icons/group.png differ
diff --git a/client/resources/icons/group_new.png b/client/resources/icons/group_new.png
index 486195b6..2614dddf 100644
Binary files a/client/resources/icons/group_new.png and b/client/resources/icons/group_new.png differ
diff --git a/client/resources/icons/navtree.png b/client/resources/icons/navtree.png
index 9c7b0522..12df4c87 100644
Binary files a/client/resources/icons/navtree.png and b/client/resources/icons/navtree.png differ
diff --git a/client/resources/icons/password.png b/client/resources/icons/password.png
index 5f807115..55520ba1 100644
Binary files a/client/resources/icons/password.png and b/client/resources/icons/password.png differ
diff --git a/client/resources/icons/project-icon.png b/client/resources/icons/project-icon.png
index af119d79..c61c4be1 100644
Binary files a/client/resources/icons/project-icon.png and b/client/resources/icons/project-icon.png differ
diff --git a/client/resources/icons/project.png b/client/resources/icons/project.png
index b9dc7879..5303a70f 100644
Binary files a/client/resources/icons/project.png and b/client/resources/icons/project.png differ
diff --git a/client/resources/icons/project_disabled.png b/client/resources/icons/project_disabled.png
new file mode 100644
index 00000000..5488707d
Binary files /dev/null and b/client/resources/icons/project_disabled.png differ
diff --git a/client/resources/icons/project_new.png b/client/resources/icons/project_new.png
index 75a4a3ff..b2f76bc6 100644
Binary files a/client/resources/icons/project_new.png and b/client/resources/icons/project_new.png differ
diff --git a/client/resources/icons/refresh.png b/client/resources/icons/refresh.png
index 5001f7de..bfaf2fe6 100755
Binary files a/client/resources/icons/refresh.png and b/client/resources/icons/refresh.png differ
diff --git a/client/resources/icons/search.png b/client/resources/icons/search.png
index 0e988c4b..ba937bc9 100755
Binary files a/client/resources/icons/search.png and b/client/resources/icons/search.png differ
diff --git a/client/resources/icons/server.png b/client/resources/icons/server.png
index 0f5785a6..407379ec 100644
Binary files a/client/resources/icons/server.png and b/client/resources/icons/server.png differ
diff --git a/client/resources/icons/site-icon.png b/client/resources/icons/site-icon.png
index 31968fc1..37668af0 100644
Binary files a/client/resources/icons/site-icon.png and b/client/resources/icons/site-icon.png differ
diff --git a/client/resources/icons/site.png b/client/resources/icons/site.png
index 2b33e4f2..8a290b22 100644
Binary files a/client/resources/icons/site.png and b/client/resources/icons/site.png differ
diff --git a/client/resources/icons/unlock.png b/client/resources/icons/unlock.png
index 8c804541..99b0f1d5 100755
Binary files a/client/resources/icons/unlock.png and b/client/resources/icons/unlock.png differ
diff --git a/client/resources/stylesheet.qss b/client/resources/stylesheet.qss
index 41cc5939..51cbfc93 100644
--- a/client/resources/stylesheet.qss
+++ b/client/resources/stylesheet.qss
@@ -10,35 +10,65 @@ QWidget{
/*
QToolBar
*/
-QToolBar {background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(125,125,125), stop: 1.0 rgb(80,80,80)); spacing: 5px;}
+QToolBar {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(125,125,125), stop: 1.0 rgb(80,80,80));
+ spacing: 5px;
+}
/*
QDockWidget
*/
-QDockWidget{titlebar-close-icon: url(:/pictures/close-red.png);font:bold large Arial; color:rgb(200,200,198);}
-QDockWidget::title{border: darkgray solid 2px;text-align:left;background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(64,64,64), stop: 1.0 rgb(40,40,40));padding-left:5px}
-QDockWidget::close-button {icon-size:14px;background: rgba(0,0,0,0);}
+QDockWidget{
+ titlebar-close-icon: url(:/pictures/close-red.png);
+ font:bold large Arial;
+ color:rgb(200,200,198);
+}
+QDockWidget::title{
+ text-align:left;
+ background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(64,64,64), stop: 1.0 rgb(40,40,40));
+ padding-left:5px
+}
+QDockWidget::close-button {
+ icon-size:14px;
+ background: rgba(0,0,0,0);
+}
+QWidget#dockWidgetContents{
+ border: 0px solid transparent;
+}
/*
QStatusBar
*/
-QStatusBar::item{border: 1px transparent black;}
+QStatusBar::item{
+ border: 1px transparent black;
+}
/*
QMainWindow
*/
-QMainWindow::separator { background: rgb(29,29,29);width: 5px;height: 5px;}
-QMainWindow::separator:hover {background: black;}
-QMainWindow{background: #2c3338; }
+QMainWindow::separator {
+ background: rgb(60,60,60);
+ width: 2px;
+ height: 5px;
+}
+
+QMainWindow::separator:hover {
+ background: rgb(120,120,120);
+}
+
+QMainWindow{
+ background: #2c3338;
+}
/*
QFrame
*/
-QFrame{background-color:rgba(29,29,29,50%);}
-
+QFrame{
+ background-color:rgba(0,0,0,50%);
+}
/*
TabWidget
@@ -54,12 +84,19 @@ QTabWidget::tab-bar {
}
QTableWidget::tab, QHeaderView::section {
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(128,128,140,50%), stop: 1.0 rgba(100,100,140,25%));
- border: 2px solid rgba(128,128,140,50%);
+ background: rgba(128,128,140,50%); /*qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(128,128,140,50%), stop: 1.0 rgba(100,100,140,25%));*/
+ border: 1px solid rgba(128,128,140,50%);
padding: 2px;
min-height:25px;
}
+QTableWidget {
+ gridline-color: rgba(128,128,140,50%);
+}
+
+QHeaderView{
+ background-color: transparent;
+}
QTableWidget QTableCornerButton::section {
background-color: rgb(64, 65, 74);
@@ -77,30 +114,55 @@ QHeaderView::up-arrow {
width: 12px;
}
+QTabBar{
+ qproperty-drawBase: 0;
+}
+
QTabBar::tab{
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(128,128,140,50%), stop: 1.0 rgba(100,100,140,25%));
- border: 2px solid rgba(128,128,140,50%);
- padding: 2px;
- min-height:25px;
+ border: 1px solid rgba(10, 100, 174, 50%);
+ background-color: #FF17365D;
+ padding: 5px;
+ min-height: 25px;
color: white;
+ margin: 1px;
+}
+
+QMainWindow QTabBar::tab:left{
+ min-height: 120px;
+}
+
+TeraForm QTabBar::tab{
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(128,128,140,50%), stop: 1.0 rgba(100,100,140,25%));
+ min-height: 15px;
+ border: 1px solid rgba(128,128,140,50%);
+}
+
+TeraForm QTabBar::tab:top{
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+}
+
+TeraForm QTabBar::tab:selected{
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(220,220,220,70%), stop: 1.0 rgba(255,255,255,50%));
+ color: black;
}
QTabBar::tab:top{
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
+ border-top-left-radius: 10px;
+ border-top-right-radius: 10px;
border-bottom: 0px;
}
QTabBar::tab:left{
- min-height:120px;
- border-bottom-left-radius: 4px;
- border-top-left-radius: 4px;
+ border-top-left-radius: 10px;
+ border-bottom-left-radius: 10px;
+ /*min-height:120px;*/
border-right: 0px;
}
QTabBar::tab:selected, QTabBar::tab:hover {
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(220,220,220,70%), stop: 1.0 rgba(255,255,255,50%));
- color: black;
+ background-color: rgba(10, 100, 174, 100%);
+ color: white;
}
QTabBar::tab:selected {
@@ -108,9 +170,9 @@ QTabBar::tab:selected {
border-bottom-color:rgba(128,128,140,60%);
}
-QTabBar::tab:!selected {
+/*QTabBar::tab:!selected {
margin-top: 2px;
-}
+}*/
/*
QGroupBox
@@ -147,9 +209,6 @@ QToolBox{
}
QToolBox::tab {
- /*background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0,5,45,50%), stop: 0.2 rgba(0,64,128,50%), stop:1 rgba(0,5,45,50%));
- border-radius: 5px;
- color: darkgray;*/
border-top-left-radius: 15px;
border-top-right-radius: 15px;
padding: 5px;
@@ -201,8 +260,12 @@ QLabel {
QTreeWidget
*/
QTreeWidget, QTableWidget{
- selection-background-color: rgba(255,255,255,50%);/*rgba(0,5,45,50%)*/;
- selection-color: black/*lightblue*/;
+ selection-background-color: rgba(23,54,93,70%);
+ selection-color: white;
+}
+
+QTreeWidget::item::selected{
+ background-color: rgba(23,54,93,70%);
}
QTreeWidget#treeNavigator {
@@ -234,7 +297,6 @@ QLineEdit:!enabled, QSpinBox:!enabled, QTextEdit:!enabled, QDateTimeEdit:!enable
background-color: rgba(0,0,0,0%);
color:rgba(255,255,255,80%);
padding-left: 0px;
- color: white;
}
@@ -254,20 +316,29 @@ QPlainTextEdit {
/*
QListWidget
*/
-QListWidget {
+
+QListView {
color: white;
- selection-background-color: rgba(0,5,45,50%);
- selection-color: cyan;
+ outline: 0;
+}
+
+QListView::item{
+ /*min-height: 24px;*/
+}
+
+QListView::item:selected {
+ color: cyan;
+ background-color: rgba(0,5,145,50%);
}
+QListView::item:hover {
+ color: white;
+ background-color: rgba(23,54,93,50%);
+}
/*
QTextEdit, See QLineEdit
*/
-/*QTextEdit {
- background-color: rgba(255,255,255,50%);
- color: white;
-}*/
/*
QComboBox
@@ -310,12 +381,11 @@ QComboBox::item{
color: white;
}
-
/*
QPushButton
*/
QPushButton{
- color:white;
+ color: white;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #173448, stop: 1 #295d80);/*qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 black, stop: 0.2 #173448, stop:1 black);*/
border: 2px solid #15679e;
border-radius: 5px;
@@ -354,9 +424,7 @@ QPushButton[checkable=true]:!checked{
*/
QToolButton{
color:white;
- /* background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 black, stop: 0.2 rgb(200,200,200), stop:1 black); */
background-color: transparent;
- /*border: 2px solid rgb(96, 96, 96);*/
border: 0px transparent;
border-radius: 5px;
min-height: 25px;
@@ -372,9 +440,7 @@ QToolButton:hover{
QToolButton[checkable=true]:!checked{
color:red;
- /*background-color:rgba(180,0,0,50%);*/
background-color:rgba(100,100,100,50%);
- /*border: 2px solid rgb(180,0,0);*/
border: 2px solid rgb(100,100,100);
}
@@ -400,7 +466,7 @@ QCheckBox::indicator {
height: 32px;
}
-QListWidget::indicator, QTreeWidget::indicator, QTableWidget::indicator {
+QListView::indicator, QTreeWidget::indicator, QTableWidget::indicator {
width: 20px;
height: 20px;
}
@@ -408,14 +474,14 @@ QListWidget::indicator, QTreeWidget::indicator, QTableWidget::indicator {
QCheckBox::indicator:unchecked:!enabled {
image: url(://controls/check_off_disabled.png);
}
-QListWidget::indicator:unchecked:!enabled, QTreeWidget::indicator:unchecked:!enabled, QTableWidget::indicator:unchecked:!enabled{
+QListView::indicator:unchecked:!enabled, QTreeWidget::indicator:unchecked:!enabled, QTableWidget::indicator:unchecked:!enabled{
image: url(://controls/check2_off_disabled.png);
}
QCheckBox::indicator:checked:!enabled{
image: url(://controls/check_on_disabled.png);
}
-QListWidget::indicator:checked:!enabled, QTreeWidget::indicator:checked:!enabled, QTableWidget::indicator:checked:!enabled {
+QListView::indicator:checked:!enabled, QTreeWidget::indicator:checked:!enabled, QTableWidget::indicator:checked:!enabled {
image: url(://controls/check2_on_disabled.png);
}
@@ -429,7 +495,7 @@ QListWidget::indicator:unchecked, QTreeWidget::indicator:unchecked, QTableWidget
QCheckBox::indicator:checked{
image: url(://controls/check_on.png);
}
-QListWidget::indicator:checked, QTreeWidget::indicator:checked, QTableWidget::indicator:checked{
+QListView::indicator:checked, QTreeWidget::indicator:checked, QTableWidget::indicator:checked{
image: url(://controls/check2_on.png);
}
@@ -462,10 +528,14 @@ QRadioButton:!checked{color:red;background-color:rgba(0,0,0,0%);}
QMenu {
icon-size: 22px;
font-size: 10pt;
+ background-color: #8817365D;
+ border: 1px solid gray;
+ border-radius: 2px;
+ padding: 4px;
}
QMenu::item{
- background: black;
+
}
QMenu::item:selected{
@@ -476,48 +546,65 @@ QMenu::item:selected{
QCalendarWidget
*/
-QCalendarWidget QWidget#qt_calendar_navigationbar { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop: 0 #cccccc, stop: 1 #333333); }
- QCalendarWidget QToolButton {
+/*QCalendarWidget QToolButton {
height: 20px;
color: white;
font-size: 12px;
- font-weight: bold;
- icon-size: 20px, 20px;
+ font-weight: bold;
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop: 0 #cccccc, stop: 1 #333333);
- }
+}
+
QCalendarWidget QMenu {
-left: 20px;
-color: white;
-font-size: 12px;
-background-color: rgb(100, 100, 100);
+ left: 20px;
+ color: white;
+ font-size: 12px;
+ background-color: rgb(100, 100, 100);
}
QCalendarWidget QSpinBox {
-font-size:12px;
-color: white;
-background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop: 0 #cccccc, stop: 1 #333333);
-selection-background-color: rgb(136, 136, 136);
-selection-color: rgb(255, 255, 255);
+ font-size:12px;
+ color: white;
+ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop: 0 #cccccc, stop: 1 #333333);
+ selection-background-color: rgb(136, 136, 136);
+ selection-color: rgb(255, 255, 255);
+}
+
+QCalendarWidget QSpinBox::up-button {
+ subcontrol-origin: border;
+ subcontrol-position: top right;
}
-QCalendarWidget QSpinBox::up-button { subcontrol-origin: border; subcontrol-position: top right; }
-QCalendarWidget QSpinBox::down-button {subcontrol-origin: border; subcontrol-position: bottom right; }
-QCalendarWidget QSpinBox::up-arrow { width:16px; height:16px; }
-QCalendarWidget QSpinBox::down-arrow { width:16px; height:16px; }
+QCalendarWidget QSpinBox::down-button {
+ subcontrol-origin: border;
+ subcontrol-position: bottom right;
+}
+
+QCalendarWidget QSpinBox::up-arrow {
+ width:16px;
+ height:16px;
+}
-QCalendarWidget QWidget { alternate-background-color: #0d5ca6; }
+QCalendarWidget QSpinBox::down-arrow {
+ width:16px;
+ height:16px;
+}
+*/
+QCalendarWidget QWidget {
+ alternate-background-color: #0d5ca6;
+}
QCalendarWidget QAbstractItemView:enabled
{
-font-size:12px;
-color: rgb(180, 180, 180);
-background-color: black;
-selection-background-color: rgb(0,0,0);
-selection-color: rgb(0, 255, 0);
+ font-size:12px;
+ color: rgb(180, 180, 180);
+ background-color: black;
+ selection-background-color: rgb(0,0,0);
+ selection-color: rgb(0, 255, 0);
}
-
-QCalendarWidget QAbstractItemView:disabled { color: rgb(64, 64, 64); }
+QCalendarWidget QAbstractItemView:disabled {
+ color: rgb(64, 64, 64);
+}
/* QProgressBar */
QProgressBar{
@@ -566,7 +653,7 @@ QLabel#lblTitle{
color: cyan;
}
-QLabel#lblWarning{
+QLabel#lblWarning, QLabel#lblWarning2{
font-weight: bold;
font-size: 14px;
color: orange;
@@ -577,15 +664,24 @@ QLabel#lblWarning{
QFrame#frameLogos{background-color:rgba(200,200,200,100%);}
QLabel#lblMessage{color:white;}
QFrame#frameMessage{background-color: transparent;}
+QFrame#frameButtons{background-color:rgba(29,29,29,50%);}
/* Customizations for MainWindow */
QMainWindow{background-image: url(://TeRA_Background.png); background-color: #2c3338;}
QWidget#toolsWidget,QWidget#InToolsWidget{background-color:rgba(0,128,200,20%);}
-QWidget#docketTopWidget{background-color: #2c3338;}
-QFrame#frameMenu,QFrame#frameVideo{border: 1px solid rgba(150,150,150,50%);}
+QWidget#dockerTopWidget{background-color: #2c3338;}
+
+QFrame#frameMenu, QFrame#frameVideo{
+ border: 1px solid rgba(150,150,150,50%);
+}
+QWidget#tabProjectNavigator, QWidget#tabOnline, QWidget#tabSearch{
+ border: 1px solid rgba(150,150,150,50%);
+ border-radius: 1px;
+}
QFrame#frameMessages{background-color:rgba(255,0,0,50%); border-radius:5px;}
QToolButton#btnVideoSwitch, QToolButton#btnLog {color: white; min-height: 35px; background-color: qlineargradient(spread:reflect, x1:0.220183, y1:0.745192, x2:1, y2:0, stop:0.201835 rgba(0, 0, 0, 255), stop:0.880734 rgba(255, 255, 255, 255), stop:1 rgba(189, 189, 189, 255)); border-radius: 5px;}
+
/* Red buttons */
QPushButton#btnLogout {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #8f1010, stop: 1 #cc1616);/*qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgba(140,10,10,100%), stop: 0.2 rgba(45,5,0,100%), stop:1 rgba(140,10,10,100%));*/
@@ -621,18 +717,20 @@ QPushButton#btnNewSession:disabled, QPushButton#btnStartSession:disabled {
}
QPushButton#btnEditUser,QPushButton#btnConfig {
- background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(100,100,100,100%), stop: 1 rgba(148,148,148,100%)); /*rgba(100,100,100,50%); */
+ background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 rgba(100,100,100,100%), stop: 1 rgba(148,148,148,100%));
border: 1px solid rgba(148,148,148,100%);
min-width: 0px;
}
-QPushButton#btnEditUser::hover, QPushButton#btnConfig::hover{
- color:black;
+
+QPushButton#btnEditUser:hover,QPushButton#btnConfig:hover{
+ color: black;
}
-QToolButton#btnVideo:!checked, QToolButton#btnLog:!checked, QToolButton#btnFilterActive:!checked, QToolButton#btnSearch:!checked{
+QToolButton#btnVideo:!checked, QToolButton#btnLog:!checked, QToolButton#btnFilterActive:!checked, QToolButton#btnSearch:!checked, QToolButton#btnAdvanced:!checked{
color:white;
background-color: transparent;
- border: 1px solid rgb(120,120,120);
+ /*border: 1px solid rgb(120,120,120);*/
+ border: 0px solid transparent;
border-radius: 5px;
}
@@ -642,7 +740,7 @@ QToolButton#btnLog:!checked, QToolButton#btnInSessionInfos:!checked, QToolButton
border: 0px;
}
-QToolButton#btnVideo:checked, QToolButton#btnLog:checked, QToolButton#btnInSessionInfos:checked, QToolButton#btnSearch:checked, QToolButton#btnFilterActive:checked, QToolButton#btnPause:checked{
+QToolButton#btnVideo:checked, QToolButton#btnLog:checked, QToolButton#btnInSessionInfos:checked, QToolButton#btnSearch:checked, QToolButton#btnFilterActive:checked, QToolButton#btnPause:checked, QToolButton#btnAdvanced:checked{
color:black;
background-color: gray;
/*border: 2px solid white;*/
@@ -698,7 +796,7 @@ QToolButton#btnRandomPass{
}
/* Customizations for SiteWidget */
-QLabel#lblInherited{
+QLabel#lblInherited, QLabel#lblAdminTestTypes, QLabel#lblAdminSessionTypes{
font-weight: bold;
font-size: 12px;
color: orange;
@@ -740,7 +838,7 @@ QPushButton#btnFilterSessionsTypes[checkable=true]:!checked{
QPushButton#btnManageInvitees:checked, QPushButton#btnUpcomingSessions:checked, QPushButton#btnRecentParticipants:checked, QPushButton#btnAttention:checked,
QPushButton#btnAdvancedConfig:checked{
color:white;
- background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 black, stop: 0.2 rgb(100,100,100), stop:1 black);
+ background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 black, stop: 0.2 rgb(10,100,174), stop:1 black);
border: 1px solid rgb(96, 96, 96);
border-radius: 5px;
text-align: left;
@@ -766,7 +864,7 @@ QPushButton#btnUpcomingSessions[checkable=true]:!checked,
QPushButton#btnRecentParticipants[checkable=true]:!checked, QPushButton#btnAttention[checkable=true]:!checked,
QPushButton#btnAdvancedConfig[checkable=true]:!checked{
color:white;
- background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgb(100,100,100), stop: 0.2 black, stop:1 rgb(100,100,100));
+ background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgb(23,54,93), stop: 0.2 black, stop:1 rgb(23,54,93));
border: 2px solid transparent/*rgb(145, 145, 145)*/;
border-radius: 5px;
text-align: left;
@@ -791,7 +889,7 @@ QTreeWidget#treeOnline{
/* Customizations for DashboardWidget */
QFrame#frameAttention, QFrame#frameRecent, QFrame#frameUpcomingSessions{
- background-color: rgba(100,100,100, 50%);
+ /*background-color: rgba(100,100,100, 50%);*/
}
QLabel#lblNoUpcomingSessions, QLabel#lblNoRecentParticipants, QLabel#lblAttention{
@@ -799,6 +897,7 @@ QLabel#lblNoUpcomingSessions, QLabel#lblNoRecentParticipants, QLabel#lblAttentio
font-size: 12px;
color: orange;
background-color: black;
+ border-radius: 15px;
}
/* Customizations for ResultMessageWidget */
@@ -817,6 +916,10 @@ QTreeWidget#treeAssets {
/* Customizations for InSessionWidget */
QPushButton#btnDefaultPath, QPushButton#btnBrowseSavePath{
- max-width: 80px;
- min-width: 80px;
+ max-width: 80px;
+ min-width: 80px;
+}
+
+QWidget#line{
+ background-color: #808080;
}
diff --git a/client/src/CMakeLists.txt b/client/src/CMakeLists.txt
index 16d32106..70dac8be 100755
--- a/client/src/CMakeLists.txt
+++ b/client/src/CMakeLists.txt
@@ -1,10 +1,20 @@
-find_package(Qt5Core REQUIRED)
-find_package(Qt5WebEngine REQUIRED)
-find_package(Qt5WebEngineWidgets REQUIRED)
-find_package(Qt5Multimedia REQUIRED)
-find_package(Qt5WebSockets REQUIRED)
-find_package(Qt5Network REQUIRED)
-find_package(Qt5LinguistTools REQUIRED)
+find_package(Qt6Core REQUIRED)
+
+if(NOT DEFINED OPENTERA_WEBASSEMBLY)
+ find_package(Qt6 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets)
+endif()
+
+if (MSVC)
+ add_definitions(
+ /wd4910 # Ignore export warnings (C4910) with MSVC
+ /wd4661 # Ignore no suitable definition for explicit template (C4661)
+ /wd4251 # Ignore needs to have dll-interface
+ /wd4146 # Ignore unary minus operator applied to unsigned type, result still unsigned
+ /wd4267 # Ignore size_t to uint32_t conversion warnings
+ )
+endif (MSVC)
+
+find_package(Qt6 REQUIRED COMPONENTS LinguistTools Multimedia WebSockets Network)
# Drivers first
add_subdirectory(drivers)
@@ -21,9 +31,10 @@ set(headers
data/TransferringFile.h
data/UploadingFile.h
data/IconMenuDelegate.h
+ # Librairies
+ libs/AudioVideoUtils.h
# Main Windows
main/MainWindow.h
- main/MainKitWindow.h
# Managers
managers/ConfigManagerClient.h
managers/ComManager.h
@@ -33,12 +44,7 @@ set(headers
managers/AssetComManager.h
# Dialogs
dialogs/LoginDialog.h
- dialogs/StartSessionDialog.h
- dialogs/SessionLobbyDialog.h
- dialogs/JoinSessionDialog.h
dialogs/EmailInviteDialog.h
- dialogs/AboutDialog.h
- dialogs/AboutDialogPage.h
dialogs/GeneratePasswordDialog.h
dialogs/PasswordStrengthDialog.h
dialogs/TransferProgressDialog.h
@@ -74,21 +80,10 @@ set(headers
services/BaseServiceWidget.h
services/BaseServiceToolsWidget.h
services/BaseServiceSetupWidget.h
- services/VideoRehabService/ScreenController.h
- services/VideoRehabService/VideoRehabWidget.h
- services/VideoRehabService/VideoRehabWebPage.h
- services/VideoRehabService/VideoRehabSetupWidget.h
- services/VideoRehabService/VideoRehabToolsWidget.h
- services/VideoRehabService/VideoRehabVirtualCamSetupDialog.h
- services/VideoRehabService/VideoRehabPTZDialog.h
- services/VideoRehabService/WebSocket/SharedObject.h
- services/VideoRehabService/WebSocket/WebSocketClientWrapper.h
- services/VideoRehabService/WebSocket/WebSocketTransport.h
services/DanceService/DanceConfigWidget.h
services/DanceService/DanceWebAPI.h
services/DanceService/DanceComManager.h
# Widgets
- widgets/InSessionWidget.h
widgets/SessionInviteWidget.h
widgets/OnlineManagerWidget.h
widgets/ClickableLabel.h
@@ -106,13 +101,40 @@ set(headers
widgets/QRWidget.h
widgets/LogViewWidget.h
widgets/SessionsListWidget.h
- # Kits
- kit/KitConfigDialog.h
- kit/KitConfigManager.h
- kit/KitInSessionDialog.h
- kit/KitVideoRehabWidget.h
+
)
+#Additional headers not for WebAssembly
+if(NOT DEFINED OPENTERA_WEBASSEMBLY)
+ set(headers ${headers}
+ # Dialogs
+ dialogs/StartSessionDialog.h
+ dialogs/SessionLobbyDialog.h
+ dialogs/JoinSessionDialog.h
+ dialogs/AboutDialog.h
+ dialogs/AboutDialogPage.h
+ # Widgets
+ widgets/InSessionWidget.h
+ # Services
+ services/VideoRehabService/ScreenController.h
+ services/VideoRehabService/VideoRehabWidget.h
+ services/VideoRehabService/VideoRehabWebPage.h
+ services/VideoRehabService/VideoRehabSetupWidget.h
+ services/VideoRehabService/VideoRehabToolsWidget.h
+ services/VideoRehabService/VideoRehabVirtualCamSetupDialog.h
+ services/VideoRehabService/VideoRehabPTZDialog.h
+ services/VideoRehabService/WebSocket/SharedObject.h
+ services/VideoRehabService/WebSocket/WebSocketClientWrapper.h
+ services/VideoRehabService/WebSocket/WebSocketTransport.h
+ # Kits
+ kit/KitConfigDialog.h
+ kit/KitConfigManager.h
+ kit/KitInSessionDialog.h
+ kit/KitVideoRehabWidget.h
+ main/MainKitWindow.h
+ )
+endif()
+
set(srcs
main.cpp
ClientApp.cpp
@@ -125,9 +147,10 @@ set(srcs
data/TransferringFile.cpp
data/UploadingFile.cpp
data/IconMenuDelegate.cpp
+ # Librairies
+ libs/AudioVideoUtils.cpp
# Main Windows
main/MainWindow.cpp
- main/MainKitWindow.cpp
# Managers
managers/ConfigManagerClient.cpp
managers/ComManager.cpp
@@ -140,17 +163,12 @@ set(srcs
dialogs/DeviceAssignDialog.cpp
dialogs/TransferProgressDialog.cpp
dialogs/BaseDialog.cpp
- dialogs/StartSessionDialog.cpp
- dialogs/SessionLobbyDialog.cpp
- dialogs/JoinSessionDialog.cpp
dialogs/EmailInviteDialog.cpp
- dialogs/AboutDialog.cpp
- dialogs/AboutDialogPage.cpp
dialogs/GeneratePasswordDialog.cpp
dialogs/PasswordStrengthDialog.cpp
dialogs/CleanUpDialog.cpp
dialogs/FileUploaderDialog.cpp
- dialogs/QRCodeDialog.cpp
+ dialogs/QRCodeDialog.cpp
# Editors
editors/DataEditorWidget.cpp
editors/DataListWidget.cpp
@@ -171,7 +189,6 @@ set(srcs
editors/UserGroupWidget.cpp
editors/UserSummaryWidget.cpp
editors/UserWidget.cpp
-
# Wizards
wizards/UserWizard.cpp
wizards/BaseWizard.cpp
@@ -179,16 +196,6 @@ set(srcs
services/BaseServiceWidget.cpp
services/BaseServiceToolsWidget.cpp
services/BaseServiceSetupWidget.cpp
- services/VideoRehabService/ScreenController.cpp
- services/VideoRehabService/VideoRehabWidget.cpp
- services/VideoRehabService/VideoRehabWebPage.cpp
- services/VideoRehabService/VideoRehabSetupWidget.cpp
- services/VideoRehabService/VideoRehabToolsWidget.cpp
- services/VideoRehabService/VideoRehabVirtualCamSetupDialog.cpp
- services/VideoRehabService/VideoRehabPTZDialog.cpp
- services/VideoRehabService/WebSocket/SharedObject.cpp
- services/VideoRehabService/WebSocket/WebSocketClientWrapper.cpp
- services/VideoRehabService/WebSocket/WebSocketTransport.cpp
services/DanceService/DanceConfigWidget.cpp
services/DanceService/DanceComManager.cpp
# Widgets
@@ -197,7 +204,6 @@ set(srcs
widgets/NotificationWindow.cpp
widgets/ConfigWidget.cpp
widgets/HistoryCalendarWidget.cpp
- widgets/InSessionWidget.cpp
widgets/SessionInviteWidget.cpp
widgets/OnlineManagerWidget.cpp
widgets/ClickableLabel.cpp
@@ -210,13 +216,40 @@ set(srcs
widgets/QRWidget.cpp
widgets/LogViewWidget.cpp
widgets/SessionsListWidget.cpp
- # Kits
- kit/KitConfigDialog.cpp
- kit/KitConfigManager.cpp
- kit/KitInSessionDialog.cpp
- kit/KitVideoRehabWidget.cpp
)
+#Additional srcs not for WebAssembly
+if(NOT DEFINED OPENTERA_WEBASSEMBLY)
+ set(srcs ${srcs}
+ # Dialogs
+ dialogs/StartSessionDialog.cpp
+ dialogs/SessionLobbyDialog.cpp
+ dialogs/JoinSessionDialog.cpp
+ dialogs/AboutDialog.cpp
+ dialogs/AboutDialogPage.cpp
+ # Widgets
+ widgets/InSessionWidget.cpp
+ # Services
+ services/VideoRehabService/ScreenController.cpp
+ services/VideoRehabService/VideoRehabWidget.cpp
+ services/VideoRehabService/VideoRehabWebPage.cpp
+ services/VideoRehabService/VideoRehabSetupWidget.cpp
+ services/VideoRehabService/VideoRehabToolsWidget.cpp
+ services/VideoRehabService/VideoRehabVirtualCamSetupDialog.cpp
+ services/VideoRehabService/VideoRehabPTZDialog.cpp
+ services/VideoRehabService/WebSocket/SharedObject.cpp
+ services/VideoRehabService/WebSocket/WebSocketClientWrapper.cpp
+ services/VideoRehabService/WebSocket/WebSocketTransport.cpp
+ # Kits
+ kit/KitConfigDialog.cpp
+ kit/KitConfigManager.cpp
+ kit/KitInSessionDialog.cpp
+ kit/KitVideoRehabWidget.cpp
+ main/MainKitWindow.cpp
+ )
+endif()
+
+
SET(uis
# Main Windows
main/MainWindow.ui
@@ -287,31 +320,34 @@ SET(qrcs
)
#Generate .h files from the .ui files
-QT5_WRAP_UI(moc_uis ${uis})
+QT6_WRAP_UI(moc_uis ${uis})
#This will generate moc_* for Qt
-QT5_WRAP_CPP(moc_srcs ${headers})
+QT6_WRAP_CPP(moc_srcs ${headers})
# generate rules for building source files from the resources
-QT5_ADD_RESOURCES(client_qrc ${qrcs})
+QT6_ADD_RESOURCES(client_qrc ${qrcs})
+
+
set(translation_files_srcs
- ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts
- ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts
+ ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts
+ ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts
)
+
#Translation files, this is done manually to avoid removing the file when doing make clean
# Add -noobsolete parameter to remove obsoleted translations
add_custom_target(openteraplus_en_ts
- COMMAND ${Qt5_LUPDATE_EXECUTABLE} -target-language en ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} -ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DEPENDS ${moc_uis}
+ COMMAND ${Qt6_LUPDATE_EXECUTABLE} -target-language en ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} -ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${moc_uis}
)
add_custom_target(openteraplus_fr_ts
- COMMAND ${Qt5_LUPDATE_EXECUTABLE} -target-language fr ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} -ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DEPENDS ${moc_uis}
+ COMMAND ${Qt6_LUPDATE_EXECUTABLE} -target-language fr ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} -ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${moc_uis}
)
#set qm files output directory
@@ -321,9 +357,9 @@ set_source_files_properties(${translation_files_srcs} PROPERTIES OUTPUT_LOCATION
add_custom_target(translations DEPENDS openteraplus_en_ts openteraplus_fr_ts)
add_custom_target(translation_files SOURCES ${translation_files_srcs})
-
#Generate qm files from .ts files
-qt5_add_translation(qm_files ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts)
+qt6_add_translation(qm_files ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts)
+
message(STATUS "qm_files : ${qm_files}")
@@ -334,11 +370,22 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/editors
${CMAKE_CURRENT_BINARY_DIR}
- # DL Temporary test for virtual cameras
${VIRTUAL_CAMERA_INCLUDES}
${PTZ_DRIVERS_INCLUDES}
${AVKYS_INCLUDES}
)
+if(WIN32)
+ set (OPENTERA_OS_LIBS
+ strmiids
+ uuid
+ ole32
+ oleaut32
+ shell32
+ )
+else()
+ set (OPENTERA_OS_LIBS
+ )
+endif()
# Application icon
SET(icon openteraico.rc)
@@ -357,13 +404,22 @@ set(ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${MACOSX_BUNDLE_ICON_FILE}")
# create an executable file named "OpenTeraPlus" from the source files
# Put qrc files after qm files
-add_executable(OpenTeraPlus MACOSX_BUNDLE WIN32 ${icon} ${srcs} ${headers} ${moc_srcs} ${moc_uis} ${ICON_PATH} ${qm_files} ${client_qrc})
-# qt5_use_modules(TeraClient Core Network Multimedia WebSockets WebEngine WebEngineWidgets WebSockets)
+if(NOT DEFINED OPENTERA_WEBASSEMBLY)
+ add_executable(OpenTeraPlus MACOSX_BUNDLE WIN32 ${icon} ${srcs} ${headers} ${moc_srcs} ${moc_uis} ${ICON_PATH} ${qm_files} ${client_qrc})
+else()
+ qt_add_executable(OpenTeraPlus ${icon} ${srcs} ${headers} ${moc_srcs} ${moc_uis} ${ICON_PATH} ${qm_files} ${client_qrc})
+endif()
+
# Linking with Qt libraries and others
-target_link_libraries(OpenTeraPlus ${OPENTERA_SHARED_LIBS} ${OPENTERA_MESSAGES_LIBS} Qt5::Core Qt5::Network Qt5::Multimedia Qt5::WebSockets Qt5::WebEngine Qt5::WebEngineWidgets)
-target_link_libraries(OpenTeraPlus ${VIRTUAL_CAMERA_LIBS})
-target_link_libraries(OpenTeraPlus ${PTZ_DRIVERS_LIBS})
+target_link_libraries(OpenTeraPlus PRIVATE ${OPENTERA_SHARED_LIBS} ${OPENTERA_MESSAGES_LIBS} ${OPENTERA_OS_LIBS} Qt6::Core Qt6::Network Qt6::Multimedia Qt6::WebSockets)
+
+if(NOT DEFINED OPENTERA_WEBASSEMBLY)
+ target_link_libraries(OpenTeraPlus PRIVATE Qt6::WebEngineCore Qt6::WebEngineWidgets)
+endif()
+
+target_link_libraries(OpenTeraPlus PRIVATE ${VIRTUAL_CAMERA_LIBS})
+target_link_libraries(OpenTeraPlus PRIVATE ${PTZ_DRIVERS_LIBS})
set_target_properties(OpenTeraPlus PROPERTIES
@@ -385,15 +441,14 @@ set_source_files_properties(${ICON_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION "Res
if (APPLE)
# Mac bundles...
# Install targets
- install(TARGETS OpenTeraPlus DESTINATION .)
+ install(TARGETS OpenTeraPlus RUNTIME DESTINATION .)
# install(TARGETS opentera_messages DESTINATION .)
else(APPLE)
# Every other systems
# Install target to bin
- install(TARGETS OpenTeraPlus DESTINATION bin)
- install(TARGETS opentera_messages DESTINATION bin)
+ install(TARGETS OpenTeraPlus RUNTIME DESTINATION bin)
+ install(TARGETS opentera_messages RUNTIME DESTINATION bin)
endif(APPLE)
-
diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp
index 186c7e02..a7fbd16e 100755
--- a/client/src/ClientApp.cpp
+++ b/client/src/ClientApp.cpp
@@ -8,12 +8,14 @@
#include "data/GlobalEvent.h"
ClientApp::ClientApp(int &argc, char **argv)
- : QApplication(argc, argv)
+ : QApplication(argc, argv)
{
m_comMan = nullptr;
m_loginDiag = nullptr;
m_mainWindow = nullptr;
+#ifndef OPENTERA_WEBASSEMBLY
m_mainKitWindow = nullptr;
+#endif
m_translator = new QTranslator();
m_qt_translator = new QTranslator();
@@ -43,8 +45,10 @@ ClientApp::ClientApp(int &argc, char **argv)
// Show login dialog
showLogin();
}else{
+#ifndef OPENTERA_WEBASSEMBLY
// Show main participant UI
showMainKitWindow();
+#endif
}
}
@@ -55,8 +59,8 @@ ClientApp::~ClientApp()
delete m_loginDiag;
if (m_comMan){
- m_comMan->disconnectFromServer();
- m_comMan->deleteLater();
+ m_comMan->disconnectFromServer();
+ m_comMan->deleteLater();
}
delete m_translator;
@@ -146,6 +150,7 @@ void ClientApp::showMainWindow()
// Delete login window, if present
if (m_loginDiag){
+ m_loginDiag->hide();
m_loginDiag->deleteLater();
m_loginDiag = nullptr;
}
@@ -162,7 +167,7 @@ void ClientApp::showMainWindow()
if (m_comMan->getCurrentUser().hasNameField())
processQueuedEvents();
}
-
+#ifndef OPENTERA_WEBASSEMBLY
void ClientApp::showMainKitWindow()
{
if (m_mainKitWindow != nullptr){
@@ -171,7 +176,7 @@ void ClientApp::showMainKitWindow()
m_mainKitWindow = new MainKitWindow(&m_config);
}
-
+#endif
void ClientApp::setupLogger()
{
@@ -206,46 +211,48 @@ void ClientApp::processQueuedEvents()
void ClientApp::setTranslation(QString language)
{
- bool lang_changed = false;
- QStringList supported_languages = {"fr", "en"};
-
- if (language.isEmpty() || !supported_languages.contains(language.toLower())){
- //Set French as default
- //m_currentLocale = QLocale(QLocale::French);
- m_currentLocale = QLocale(); // Use system locale by default
- lang_changed = true;
- }
- if (language.toLower() == "en" && m_currentLocale != QLocale::English){
- m_currentLocale = QLocale(QLocale::English);
- lang_changed = true;
- }
-
- if (language.toLower() == "fr" && m_currentLocale != QLocale::French){
- m_currentLocale = QLocale(QLocale::French);
- lang_changed = true;
- }
-
- //QLocale english = QLocale(QLocale::English);
- //QLocale french = QLocale(QLocale::French);
- //QLocale::setDefault(english);
- //qDebug() << QLocale();
-
- if (lang_changed){
- QLocale::setDefault(m_currentLocale);
-
- // Install Qt translator for default widgets
- m_qt_translator->load("qt_" + m_currentLocale.name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
- this->installTranslator(m_qt_translator);
-
- // Install app specific translator
- if (m_translator->load(m_currentLocale, QLatin1String("openteraplus"), QLatin1String("_"), QLatin1String(":/translations"))) {
- this->installTranslator(m_translator);
- //qDebug() << "Installed translator";
- }
-
- // Save last used language
- TeraSettings::setGlobalSetting(SETTINGS_LASTLANGUAGE, language.toLower());
- }
+ bool lang_changed = false;
+ QStringList supported_languages = {"fr", "en"};
+
+ if (language.isEmpty() || !supported_languages.contains(language.toLower())){
+ //Set French as default
+ //m_currentLocale = QLocale(QLocale::French);
+ m_currentLocale = QLocale(); // Use system locale by default
+ lang_changed = true;
+ }
+ if (language.toLower() == "en" && m_currentLocale != QLocale::English){
+ m_currentLocale = QLocale(QLocale::English);
+ lang_changed = true;
+ }
+
+ if (language.toLower() == "fr" && m_currentLocale != QLocale::French){
+ m_currentLocale = QLocale(QLocale::French);
+ lang_changed = true;
+ }
+
+ //QLocale english = QLocale(QLocale::English);
+ //QLocale french = QLocale(QLocale::French);
+ //QLocale::setDefault(english);
+ //qDebug() << QLocale();
+
+ if (lang_changed){
+ QLocale::setDefault(m_currentLocale);
+
+ // Install Qt translator for default widgets
+ if (m_qt_translator->load("qt_" + m_currentLocale.name(), QLibraryInfo::path(QLibraryInfo::TranslationsPath)))
+ {
+ this->installTranslator(m_qt_translator);
+ }
+
+ // Install app specific translator
+ if (m_translator->load(m_currentLocale, QLatin1String("openteraplus"), QLatin1String("_"), QLatin1String(":/translations"))) {
+ this->installTranslator(m_translator);
+ //qDebug() << "Installed translator";
+ }
+
+ // Save last used language
+ TeraSettings::setGlobalSetting(SETTINGS_LASTLANGUAGE, language.toLower());
+ }
}
@@ -327,21 +334,21 @@ void ClientApp::on_networkError(QNetworkReply::NetworkError error, QString error
if (m_loginDiag){
switch(error){
- case QNetworkReply::ConnectionRefusedError:
- error_str = tr("La connexion a été refusée par le serveur.");
+ case QNetworkReply::ConnectionRefusedError:
+ error_str = tr("La connexion a été refusée par le serveur.");
break;
- case QNetworkReply::AuthenticationRequiredError:
- //error_str = tr("Impossible de négocier l'authentification avec le serveur");
- return;
+ case QNetworkReply::AuthenticationRequiredError:
+ //error_str = tr("Impossible de négocier l'authentification avec le serveur");
+ return;
break;
- case QNetworkReply::TimeoutError:
- error_str = tr("Impossible de rejoindre le serveur.");
+ case QNetworkReply::TimeoutError:
+ error_str = tr("Impossible de rejoindre le serveur.");
break;
- case QNetworkReply::HostNotFoundError:
- error_str = tr("Le serveur est introuvable.");
+ case QNetworkReply::HostNotFoundError:
+ error_str = tr("Le serveur est introuvable.");
break;
- default:
- error_str = tr("Impossible de se connecter (Code erreur: ") + QString::number(status_code) + " " + error_str + ")";
+ default:
+ error_str = tr("Impossible de se connecter (Code erreur: ") + QString::number(status_code) + " " + error_str + ")";
}
//Remove \n from error_str
diff --git a/client/src/ClientApp.h b/client/src/ClientApp.h
index 92132023..ae14b5ec 100755
--- a/client/src/ClientApp.h
+++ b/client/src/ClientApp.h
@@ -11,7 +11,9 @@
#include
#include "main/MainWindow.h"
+#ifndef OPENTERA_WEBASSEMBLY
#include "main/MainKitWindow.h"
+#endif
#include "dialogs/LoginDialog.h"
#include "GlobalMessageBox.h"
@@ -24,8 +26,7 @@ class ClientApp : public QApplication
Q_OBJECT
public:
ClientApp(int &argc, char** argv);
- ~ClientApp();
-
+ virtual ~ClientApp() override;
ComManager *getComManager();
protected:
@@ -33,7 +34,9 @@ class ClientApp : public QApplication
void connectSignals();
void showLogin();
void showMainWindow();
+#ifndef OPENTERA_WEBASSEMBLY
void showMainKitWindow();
+#endif
void setupLogger();
void processQueuedEvents();
@@ -43,7 +46,9 @@ class ClientApp : public QApplication
ConfigManagerClient m_config;
LoginDialog* m_loginDiag;
MainWindow* m_mainWindow;
+#ifndef OPENTERA_WEBASSEMBLY
MainKitWindow* m_mainKitWindow;
+#endif
QList m_eventQueue; // Queue to stack missed events when just connected, but no MainWindow yet.
diff --git a/client/src/GlobalMessageBox.cpp b/client/src/GlobalMessageBox.cpp
index 1587e4e0..fccedb4b 100644
--- a/client/src/GlobalMessageBox.cpp
+++ b/client/src/GlobalMessageBox.cpp
@@ -17,6 +17,7 @@ GlobalMessageBox::GlobalMessageBox(QWidget *parent) :
"QPushButton:hover{background-color: rgba(255,255,255,75%);color:black;}");*/
m_xPressed=false;
+ setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
}
GlobalMessageBox::~GlobalMessageBox()
@@ -25,23 +26,24 @@ GlobalMessageBox::~GlobalMessageBox()
}
QMessageBox::StandardButton GlobalMessageBox::showYesNo(const QString &title, const QString &text){
-
- /* QPixmap image;
- image.load(":/pictures/UnknownSystem.png");
-
- setIconPixmap(image.scaled(48,48));*/
setIcon(QMessageBox::Question);
setWindowTitle(title);
setText(text);
setModal(true);
+
setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- setButtonText(QMessageBox::Yes,tr("Oui"));
- setButtonText(QMessageBox::No,tr("Non"));
+ //setButtonText(QMessageBox::Yes,tr("Oui"));
+ //setButtonText(QMessageBox::No,tr("Non"));
button(QMessageBox::Yes)->setIcon(QIcon("://icons/ok.png"));
button(QMessageBox::Yes)->setCursor(Qt::PointingHandCursor);
+ button(QMessageBox::Yes)->setText(tr("Oui"));
+
button(QMessageBox::No)->setIcon(QIcon("://icons/error.png"));
button(QMessageBox::No)->setCursor(Qt::PointingHandCursor);
+ button(QMessageBox::No)->setText(tr("Non"));
+
+
setDefaultButton(QMessageBox::No);
exec();
diff --git a/client/src/data/DownloadingFile.cpp b/client/src/data/DownloadingFile.cpp
index bf294013..d5f7913b 100644
--- a/client/src/data/DownloadingFile.cpp
+++ b/client/src/data/DownloadingFile.cpp
@@ -69,7 +69,7 @@ void DownloadingFile::onDownloadDataReceived()
abortTransfer();
return;
}*/
- for (const QString &info: qAsConst(header_info_parts)){
+ for (const QString &info: std::as_const(header_info_parts)){
if (info.trimmed().startsWith("filename=")){
QStringList file_parts = info.split("=");
if (file_parts.count() == 2)
diff --git a/client/src/dialogs/AboutDialog.cpp b/client/src/dialogs/AboutDialog.cpp
index b9c6495e..f35497ae 100644
--- a/client/src/dialogs/AboutDialog.cpp
+++ b/client/src/dialogs/AboutDialog.cpp
@@ -25,6 +25,7 @@ AboutDialog::AboutDialog(QUrl server_url, QWidget *parent) :
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
m_webEngine->setSizePolicy(sizePolicy);
ui->wdgWebView->layout()->addWidget(m_webEngine);
+ ui->wdgWebView->setFocus();
}
AboutDialog::~AboutDialog()
@@ -42,6 +43,8 @@ void AboutDialog::on_btnOk_clicked()
void AboutDialog::on_lblAbout_clicked()
{
if (m_webEngine){
- m_webEngine->setUrl(QUrl("chrome://dino"));
+ m_webEngine->setUrl(QUrl("chrome://dino"));
+ ui->wdgWebView->setFocus();
+
}
}
diff --git a/client/src/dialogs/AboutDialog.ui b/client/src/dialogs/AboutDialog.ui
index 864e98a2..95b77983 100644
--- a/client/src/dialogs/AboutDialog.ui
+++ b/client/src/dialogs/AboutDialog.ui
@@ -33,6 +33,9 @@
0
+
+ Qt::StrongFocus
+
-
@@ -74,6 +77,9 @@
24
+
+ false
+
@@ -86,6 +92,7 @@
QLabel
+ clicked()
clicked()
diff --git a/client/src/dialogs/AboutDialogPage.cpp b/client/src/dialogs/AboutDialogPage.cpp
index 6c374ed4..d473e1ac 100644
--- a/client/src/dialogs/AboutDialogPage.cpp
+++ b/client/src/dialogs/AboutDialogPage.cpp
@@ -1,13 +1,17 @@
#include "AboutDialogPage.h"
+#include
AboutDialogPage::AboutDialogPage()
{
-
+ //TODO Do something about certificate errors.
+ connect(this, &QWebEnginePage::certificateError, this, &AboutDialogPage::onCertificateError);
}
-bool AboutDialogPage::certificateError(const QWebEngineCertificateError &certificateError)
+void AboutDialogPage::onCertificateError(const QWebEngineCertificateError &certificateError)
{
- Q_UNUSED(certificateError)
-
- return true; // Accept all certificates
+ //TODO do Something about certificates
+ qDebug() << "Certificate error: " << certificateError.description();
+ //TODO Do not accept certificates in production ?
+ auto mutableError = const_cast(certificateError);
+ mutableError.acceptCertificate();
}
diff --git a/client/src/dialogs/AboutDialogPage.h b/client/src/dialogs/AboutDialogPage.h
index 59d0910f..c8bb73c8 100644
--- a/client/src/dialogs/AboutDialogPage.h
+++ b/client/src/dialogs/AboutDialogPage.h
@@ -10,8 +10,9 @@ class AboutDialogPage : public QWebEnginePage
public:
AboutDialogPage();
-protected:
- virtual bool certificateError(const QWebEngineCertificateError &certificateError) override;
+protected slots:
+
+ void onCertificateError(const QWebEngineCertificateError &certificateError);
};
#endif // ABOUTDIALOGPAGE_H
diff --git a/client/src/dialogs/BaseDialog.cpp b/client/src/dialogs/BaseDialog.cpp
index bab5b60f..5b739582 100644
--- a/client/src/dialogs/BaseDialog.cpp
+++ b/client/src/dialogs/BaseDialog.cpp
@@ -8,7 +8,7 @@ BaseDialog::BaseDialog(QWidget *parent)
m_ui.setupUi(this);
m_centralWidgetLayout = new QVBoxLayout(m_ui.centralWidget);
- m_centralWidgetLayout->setMargin(0);
+ //m_centralWidgetLayout->setMargin(0);
m_centralWidgetLayout->setContentsMargins(0,0,0,0);
// setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
diff --git a/client/src/dialogs/CleanUpDialog.cpp b/client/src/dialogs/CleanUpDialog.cpp
index 1c55c81d..bbc15974 100644
--- a/client/src/dialogs/CleanUpDialog.cpp
+++ b/client/src/dialogs/CleanUpDialog.cpp
@@ -133,11 +133,11 @@ void CleanUpDialog::refreshData()
ui->tableItems->clearContents();
m_itemsMap.clear();
- for(const QVariant &data:qAsConst(m_data)){
+ for(const QVariant &data:std::as_const(m_data)){
QVariantMap data_map = data.toMap();
int current_row = ui->tableItems->rowCount();
ui->tableItems->setRowCount(ui->tableItems->rowCount()+1);
- for (const QVariant &data_value: qAsConst(data_map)){
+ for (const QVariant &data_value: std::as_const(data_map)){
QString data_key = data_map.key(data_value);
if (m_columnsMap.contains(data_key)){
QTableWidgetItem* item;
@@ -163,7 +163,7 @@ void CleanUpDialog::refreshData()
QFrame* action_frame = new QFrame();
QHBoxLayout* layout = new QHBoxLayout();
layout->setContentsMargins(0,0,0,0);
- layout->setAlignment(Qt::AlignLeft);
+ layout->setAlignment(Qt::AlignHCenter);
action_frame->setLayout(layout);
// Delete button
@@ -172,7 +172,7 @@ void CleanUpDialog::refreshData()
btnDisable->setIcon(QIcon("://controls/check_off.png"));
btnDisable->setProperty("id", m_itemsMap[ui->tableItems->item(current_row,0)]);
btnDisable->setCursor(Qt::PointingHandCursor);
- btnDisable->setMaximumWidth(32);
+ btnDisable->setMaximumWidth(48);
btnDisable->setToolTip(tr("Désactiver"));
connect(btnDisable, &QToolButton::clicked, this, &CleanUpDialog::btnDisable_clicked);
layout->addWidget(btnDisable);
@@ -184,7 +184,7 @@ void CleanUpDialog::refreshData()
btnDelete->setIcon(QIcon(":/icons/delete_old.png"));
btnDelete->setProperty("id", m_itemsMap[ui->tableItems->item(current_row,0)]);
btnDelete->setCursor(Qt::PointingHandCursor);
- btnDelete->setMaximumWidth(32);
+ btnDelete->setMaximumWidth(48);
btnDelete->setToolTip(tr("Supprimer"));
connect(btnDelete, &QToolButton::clicked, this, &CleanUpDialog::btnDelete_clicked);
layout->addWidget(btnDelete);
@@ -289,7 +289,7 @@ void CleanUpDialog::on_btnDisableAll_clicked()
answer = diag.showYesNo(tr("Désactivation?"), tr("Êtes-vous sûrs de vouloir tout désactiver?"));
if (answer == QMessageBox::Yes){
- for(int id:qAsConst(m_itemsMap)){
+ for(int id:std::as_const(m_itemsMap)){
m_idsToManage.append(id);
}
disableNextItem();
@@ -304,7 +304,7 @@ void CleanUpDialog::on_btnDeleteAll_clicked()
answer = diag.showYesNo(tr("Suppression?"), tr("Êtes-vous sûrs de vouloir tout supprimer?"));
if (answer == QMessageBox::Yes){
- for(int id:qAsConst(m_itemsMap)){
+ for(int id:std::as_const(m_itemsMap)){
m_idsToManage.append(id);
}
deleteNextItem();
diff --git a/client/src/dialogs/FileUploaderDialog.cpp b/client/src/dialogs/FileUploaderDialog.cpp
index 5f12d7bf..342b6013 100644
--- a/client/src/dialogs/FileUploaderDialog.cpp
+++ b/client/src/dialogs/FileUploaderDialog.cpp
@@ -54,7 +54,7 @@ void FileUploaderDialog::on_btnAddFile_clicked()
QStringList files_to_upload = dlg.getOpenFileNames(this, tr("Choisir le(s) fichier(s) à envoyer"), m_current_base_path, m_file_pattern);
- for (const QString &file:qAsConst(files_to_upload)){
+ for (const QString &file:std::as_const(files_to_upload)){
QFileInfo file_info(file);
QString filename = file_info.fileName();
QString default_label = filename.left(filename.length() - filename.split(".").last().length() - 1);
diff --git a/client/src/dialogs/JoinSessionDialog.cpp b/client/src/dialogs/JoinSessionDialog.cpp
index f2e79317..86eec8ad 100644
--- a/client/src/dialogs/JoinSessionDialog.cpp
+++ b/client/src/dialogs/JoinSessionDialog.cpp
@@ -1,5 +1,6 @@
#include "JoinSessionDialog.h"
#include "ui_JoinSessionDialog.h"
+#include
JoinSessionDialog::JoinSessionDialog(ComManager *comMan, opentera::protobuf::JoinSessionEvent event, QWidget *parent) :
QDialog(parent),
@@ -65,7 +66,9 @@ void JoinSessionDialog::initUi()
ui->lblInviteMsg->setText(tr("L'invitation comporte le message suivant:
") + QString::fromStdString(m_event.join_msg()) + "");
}
- QSound::play("://sounds/notify_invite.wav");
+ m_soundPlayer.setSource(QUrl::fromLocalFile("://sounds/notify_invite.wav"));
+ m_soundPlayer.setVolume(0.25f);
+ m_soundPlayer.play();
}
void JoinSessionDialog::connectSignals()
diff --git a/client/src/dialogs/JoinSessionDialog.h b/client/src/dialogs/JoinSessionDialog.h
index 7a260a7b..71713891 100644
--- a/client/src/dialogs/JoinSessionDialog.h
+++ b/client/src/dialogs/JoinSessionDialog.h
@@ -2,8 +2,7 @@
#define JOINSESSIONDIALOG_H
#include
-#include
-
+#include
#include "managers/ComManager.h"
// Protobuf
@@ -30,7 +29,7 @@ class JoinSessionDialog : public QDialog
int getSessionId();
- ~JoinSessionDialog();
+ virtual ~JoinSessionDialog() override;
private slots:
void on_btnJoinSession_clicked();
@@ -51,6 +50,7 @@ private slots:
TeraData m_session;
TeraData m_sessionType;
+ QSoundEffect m_soundPlayer;
void initUi();
void connectSignals();
diff --git a/client/src/dialogs/LoginDialog.ui b/client/src/dialogs/LoginDialog.ui
index 397cb6f3..b76fe565 100644
--- a/client/src/dialogs/LoginDialog.ui
+++ b/client/src/dialogs/LoginDialog.ui
@@ -439,7 +439,7 @@ QGroupBox#grpLogos{background-color:rgba(200,200,200,200);}
- :/controls/branch_closed.png:/controls/branch_closed.png
+ :/icons/play.png:/icons/play.png
diff --git a/client/src/dialogs/SessionLobbyDialog.cpp b/client/src/dialogs/SessionLobbyDialog.cpp
index 9dafc5a2..281c2951 100644
--- a/client/src/dialogs/SessionLobbyDialog.cpp
+++ b/client/src/dialogs/SessionLobbyDialog.cpp
@@ -12,6 +12,8 @@ SessionLobbyDialog::SessionLobbyDialog(ComManager* comManager, TeraData &session
ui->setupUi(this);
m_setupWdg = nullptr;
+ setModal(true);
+
ui->lblTitle->setText(m_sessionType.getFieldValue("session_type_name").toString());
connectSignals();
@@ -43,37 +45,16 @@ void SessionLobbyDialog::addDevicesToSession(const QList &devices, con
QStringList SessionLobbyDialog::getSessionParticipantsUuids()
{
- /*QStringList uuids;
- QList participants = ui->wdgSessionInvite->getParticipantsInSession();
-
- foreach(TeraData part, participants){
- uuids.append(part.getUuid());
- }
- return uuids;*/
return ui->wdgSessionInvite->getParticipantsUuidsInSession();
}
QStringList SessionLobbyDialog::getSessionUsersUuids()
{
- /*QStringList uuids;
- QList users = ui->wdgSessionInvite->getUsersInSession();
-
- foreach(TeraData user, users){
- uuids.append(user.getUuid());
- }
- return uuids;*/
return ui->wdgSessionInvite->getUsersUuidsInSession();
}
QStringList SessionLobbyDialog::getSessionDevicesUuids()
{
- /*QStringList uuids;
- QList devices = ui->wdgSessionInvite->getDevicesInSession();
-
- foreach(TeraData device, devices){
- uuids.append(device.getUuid());
- }
- return uuids;*/
return ui->wdgSessionInvite->getDevicesUuidsInSession();
}
@@ -266,7 +247,7 @@ void SessionLobbyDialog::processSessionsReply(QList sessions)
if (session.hasFieldName("session_participants")){
item_list = session.getFieldValue("session_participants").toList();
- for(const QVariant &session_part:qAsConst(item_list)){
+ for(const QVariant &session_part:std::as_const(item_list)){
QVariantMap part_info = session_part.toMap();
ui->wdgSessionInvite->addRequiredParticipant(part_info["id_participant"].toInt());
}
@@ -275,7 +256,7 @@ void SessionLobbyDialog::processSessionsReply(QList sessions)
if (session.hasFieldName("session_users")){
item_list = session.getFieldValue("session_users").toList();
- for(const QVariant &session_user:qAsConst(item_list)){
+ for(const QVariant &session_user:std::as_const(item_list)){
QVariantMap user_info = session_user.toMap();
ui->wdgSessionInvite->addRequiredUser(user_info["id_user"].toInt());
}
@@ -284,7 +265,7 @@ void SessionLobbyDialog::processSessionsReply(QList sessions)
if (session.hasFieldName("session_devices")){
item_list = session.getFieldValue("session_devices").toList();
- for(const QVariant &session_device:qAsConst(item_list)){
+ for(const QVariant &session_device:std::as_const(item_list)){
QVariantMap device_info = session_device.toMap();
ui->wdgSessionInvite->addRequiredDevice(device_info["id_device"].toInt());
}
diff --git a/client/src/dialogs/TransferProgressDialog.cpp b/client/src/dialogs/TransferProgressDialog.cpp
index fb1d6187..8cf9aba0 100644
--- a/client/src/dialogs/TransferProgressDialog.cpp
+++ b/client/src/dialogs/TransferProgressDialog.cpp
@@ -177,10 +177,10 @@ void TransferProgressDialog::on_btnCancel_clicked()
// Set aborting flag to prevent further updates
m_aborting = true;
- /*for(QTableWidgetItem* item:qAsConst(m_files)){
+ /*for(QTableWidgetItem* item:std::as_const(m_files)){
m_files.key(item)->abortTransfer();
}
- for(TransferringFile* file:qAsConst(m_waitingFiles)){
+ for(TransferringFile* file:std::as_const(m_waitingFiles)){
file->abortTransfer();
}*/
emit transferAbortRequested();
diff --git a/client/src/drivers/PTZ/CMakeLists.txt b/client/src/drivers/PTZ/CMakeLists.txt
index 87c78e0f..2e122805 100644
--- a/client/src/drivers/PTZ/CMakeLists.txt
+++ b/client/src/drivers/PTZ/CMakeLists.txt
@@ -1,8 +1,7 @@
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Widgets REQUIRED)
-find_package(Qt5LinguistTools REQUIRED)
-find_package(Qt5Xml REQUIRED)
-find_package(Qt5Network REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Widgets REQUIRED)
+find_package(Qt6Xml REQUIRED)
+find_package(Qt6Network REQUIRED)
set(PTZDrivers_headers
ICameraDriver.h
@@ -34,18 +33,18 @@ include_directories(
)
#Generate .h files from the .ui files
-QT5_WRAP_UI(moc_uis ${PTZDrivers_uis})
+QT6_WRAP_UI(moc_uis ${PTZDrivers_uis})
# generate rules for building source files from the resources
-QT5_ADD_RESOURCES(ptz_drivers_qrc ${PTZDrivers_qrcs})
+QT6_ADD_RESOURCES(ptz_drivers_qrc ${PTZDrivers_qrcs})
#This will generate moc_* for Qt
-qt5_wrap_cpp(ptz_drivers_moc_srcs ${PTZDrivers_headers})
+qt6_wrap_cpp(ptz_drivers_moc_srcs ${PTZDrivers_headers})
add_library(PTZDrivers STATIC ${PTZDrivers_headers} ${PTZDrivers_srcs} ${ptz_drivers_qrc} ${ptz_drivers_moc_srcs} ${moc_uis})
-target_link_libraries(PTZDrivers Qt5::Core Qt5::Widgets Qt5::Xml Qt5::Network)
+target_link_libraries(PTZDrivers Qt6::Core Qt6::Widgets Qt6::Xml Qt6::Network)
set(PTZ_DRIVERS_LIBS PTZDrivers CACHE INTERNAL "doc string")
set(PTZ_DRIVERS_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "doc string")
diff --git a/client/src/drivers/VirtualCamera/CMakeLists.txt b/client/src/drivers/VirtualCamera/CMakeLists.txt
index 10e7c507..576d88c7 100644
--- a/client/src/drivers/VirtualCamera/CMakeLists.txt
+++ b/client/src/drivers/VirtualCamera/CMakeLists.txt
@@ -1,8 +1,8 @@
-find_package(Qt5Core REQUIRED)
-find_package(Qt5LinguistTools REQUIRED)
-find_package(Qt5Qml REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Quick REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6LinguistTools REQUIRED)
+find_package(Qt6Qml REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Quick REQUIRED)
set(VirtualCamera_headers
VirtualCamera.h
@@ -25,17 +25,18 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
)
-message(STATUS "PLUGIN_DIRECTORY: ${AVKYS_PLUGIN_DIRECTORY}")
+message(STATUS "Virtual Camera AVKYS PLUGIN_DIRECTORY: ${AVKYS_PLUGIN_DIRECTORY}")
+message(STATUS "Virtual Camera AVKYS INCLUDE_DIRECTORY: ${AVKYS_INCLUDES}")
# generate rules for building source files from the resources
-QT5_ADD_RESOURCES(virtual_camera_qrc ${VirtualCamera_qrcs})
+QT6_ADD_RESOURCES(virtual_camera_qrc ${VirtualCamera_qrcs})
#This will generate moc_* for Qt
-qt5_wrap_cpp(virtual_camera_moc_srcs ${VirtualCamera_headers})
+qt_wrap_cpp(virtual_camera_moc_srcs ${VirtualCamera_headers})
add_definitions(-DAVKYS_PLUGIN_DIRECTORY="${AVKYS_PLUGIN_DIRECTORY}")
add_library(VirtualCameraDriver STATIC ${VirtualCamera_headers} ${VirtualCamera_srcs} ${virtual_camera_qrc} ${virtual_camera_moc_srcs})
-target_link_libraries(VirtualCameraDriver Qt5::Core Qt5::Qml Qt5::Concurrent Qt5::Quick ${AVKYS_LIBS})
+target_link_libraries(VirtualCameraDriver Qt6::Core Qt6::Qml Qt6::Concurrent Qt6::Quick ${AVKYS_LIBS})
set(VIRTUAL_CAMERA_LIBS VirtualCameraDriver CACHE INTERNAL "doc string")
set(VIRTUAL_CAMERA_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "doc string")
diff --git a/client/src/editors/DataEditorWidget.cpp b/client/src/editors/DataEditorWidget.cpp
index b1d34631..1ecbd20e 100644
--- a/client/src/editors/DataEditorWidget.cpp
+++ b/client/src/editors/DataEditorWidget.cpp
@@ -256,6 +256,10 @@ QString DataEditorWidget::getRoleName(const QString &role)
return tr("Administrateur");
if (role == "user")
return tr("Utilisateur");
+ if (role == "manager")
+ return tr("Gestionnaire");
+ if (role == "editor")
+ return tr("Éditeur");
if (role == "")
return tr("Aucun rôle");
return role;
@@ -331,11 +335,15 @@ void DataEditorWidget::deleteDataReplyOK(const QString &path, const int &id)
setReady();
}
-void DataEditorWidget::comDataError(QNetworkReply::NetworkError error, QString error_str)
+void DataEditorWidget::comDataError(QNetworkReply::NetworkError error, QString error_str, QNetworkAccessManager::Operation op, int status_code, QString path, QUrlQuery url_query)
{
Q_UNUSED(error)
Q_UNUSED(error_str)
+ QString query_name = getQueryDataName(path, url_query);
+ m_requests.removeOne(query_name);
setReady();
+ if (!hasPendingDataRequests())
+ updateFieldsValue();
}
void DataEditorWidget::editToggleClicked()
@@ -358,7 +366,7 @@ void DataEditorWidget::saveButtonClicked()
if (!invalids.isEmpty()){
QString msg = tr("Les champs suivants doivent être complétés:") +" ";
- for (const QString &field:qAsConst(invalids)){
+ for (const QString &field:std::as_const(invalids)){
msg += "- " + field + "
";
}
msg += "
";
diff --git a/client/src/editors/DataEditorWidget.h b/client/src/editors/DataEditorWidget.h
index 077c6f35..31769765 100644
--- a/client/src/editors/DataEditorWidget.h
+++ b/client/src/editors/DataEditorWidget.h
@@ -16,7 +16,7 @@ class DataEditorWidget : public QWidget
Q_OBJECT
public:
explicit DataEditorWidget(ComManager *comMan, const TeraData* data = nullptr, QWidget *parent = nullptr);
- ~DataEditorWidget();
+ ~DataEditorWidget() override;
enum EditorState{
STATE_READY=0,
@@ -110,7 +110,7 @@ private slots:
void queryDataReplyOK(const QString &path, const QUrlQuery &query_args);
void postDataReplyOK(const QString &path);
void deleteDataReplyOK(const QString &path, const int &id);
- void comDataError(QNetworkReply::NetworkError error, QString error_str);
+ void comDataError(QNetworkReply::NetworkError error, QString error_str, QNetworkAccessManager::Operation op, int status_code, QString path, QUrlQuery url_query);
protected slots:
virtual void editToggleClicked();
diff --git a/client/src/editors/DataListWidget.cpp b/client/src/editors/DataListWidget.cpp
index 0d6089f8..56d9ffd4 100644
--- a/client/src/editors/DataListWidget.cpp
+++ b/client/src/editors/DataListWidget.cpp
@@ -109,7 +109,7 @@ void DataListWidget::updateDataInList(TeraData* data, bool select_item){
// If we have extra fields to display, append them
QString extra_field = "";
if (!m_extraDisplayFields.isEmpty() && !m_extraInfos.contains(data->getId())){
- for (QString field:qAsConst(m_extraDisplayFields)){
+ for (QString field:std::as_const(m_extraDisplayFields)){
QStringList subfields = field.split(".");
QString subfield;
if (subfields.count() > 1){
@@ -121,22 +121,26 @@ void DataListWidget::updateDataInList(TeraData* data, bool select_item){
extra_field += ", ";
QVariant field_value = data->getFieldValue(field);
- if (field_value.canConvert(QMetaType::QVariantList)){
- QVariantList field_values = field_value.toList();
- QString merged_list;
- for (QVariant field_value:qAsConst(field_values)){
- if (!merged_list.isEmpty())
- merged_list += ", ";
- // Search for subfield?
- if (field_value.canConvert(QMetaType::QVariantMap)){
- QVariantMap field_map = field_value.toMap();
- field_value = field_map[subfield];
+ if (field_value.typeId() == QMetaType::QString){
+ extra_field += field_value.toString();
+ }else{
+ if (field_value.canConvert()){
+ QVariantList field_values = field_value.toList();
+ QString merged_list;
+ for (QVariant field_value:std::as_const(field_values)){
+ if (!merged_list.isEmpty())
+ merged_list += ", ";
+ // Search for subfield?
+ if (field_value.canConvert()){
+ QVariantMap field_map = field_value.toMap();
+ field_value = field_map[subfield];
+ }
+ merged_list += field_value.toString();
}
- merged_list += field_value.toString();
+ extra_field += merged_list;
+ }else{
+ extra_field += field_value.toString();
}
- extra_field += merged_list;
- }else{
- extra_field += data->getFieldValue(field).toString();
}
}
}
@@ -224,7 +228,7 @@ void DataListWidget::showEditor(TeraData *data)
m_editor = new UserWidget(m_comManager, data);
break;
case TERADATA_SITE:
- m_editor = new SiteWidget(m_comManager, data);
+ m_editor = new SiteWidget(m_comManager, data, true);
break;
case TERADATA_DEVICE:
m_editor = new DeviceWidget(m_comManager, data);
@@ -341,7 +345,7 @@ QListWidgetItem *DataListWidget::getItemForData(TeraData *data)
// Less simple case - the pointers are not the same, but we might be referencing an object already present.
if (!data->isNew()){
- for (QListWidgetItem* item: qAsConst(m_datamap)){
+ for (QListWidgetItem* item: std::as_const(m_datamap)){
TeraData* current_data = m_datamap.key(item);
/*}
for (TeraData* current_data:m_datamap.keys()){*/
@@ -352,7 +356,7 @@ QListWidgetItem *DataListWidget::getItemForData(TeraData *data)
// Not found - try to find an item which is new but with the same name
//for (TeraData* current_data:m_datamap.keys()){
- for (QListWidgetItem* item: qAsConst(m_datamap)){
+ for (QListWidgetItem* item: std::as_const(m_datamap)){
TeraData* current_data = m_datamap.key(item);
if (current_data->isNew() && current_data->getName() == data->getName()){
m_newdata=false;
@@ -362,7 +366,7 @@ QListWidgetItem *DataListWidget::getItemForData(TeraData *data)
}else{
// We have a new item - try and match.
//for (TeraData* current_data:m_datamap.keys()){
- for (QListWidgetItem* item: qAsConst(m_datamap)){
+ for (QListWidgetItem* item: std::as_const(m_datamap)){
TeraData* current_data = m_datamap.key(item);
if (current_data->isNew()){
return m_datamap[current_data];
@@ -379,7 +383,7 @@ void DataListWidget::clearDataList(){
ui->lstData->clear();
//for (TeraData* data:m_datamap.keys()){
- for (QListWidgetItem* item: qAsConst(m_datamap)){
+ for (QListWidgetItem* item: std::as_const(m_datamap)){
TeraData* data = m_datamap.key(item);
delete data;
}
@@ -407,7 +411,7 @@ void DataListWidget::deleteDataReply(QString path, int id)
if (path == TeraData::getPathForDataType(m_dataType)){
// An item that we are managing got deleted
- for (QListWidgetItem* item: qAsConst(m_datamap)){
+ for (QListWidgetItem* item: std::as_const(m_datamap)){
TeraData* data = m_datamap.key(item);
//for (TeraData* data:m_datamap.keys()){
if (data->getId() == id){
@@ -464,7 +468,7 @@ void DataListWidget::editor_dataChanged()
void DataListWidget::searchChanged(QString new_search){
Q_UNUSED(new_search)
// Check if search field is empty
- if (ui->txtSearch->text().count()==0){
+ if (ui->txtSearch->text().size()==0){
setSearching(false);
// Display back all items
for (int i=0; ilstData->count();i++){
diff --git a/client/src/editors/DataListWidget.ui b/client/src/editors/DataListWidget.ui
index 10d85c31..3a0ed15e 100644
--- a/client/src/editors/DataListWidget.ui
+++ b/client/src/editors/DataListWidget.ui
@@ -92,7 +92,7 @@ QTreeWidget::branch:closed:has-children:has-siblings {
- 3
+ 6
QLayout::SetMaximumSize
@@ -165,6 +165,9 @@ QTreeWidget::branch:closed:has-children:has-siblings {
Seuls les ... ayant un lien avec ce ... sont présentement affichés.
+
+ Qt::AlignCenter
+
true
@@ -172,8 +175,26 @@ QTreeWidget::branch:closed:has-children:has-siblings {
-
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
-
+
+
+ 0
+ 0
+
+
PointingHandCursor
@@ -187,6 +208,12 @@ QTreeWidget::branch:closed:has-children:has-siblings {
-
+
+
+ 0
+ 0
+
+
PointingHandCursor
@@ -222,7 +249,7 @@ QTreeWidget::branch:closed:has-children:has-siblings {
- 0
+ 6
0
diff --git a/client/src/editors/DeviceSummaryWidget.cpp b/client/src/editors/DeviceSummaryWidget.cpp
index f577826a..bdb97173 100644
--- a/client/src/editors/DeviceSummaryWidget.cpp
+++ b/client/src/editors/DeviceSummaryWidget.cpp
@@ -9,7 +9,9 @@ DeviceSummaryWidget::DeviceSummaryWidget(ComManager *comMan, const TeraData *dat
{
m_diag_editor = nullptr;
+#ifndef OPENTERA_WEBASSEMBLY
m_sessionLobby = nullptr;
+#endif
m_idProject = id_project;
ui->setupUi(this);
@@ -47,9 +49,10 @@ DeviceSummaryWidget::DeviceSummaryWidget(ComManager *comMan, const TeraData *dat
DeviceSummaryWidget::~DeviceSummaryWidget()
{
delete ui;
-
+#ifndef OPENTERA_WEBASSEMBLY
if (m_sessionLobby)
m_sessionLobby->deleteLater();
+#endif
}
void DeviceSummaryWidget::connectSignals()
@@ -232,7 +235,7 @@ void DeviceSummaryWidget::ws_deviceEvent(DeviceEvent event)
}
updateFieldsValue();
}
-
+#ifndef OPENTERA_WEBASSEMBLY
void DeviceSummaryWidget::sessionLobbyStartSessionRequested()
{
int id_session_type = ui->cmbSessionType->currentData().toInt();
@@ -281,7 +284,7 @@ void DeviceSummaryWidget::on_btnNewSession_clicked()
// Show Session Lobby
m_sessionLobby->exec();
}
-
+#endif
void DeviceSummaryWidget::on_tabNav_currentChanged(int index)
{
Q_UNUSED(index)
diff --git a/client/src/editors/DeviceSummaryWidget.h b/client/src/editors/DeviceSummaryWidget.h
index 8dec8686..b335cf87 100644
--- a/client/src/editors/DeviceSummaryWidget.h
+++ b/client/src/editors/DeviceSummaryWidget.h
@@ -10,7 +10,10 @@
#include "TeraSessionStatus.h"
#include "Utils.h"
#include "ServiceConfigWidget.h"
+
+#ifndef OPENTERA_WEBASSEMBLY
#include "dialogs/SessionLobbyDialog.h"
+#endif
namespace Ui {
class DeviceSummaryWidget;
@@ -22,9 +25,9 @@ class DeviceSummaryWidget : public DataEditorWidget
public:
explicit DeviceSummaryWidget(ComManager* comMan, const TeraData* data = nullptr, const int &id_project = -1, QWidget *parent = nullptr);
- ~DeviceSummaryWidget();
+ ~DeviceSummaryWidget() override;
- void saveData(bool signal=true);
+ void saveData(bool signal=true) override;
void connectSignals();
private:
@@ -33,15 +36,17 @@ class DeviceSummaryWidget : public DataEditorWidget
QMap m_ids_session_types;
BaseDialog* m_diag_editor;
+#ifndef OPENTERA_WEBASSEMBLY
SessionLobbyDialog* m_sessionLobby;
+#endif
int m_idProject;
- void updateControlsState();
- void updateFieldsValue();
+ void updateControlsState() override;
+ void updateFieldsValue() override;
void initUI();
- bool validateData();
+ bool validateData() override;
private slots:
void processFormsReply(QString form_type, QString data);
@@ -51,11 +56,11 @@ private slots:
void processStatsReply(TeraData stats, QUrlQuery reply_query);
void ws_deviceEvent(opentera::protobuf::DeviceEvent event);
-
+#ifndef OPENTERA_WEBASSEMBLY
void sessionLobbyStartSessionRequested();
void sessionLobbyStartSessionCancelled();
-
void on_btnNewSession_clicked();
+#endif
void on_tabNav_currentChanged(int index);
void sessionTotalCountUpdated(int new_count);
diff --git a/client/src/editors/DeviceWidget.cpp b/client/src/editors/DeviceWidget.cpp
index 58dbfdd2..64afef17 100644
--- a/client/src/editors/DeviceWidget.cpp
+++ b/client/src/editors/DeviceWidget.cpp
@@ -112,7 +112,7 @@ void DeviceWidget::updateControlsState()
bool has_project_admin_access = m_comManager->isCurrentUserSuperAdmin();
if (!has_project_admin_access){
// Check if we are admin in a list one site
- for(int id_project:qAsConst(m_devicesProjects)){
+ for(int id_project:std::as_const(m_devicesProjects)){
if (m_comManager->isCurrentUserProjectAdmin(id_project)){
has_project_admin_access = true;
break;
@@ -153,7 +153,7 @@ bool DeviceWidget::validateSitesProjects()
if (!m_comManager->isCurrentUserSuperAdmin()){
bool at_least_one_selected = false;
// Sites
- for (QTreeWidgetItem* item: qAsConst(m_treeSites_items)){
+ for (QTreeWidgetItem* item: std::as_const(m_treeSites_items)){
if (item->checkState(0) == Qt::Checked){
at_least_one_selected = true;
break;
@@ -161,7 +161,7 @@ bool DeviceWidget::validateSitesProjects()
}
// Projects
- for (QTreeWidgetItem* item: qAsConst(m_treeProjects_items)){
+ for (QTreeWidgetItem* item: std::as_const(m_treeProjects_items)){
if (item->checkState(0) == Qt::Checked){
at_least_one_selected = true;
break;
@@ -344,7 +344,7 @@ void DeviceWidget::postDeviceSites()
QJsonObject base_obj;
QJsonArray sites;
- for(QTreeWidgetItem* item: qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeSites_items)){
int site_id = m_treeSites_items.key(item);
if (item->checkState(0) == Qt::Checked){
QJsonObject data_obj;
@@ -367,7 +367,7 @@ void DeviceWidget::postDeviceProjects()
QJsonObject base_obj;
QJsonArray projects;
- for(QTreeWidgetItem* item: qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeProjects_items)){
int project_id = m_treeProjects_items.key(item);
if (item->checkState(0) == Qt::Checked){
QJsonObject data_obj;
@@ -387,7 +387,7 @@ void DeviceWidget::postDeviceProjects()
QJsonArray DeviceWidget::getSelectedProjectsAsJsonArray()
{
QJsonArray projects;
- for(QTreeWidgetItem* item: qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeProjects_items)){
//for (int i=0; icheckState(0) == Qt::Checked){
@@ -402,7 +402,7 @@ QJsonArray DeviceWidget::getSelectedProjectsAsJsonArray()
QJsonArray DeviceWidget::getSelectedSitesAsJsonArray()
{
QJsonArray sites;
- for(QTreeWidgetItem* item: qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeSites_items)){
int site_id = m_treeSites_items.key(item);
if (item->checkState(0) == Qt::Checked){
QJsonObject data_obj;
@@ -499,7 +499,7 @@ void DeviceWidget::btnSaveSites_clicked()
bool has_removed = false;
- for(QTreeWidgetItem* item: qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeSites_items)){
if (item->checkState(0) == Qt::Unchecked && item->data(0, Qt::UserRole) == Qt::Checked){
has_removed = true;
break;
@@ -507,7 +507,7 @@ void DeviceWidget::btnSaveSites_clicked()
}
if (!has_removed){
- for(QTreeWidgetItem* item: qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeProjects_items)){
if (item->checkState(0) == Qt::Unchecked && item->data(0, Qt::UserRole) == Qt::Checked){
has_removed = true;
break;
@@ -598,14 +598,14 @@ void DeviceWidget::lstSites_itemChanged(QTreeWidgetItem *item, int column)
updating = false;
- for(QTreeWidgetItem* site: qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* site: std::as_const(m_treeSites_items)){
if (site->checkState(0) != site->data(0, Qt::UserRole) && site->data(0, Qt::UserRole) != Qt::PartiallyChecked){
has_changes = true;
break;
}
}
if (!has_changes){
- for(QTreeWidgetItem* proj: qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* proj: std::as_const(m_treeProjects_items)){
if (proj->checkState(0) != proj->data(0, Qt::UserRole)){
has_changes = true;
break;
@@ -644,7 +644,7 @@ void DeviceWidget::on_tabNav_currentChanged(int index)
// Service configuration
if (!ui->wdgServiceConfig->layout()){
QHBoxLayout* layout = new QHBoxLayout();
- layout->setMargin(0);
+ layout->setContentsMargins(0,0,0,0);
ui->wdgServiceConfig->setLayout(layout);
}
if (ui->wdgServiceConfig->layout()->count() == 0){
diff --git a/client/src/editors/DeviceWidget.ui b/client/src/editors/DeviceWidget.ui
index 6f3735ba..e11222d3 100644
--- a/client/src/editors/DeviceWidget.ui
+++ b/client/src/editors/DeviceWidget.ui
@@ -338,6 +338,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
0
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -402,6 +405,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
true
+
+ QAbstractItemView::NoEditTriggers
+
24
diff --git a/client/src/editors/GroupWidget.cpp b/client/src/editors/GroupWidget.cpp
index 5cabded7..c3fcafca 100644
--- a/client/src/editors/GroupWidget.cpp
+++ b/client/src/editors/GroupWidget.cpp
@@ -15,9 +15,9 @@ GroupWidget::GroupWidget(ComManager *comMan, const TeraData *data, QWidget *pare
setAttribute(Qt::WA_StyledBackground); //Required to set a background image
setLimited(false);
-
+#ifndef OPENTERA_WEBASSEMBLY
m_sessionLobby = nullptr;
-
+#endif
// Use base class to manage editing
setEditorControls(ui->wdgGroup, ui->btnEdit, ui->frameButtons, ui->btnSave, ui->btnUndo);
@@ -60,13 +60,16 @@ GroupWidget::GroupWidget(ComManager *comMan, const TeraData *data, QWidget *pare
GroupWidget::~GroupWidget()
{
- if (ui)
+ if (ui) {
delete ui;
+ }
qDeleteAll(m_ids_session_types);
-
- if (m_sessionLobby)
+#ifndef OPENTERA_WEBASSEMBLY
+ if (m_sessionLobby) {
m_sessionLobby->deleteLater();
+ }
+#endif
}
void GroupWidget::saveData(bool signal){
@@ -178,7 +181,7 @@ void GroupWidget::processStatsReply(TeraData stats, QUrlQuery reply_query)
QVariantList parts_list = stats.getFieldValue("participants").toList();
- for(const QVariant &part:qAsConst(parts_list)){
+ for(const QVariant &part:std::as_const(parts_list)){
QVariantMap part_info = part.toMap();
int part_id = part_info["id_participant"].toInt();
@@ -196,9 +199,12 @@ void GroupWidget::processStatsReply(TeraData stats, QUrlQuery reply_query)
item->setForeground(Qt::green);
if (!m_activeParticipants.contains(part_id))
m_activeParticipants.append(part_id);
+ ui->tableSummary->showRow(current_row);
}else{
status = tr("Inactif");
item->setForeground(Qt::red);
+ if (!ui->chkShowInactive->isChecked())
+ ui->tableSummary->hideRow(current_row);
}
item->setText(status);
item->setTextAlignment(Qt::AlignCenter);
@@ -325,7 +331,7 @@ void GroupWidget::deleteDataReply(QString path, int del_id)
}
}
}
-
+#ifndef OPENTERA_WEBASSEMBLY
void GroupWidget::showSessionLobby(const int &id_session_type, const int &id_session)
{
if (m_sessionLobby)
@@ -335,7 +341,7 @@ void GroupWidget::showSessionLobby(const int &id_session_type, const int &id_ses
// Add current participants to session
//m_sessionLobby->addParticipantsToSession(QList() << *m_data, QList() << m_data->getId());
- for(int id_part:qAsConst(m_activeParticipants)){
+ for(int id_part:std::as_const(m_activeParticipants)){
TeraData part_data;
part_data.setDataType(TeraDataTypes::TERADATA_PARTICIPANT);
part_data.setId(id_part);
@@ -385,6 +391,7 @@ void GroupWidget::sessionLobbyStartSessionCancelled()
}
}
+#endif
void GroupWidget::connectSignals()
{
connect(m_comManager, &ComManager::formReceived, this, &GroupWidget::processFormsReply);
@@ -429,7 +436,7 @@ void GroupWidget::on_tableSummary_itemSelectionChanged()
ui->btnDelete->setEnabled(!ui->tableSummary->selectedItems().isEmpty());
}
-
+#ifndef OPENTERA_WEBASSEMBLY
void GroupWidget::on_btnNewSession_clicked()
{
if (ui->cmbSessionType->currentIndex() < 0)
@@ -443,4 +450,22 @@ void GroupWidget::on_btnNewSession_clicked()
showSessionLobby(id_session_type, id_session);
}
+#endif
+
+void GroupWidget::on_chkShowInactive_stateChanged(int checked)
+{
+ for(QTableWidgetItem* item: m_tableParticipants_items){
+ int row = item->row();
+ if (ui->chkShowInactive->isChecked()){
+ if (ui->tableSummary->isRowHidden(row))
+ ui->tableSummary->showRow(row);
+ }else{
+ bool active = ui->tableSummary->item(row, 1)->foreground() != Qt::red;
+ if (!active){
+ ui->tableSummary->hideRow(row);
+ }
+ }
+ }
+ ui->tableSummary->resizeColumnsToContents();
+}
diff --git a/client/src/editors/GroupWidget.h b/client/src/editors/GroupWidget.h
index 601a358d..c93de90b 100644
--- a/client/src/editors/GroupWidget.h
+++ b/client/src/editors/GroupWidget.h
@@ -11,7 +11,9 @@
#include "widgets/TableDateWidgetItem.h"
#include "widgets/TableNumberWidgetItem.h"
+#ifndef OPENTERA_WEBASSEMBLY
#include "dialogs/SessionLobbyDialog.h"
+#endif
namespace Ui {
class GroupWidget;
@@ -23,9 +25,9 @@ class GroupWidget : public DataEditorWidget
public:
explicit GroupWidget(ComManager* comMan, const TeraData* data = nullptr, QWidget *parent = nullptr);
- ~GroupWidget();
+ ~GroupWidget() override;
- void saveData(bool signal=true);
+ void saveData(bool signal=true) override;
void connectSignals();
@@ -36,17 +38,17 @@ class GroupWidget : public DataEditorWidget
QList m_activeParticipants;
QMap m_ids_session_types;
-
+#ifndef OPENTERA_WEBASSEMBLY
SessionLobbyDialog* m_sessionLobby;
+#endif
+ void updateControlsState() override;
+ void updateFieldsValue() override;
- void updateControlsState();
- void updateFieldsValue();
-
- void setData(const TeraData* data);
+ void setData(const TeraData* data) override;
bool canStartSession();
- bool validateData();
+ bool validateData() override;
private slots:
void processFormsReply(QString form_type, QString data);
@@ -55,15 +57,17 @@ private slots:
void postResultReply(QString path);
void deleteDataReply(QString path, int del_id);
-
+#ifndef OPENTERA_WEBASSEMBLY
void showSessionLobby(const int& id_session_type, const int& id_session);
void sessionLobbyStartSessionRequested();
void sessionLobbyStartSessionCancelled();
-
+ void on_btnNewSession_clicked();
+#endif
void on_btnNewParticipant_clicked();
void on_btnDelete_clicked();
void on_tableSummary_itemSelectionChanged();
- void on_btnNewSession_clicked();
+
+ void on_chkShowInactive_stateChanged(int checked);
};
#endif // GROUPWIDGET_H
diff --git a/client/src/editors/GroupWidget.ui b/client/src/editors/GroupWidget.ui
index 1ce75076..66278299 100644
--- a/client/src/editors/GroupWidget.ui
+++ b/client/src/editors/GroupWidget.ui
@@ -160,126 +160,126 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
-
- 0
- 40
-
-
-
-
- 400
- 16777215
-
-
-
-
- -
-
-
- true
-
-
-
- 0
- 0
-
-
-
-
- 125
- 40
-
-
-
-
- 16777215
- 40
-
-
-
- PointingHandCursor
-
-
- Démarrer Séance
+
-
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+ 0
-
-
- :/icons/play.png:/icons/play.png
+
+ 0
-
-
- 24
- 24
-
+
+ 0
-
- false
+
+ 0
-
-
-
-
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 40
+
+
+
+
+ 400
+ 16777215
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+ 125
+ 40
+
+
+
+
+ 16777215
+ 40
+
+
+
+ PointingHandCursor
+
+
+ Démarrer Séance
+
+
+
+ :/icons/play.png:/icons/play.png
+
+
+
+ 24
+ 24
+
+
+
+ false
+
+
+
+
+
+
+
-
@@ -411,6 +411,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
Résumé
+
+ 15
+
-
@@ -528,6 +531,13 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ -
+
+
+ Qt::Horizontal
+
+
+
-
@@ -595,6 +605,13 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ -
+
+
+ Afficher les participants inactifs
+
+
+
diff --git a/client/src/editors/ParticipantWidget.cpp b/client/src/editors/ParticipantWidget.cpp
index 5959b820..40339748 100644
--- a/client/src/editors/ParticipantWidget.cpp
+++ b/client/src/editors/ParticipantWidget.cpp
@@ -15,9 +15,9 @@ ParticipantWidget::ParticipantWidget(ComManager *comMan, const TeraData *data, Q
DataEditorWidget(comMan, data, parent),
ui(new Ui::ParticipantWidget)
{
-
+#ifndef OPENTERA_WEBASSEMBLY
m_sessionLobby = nullptr;
-
+#endif
m_allowFileTransfers = false;
ui->setupUi(this);
@@ -76,11 +76,15 @@ ParticipantWidget::~ParticipantWidget()
qDeleteAll(m_ids_session_types);
delete ui;
- if (m_sessionLobby)
+#ifndef OPENTERA_WEBASSEMBLY
+ if (m_sessionLobby) {
m_sessionLobby->deleteLater();
+ }
+#endif
- if (m_diag_qr)
+ if (m_diag_qr) {
m_diag_qr->deleteLater();
+ }
}
@@ -132,8 +136,9 @@ void ParticipantWidget::connectSignals()
connect(ui->lstAvailDevices, &QListWidget::currentItemChanged, this, &ParticipantWidget::currentAvailDeviceChanged);
connect(ui->lstDevices, &QListWidget::currentItemChanged, this, &ParticipantWidget::currentDeviceChanged);
-
+#ifndef OPENTERA_WEBASSEMBLY
connect(ui->wdgSessions, &SessionsListWidget::startSessionRequested, this, &ParticipantWidget::showSessionLobby);
+#endif
connect(ui->wdgSessions, &SessionsListWidget::sessionsCountUpdated, this, &ParticipantWidget::sessionTotalCountUpdated);
}
@@ -169,6 +174,9 @@ void ParticipantWidget::updateFieldsValue()
if (!dataIsNew()){
ui->lblTitle->setText(m_data->getName());
ui->chkEnabled->setChecked(m_data->getFieldValue("participant_enabled").toBool());
+ if (m_data->hasFieldName("participant_project_enabled")){
+ ui->chkEnabled->setEnabled(m_data->getFieldValue("participant_project_enabled").toBool());
+ }
ui->chkLogin->setChecked(m_data->getFieldValue("participant_login_enabled").toBool());
if (ui->chkLogin->isChecked()){
ui->btnSaveLogin->setEnabled(false); // Disable save login infos on already enabled participants
@@ -186,7 +194,7 @@ void ParticipantWidget::updateFieldsValue()
on_txtPassword_textEdited("");
// Status
- ui->icoOnline->setVisible(m_data->isEnabled());
+ //ui->icoOnline->setVisible(m_data->isEnabled());
ui->icoTitle->setPixmap(QPixmap(m_data->getIconStateFilename()));
if (m_data->isBusy()){
ui->icoOnline->setPixmap(QPixmap("://status/status_busy.png"));
@@ -219,6 +227,7 @@ void ParticipantWidget::initUI()
ui->frameActive->hide();
ui->frameWeb->hide();
ui->txtWeb->hide();
+ ui->icoOnline->hide();
// Disable random password button, handled in the PasswordStrengthDialog now!
ui->btnRandomPass->hide();
@@ -364,7 +373,7 @@ void ParticipantWidget::updateServiceTabs()
QList ids_service;
- for(const TeraData &service: qAsConst(m_services)){
+ for(const TeraData &service: std::as_const(m_services)){
ids_service.append(service.getId());
// Create specific tabs for services
@@ -372,7 +381,7 @@ void ParticipantWidget::updateServiceTabs()
}
// Remove tabs not anymore present
- /*for(QWidget* tab: qAsConst(m_services_tabs)){
+ /*for(QWidget* tab: std::as_const(m_services_tabs)){
if (!ids_service.contains(m_services_tabs.key(tab))){
ui->tabNav->removeTab(ui->tabNav->indexOf(tab));
tab->deleteLater();
@@ -598,7 +607,7 @@ void ParticipantWidget::deleteDataReply(QString path, int id)
if (path == WEB_DEVICEPARTICIPANTINFO_PATH){
// A participant device association was deleted
- for (QListWidgetItem* item: qAsConst(m_listDevices_items)){
+ for (QListWidgetItem* item: std::as_const(m_listDevices_items)){
// Check for id_device_participant, which is stored in "data" of the item
if (item->data(Qt::UserRole).toInt() == id){
// We found it - remove it and request update
@@ -665,7 +674,7 @@ void ParticipantWidget::btnAddDevice_clicked()
if (diag->result() == DeviceAssignDialog::DEVICEASSIGN_DEASSIGN){
// Delete all associated participants
QList ids = diag->getDeviceParticipantsIds();
- for (int id:qAsConst(ids)){
+ for (int id:std::as_const(ids)){
deleteDataRequest(WEB_DEVICEPARTICIPANTINFO_PATH, id);
}
}
@@ -714,7 +723,7 @@ bool ParticipantWidget::isProjectAdmin()
return m_comManager->getCurrentUserProjectRole(m_data->getFieldValue("id_project").toInt()) == "admin";
}
-
+#ifndef OPENTERA_WEBASSEMBLY
void ParticipantWidget::showSessionLobby(const int &id_session_type, const int &id_session)
{
if (!canStartNewSession(id_session_type)){
@@ -738,6 +747,10 @@ void ParticipantWidget::showSessionLobby(const int &id_session_type, const int &
connect(m_sessionLobby, &QDialog::rejected, this, &ParticipantWidget::sessionLobbyStartSessionCancelled);
if (height()<800)
m_sessionLobby->showMaximized();
+ else{
+ m_sessionLobby->setMinimumSize(3*QGuiApplication::primaryScreen()->availableGeometry().width() / 4,
+ 2*QGuiApplication::primaryScreen()->availableGeometry().height() / 3);
+ }
// Show Session Lobby
m_sessionLobby->exec();
@@ -773,7 +786,7 @@ void ParticipantWidget::sessionLobbyStartSessionCancelled()
m_sessionLobby = nullptr;
}
}
-
+#endif
void ParticipantWidget::currentAvailDeviceChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
Q_UNUSED(previous)
@@ -876,7 +889,7 @@ void ParticipantWidget::on_chkLogin_stateChanged(int checkState)
ui->btnSaveLogin->setEnabled(false);
}else{
ui->txtPassword->setStyleSheet("background-color: #ffaaaa;");
- ui->btnSaveLogin->setEnabled(true);
+ ui->btnSaveLogin->setEnabled(false);
}
}
}
@@ -1019,7 +1032,9 @@ void ParticipantWidget::on_btnNewSession_clicked()
}
// If id_session == 0, will start a new session. Otherwise, will resume that session with id_session
+#ifndef OPENTERA_WEBASSEMBLY
showSessionLobby(id_session_type, id_session);
+#endif
}
void ParticipantWidget::on_btnViewLink_clicked()
@@ -1118,7 +1133,8 @@ void ParticipantWidget::on_tabNav_currentChanged(int index)
if (current_tab == ui->tabServices){ // Services
if (!ui->wdgServiceConfig->layout()){
QHBoxLayout* layout = new QHBoxLayout();
- layout->setMargin(0);
+
+ //layout->setMargin(0);
ui->wdgServiceConfig->setLayout(layout);
}
if (ui->wdgServiceConfig->layout()->count() == 0){
@@ -1131,12 +1147,14 @@ void ParticipantWidget::on_tabNav_currentChanged(int index)
void ParticipantWidget::on_lstAvailDevices_itemDoubleClicked(QListWidgetItem *item)
{
+ Q_UNUSED(item)
btnAddDevice_clicked();
}
void ParticipantWidget::on_lstDevices_itemDoubleClicked(QListWidgetItem *item)
{
+ Q_UNUSED(item)
btnDelDevice_clicked();
}
diff --git a/client/src/editors/ParticipantWidget.h b/client/src/editors/ParticipantWidget.h
index c34a3f4d..87eaf023 100644
--- a/client/src/editors/ParticipantWidget.h
+++ b/client/src/editors/ParticipantWidget.h
@@ -17,7 +17,10 @@
#include "TeraSettings.h"
#include "ServiceConfigWidget.h"
+#ifndef OPENTERA_WEBASSEMBLY
#include "dialogs/SessionLobbyDialog.h"
+#endif
+
#include "dialogs/EmailInviteDialog.h"
#include "dialogs/DeviceAssignDialog.h"
#include "dialogs/QRCodeDialog.h"
@@ -56,7 +59,9 @@ class ParticipantWidget : public DataEditorWidget
bool m_allowFileTransfers; // Allow to attach files to a session?
QRCodeDialog* m_diag_qr = nullptr;
+#ifndef OPENTERA_WEBASSEMBLY
SessionLobbyDialog* m_sessionLobby;
+#endif
QHash m_ids_session_types;
@@ -95,10 +100,11 @@ private slots:
void btnAddDevice_clicked();
void btnDelDevice_clicked();
-
+#ifndef OPENTERA_WEBASSEMBLY
void showSessionLobby(const int& id_session_type, const int& id_session);
void sessionLobbyStartSessionRequested();
void sessionLobbyStartSessionCancelled();
+#endif
void currentAvailDeviceChanged(QListWidgetItem* current, QListWidgetItem* previous);
void currentDeviceChanged(QListWidgetItem* current, QListWidgetItem* previous);
diff --git a/client/src/editors/ParticipantWidget.ui b/client/src/editors/ParticipantWidget.ui
index 1e8922ad..a28900d7 100644
--- a/client/src/editors/ParticipantWidget.ui
+++ b/client/src/editors/ParticipantWidget.ui
@@ -212,146 +212,146 @@ QCalendarWidget QSpinBox::down-arrow { width:16px; height:16px; }
-
-
-
-
- 0
- 0
-
-
-
-
- 32
- 32
-
-
-
-
-
-
- :/status/status_unknown.png
-
-
- true
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- true
-
+
-
+
0
0
-
-
- 0
- 40
-
+
+ QFrame::StyledPanel
-
-
- 400
- 16777215
-
+
+ QFrame::Raised
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 40
+
+
+
+
+ 400
+ 16777215
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+ 125
+ 40
+
+
+
+
+ 16777215
+ 40
+
+
+
+ PointingHandCursor
+
+
+ Démarrer Séance
+
+
+
+ :/icons/play.png:/icons/play.png
+
+
+
+ 24
+ 24
+
+
+
+ false
+
+
+
+
-
-
-
- true
-
+
-
+
0
0
-
-
- 125
- 40
-
-
- 16777215
- 40
+ 32
+ 32
-
- PointingHandCursor
-
- Démarrer Séance
-
-
-
- :/icons/play.png:/icons/play.png
+
-
-
- 24
- 24
-
+
+ :/status/status_unknown.png
-
- false
+
+ true
diff --git a/client/src/editors/ProjectWidget.cpp b/client/src/editors/ProjectWidget.cpp
index a860d581..97b8b9aa 100644
--- a/client/src/editors/ProjectWidget.cpp
+++ b/client/src/editors/ProjectWidget.cpp
@@ -2,13 +2,13 @@
#include "ui_ProjectWidget.h"
#include "editors/DataListWidget.h"
-#include "Logger.h"
ProjectWidget::ProjectWidget(ComManager *comMan, const TeraData *data, QWidget *parent) :
DataEditorWidget(comMan, data, parent),
ui(new Ui::ProjectWidget)
{
m_diag_editor = nullptr;
+ m_refreshProjectParticipants = false;
ui->setupUi(this);
@@ -29,10 +29,12 @@ ProjectWidget::ProjectWidget(ComManager *comMan, const TeraData *data, QWidget *
queryDataRequest(WEB_FORMS_PATH, QUrlQuery(WEB_FORMS_QUERY_PROJECT));
ui->wdgProject->setComManager(m_comManager);
+ ui->wdgProject->setSectionsPosition(QTabWidget::North);
if (data->isNew()){
// Connect session-type site for new project
connect(m_comManager, &ComManager::sessionTypesSitesReceived, this, &ProjectWidget::processSessionTypeSiteReply);
+ connect(m_comManager, &ComManager::testTypesSitesReceived, this, &ProjectWidget::processTestTypeSiteReply);
}
ProjectWidget::setData(data);
@@ -59,7 +61,7 @@ void ProjectWidget::saveData(bool signal)
QJsonObject base_st = base_obj["project"].toObject();
QJsonArray session_types;
- for(QListWidgetItem* item:qAsConst(m_listSessionTypes_items)){
+ for(QListWidgetItem* item:std::as_const(m_listSessionTypes_items)){
if (item->checkState() == Qt::Checked){
int session_type_id = m_listSessionTypes_items.key(item);
QJsonObject data_obj;
@@ -80,6 +82,10 @@ void ProjectWidget::saveData(bool signal)
if (signal){
TeraData* new_data = ui->wdgProject->getFormDataObject(TERADATA_PROJECT);
+ if (m_data->isEnabled() && !new_data->isEnabled()){
+ // Project was disabled. Also forces participants from that project refresh when we get the "Post" reply
+ m_refreshProjectParticipants = true;
+ }
*m_data = *new_data;
delete new_data;
emit dataWasChanged();
@@ -96,7 +102,6 @@ void ProjectWidget::setData(const TeraData *data)
args.addQueryItem(WEB_QUERY_ID_PROJECT, QString::number(m_data->getId()));
args.addQueryItem(WEB_QUERY_WITH_PARTICIPANTS, "1");
queryDataRequest(WEB_STATS_PATH, args);
-
}
}
@@ -107,6 +112,7 @@ void ProjectWidget::connectSignals()
connect(m_comManager, &ComManager::postResultsOK, this, &ProjectWidget::processPostOKReply);
connect(m_comManager, &ComManager::servicesProjectsReceived, this, &ProjectWidget::processServiceProjectsReply);
connect(m_comManager, &ComManager::sessionTypesProjectsReceived, this, &ProjectWidget::processSessionTypeProjectReply);
+ connect(m_comManager, &ComManager::testTypesProjectsReceived, this, &ProjectWidget::processTestTypeProjectReply);
connect(m_comManager, &ComManager::statsReceived, this, &ProjectWidget::processStatsReply);
connect(m_comManager, &ComManager::deleteResultsOK, this, &ProjectWidget::deleteDataReply);
@@ -206,7 +212,7 @@ void ProjectWidget::updateDevice(const TeraData *device)
// Add participants to devices
if (device->hasFieldName("device_participants")){
QVariantList participants = device->getFieldValue("device_participants").toList();
- for(const QVariant &participant: qAsConst(participants)){
+ for(const QVariant &participant: std::as_const(participants)){
QVariantHash part_info = participant.toHash();
if (part_info.contains("id_project")){
if (part_info["id_project"].toInt() != m_data->getId())
@@ -386,6 +392,157 @@ void ProjectWidget::updateSessionTypeSite(const TeraData *sts)
item->setText(st_name);
}
+void ProjectWidget::updateTestTypeProject(const TeraData *ttp)
+{
+ int id_tt_project = ttp->getId();
+ int id_test_type = ttp->getFieldValue("id_test_type").toInt();
+ QString tt_name;
+ if (ttp->hasFieldName("test_type_name"))
+ tt_name = ttp->getFieldValue("test_type_name").toString();
+
+ QListWidgetItem* item;
+ if (m_listTestTypes_items.contains(id_test_type)){
+ item = m_listTestTypes_items[id_test_type];
+ }else{
+ // Must create a new item
+ item = new QListWidgetItem(tt_name);
+ item->setIcon(QIcon(TeraData::getIconFilenameForDataType(TERADATA_TESTTYPE)));
+ ui->lstTestTypes->addItem(item);
+
+ m_listTestTypes_items[id_test_type] = item;
+ }
+
+ if (!tt_name.isEmpty())
+ item->setText(tt_name);
+
+ if (ttp->getFieldValue("id_project").toInt() == m_data->getId()){
+ item->setCheckState(Qt::Checked);
+ if (!m_listTestTypesProjects_items.contains(id_tt_project)){
+ m_listTestTypesProjects_items[id_tt_project] = item;
+ }
+ }else{
+ item->setCheckState(Qt::Unchecked);
+ if (m_listTestTypesProjects_items.contains(id_tt_project)){
+ m_listTestTypesProjects_items.remove(id_tt_project);
+ }
+ }
+}
+
+void ProjectWidget::updateTestTypeSite(const TeraData *tts)
+{
+ int id_test_type = tts->getFieldValue("id_test_type").toInt();
+ QString tt_name;
+ if (tts->hasFieldName("test_type_name"))
+ tt_name = tts->getFieldValue("test_type_name").toString();
+
+ QListWidgetItem* item;
+ if (m_listTestTypes_items.contains(id_test_type)){
+ item = m_listTestTypes_items[id_test_type];
+ }else{
+ // Must create a new item
+ item = new QListWidgetItem(tt_name);
+ item->setIcon(QIcon(TeraData::getIconFilenameForDataType(TERADATA_TESTTYPE)));
+ item->setCheckState(Qt::Unchecked);
+ ui->lstTestTypes->addItem(item);
+
+ m_listTestTypes_items[id_test_type] = item;
+ }
+
+ if (!tt_name.isEmpty())
+ item->setText(tt_name);
+}
+
+void ProjectWidget::updateParticipant(const TeraData *participant)
+{
+ QTableWidgetItem* item_name;
+ QTableWidgetItem* item_state;
+ TableNumberWidgetItem* item_sessions;
+ TableDateWidgetItem* item_first_session;
+ TableDateWidgetItem* item_last_session;
+ TableDateWidgetItem* item_last_online;
+
+ if (m_tableParticipants_items.contains(participant->getId())){
+ item_name = m_tableParticipants_items[participant->getId()];
+ int row = item_name->row();
+ item_state = ui->tableSummary->item(row, 1);
+ item_sessions = dynamic_cast(ui->tableSummary->item(row, 2));
+ item_first_session = dynamic_cast(ui->tableSummary->item(row, 3));
+ item_last_session = dynamic_cast(ui->tableSummary->item(row, 4));
+ item_last_online = dynamic_cast(ui->tableSummary->item(row, 5));
+ }else{
+ // Create new widget items
+ item_name = new QTableWidgetItem(QIcon(TeraData::getIconFilenameForDataType(TERADATA_PARTICIPANT)), participant->getName());
+ m_tableParticipants_items[participant->getId()] = item_name;
+
+ ui->tableSummary->setRowCount(ui->tableSummary->rowCount()+1);
+ int current_row = ui->tableSummary->rowCount()-1;
+
+ ui->tableSummary->setItem(current_row, 0, item_name);
+
+ item_state = new QTableWidgetItem();
+ item_state->setTextAlignment(Qt::AlignCenter);
+ ui->tableSummary->setItem(current_row, 1, item_state);
+
+ item_sessions = new TableNumberWidgetItem();
+ item_sessions->setTextAlignment(Qt::AlignCenter);
+ ui->tableSummary->setItem(current_row, 2, item_sessions);
+
+ item_first_session = new TableDateWidgetItem();
+ item_first_session->setTextAlignment(Qt::AlignCenter);
+ ui->tableSummary->setItem(current_row, 3, item_first_session);
+ item_last_session = new TableDateWidgetItem();
+ item_last_session->setTextAlignment(Qt::AlignCenter);
+ ui->tableSummary->setItem(current_row, 4, item_last_session);
+
+ item_last_online = new TableDateWidgetItem();
+ item_last_online->setTextAlignment(Qt::AlignCenter);
+ ui->tableSummary->setItem(current_row, 5, item_last_online);
+ }
+
+ // Set current values
+ item_name->setText(participant->getName());
+ QString status;
+ if (participant->isEnabled()){
+ status = tr("Actif");
+ item_state->setForeground(Qt::green);
+ ui->tableSummary->showRow(item_state->row());
+ }else{
+ status = tr("Inactif");
+ item_state->setForeground(Qt::red);
+ if (!ui->chkShowInactive->isChecked())
+ ui->tableSummary->hideRow(item_state->row());
+ }
+ item_state->setText(status);
+ if (participant->hasFieldName("participant_sessions_count")){
+ item_sessions->setText(participant->getFieldValue("participant_sessions_count").toString());
+ }
+ if (participant->hasFieldName("participant_first_session")){
+ item_first_session->setDate(participant->getFieldValue("participant_first_session").toDateTime().toLocalTime());
+ }
+ if (participant->hasFieldName("participant_last_session")){
+ QDateTime last_session_datetime = participant->getFieldValue("participant_last_session").toDateTime().toLocalTime();
+ item_last_session->setDate(last_session_datetime);
+ if (participant->isEnabled() && last_session_datetime.isValid()){
+ // Set background color
+ QColor back_color = TeraForm::getGradientColor(0, 7, 14, static_cast(last_session_datetime.daysTo(QDateTime::currentDateTime())));
+ back_color.setAlphaF(0.5);
+ item_last_session->setBackground(back_color);
+ }
+ }
+ if (participant->hasFieldName("participant_last_online")){
+ QDateTime last_connect_datetime = participant->getFieldValue("participant_last_online").toDateTime().toLocalTime();
+ item_last_online->setDate(last_connect_datetime);
+ if (participant->isEnabled() && last_connect_datetime.isValid()){
+ // Set background color
+ QColor back_color = TeraForm::getGradientColor(0, 7, 14, static_cast(last_connect_datetime.daysTo(QDateTime::currentDateTime())));
+ back_color.setAlphaF(0.5);
+ item_last_online->setBackground(back_color);
+ }
+ }
+
+
+}
+
void ProjectWidget::queryServicesProject()
{
// Query services for this project
@@ -403,6 +560,14 @@ void ProjectWidget::querySessionTypesProject()
queryDataRequest(WEB_SESSIONTYPEPROJECT_PATH, args);
}
+void ProjectWidget::queryTestTypesProject()
+{
+ QUrlQuery args;
+ args.addQueryItem(WEB_QUERY_ID_PROJECT, QString::number(m_data->getId()));
+ args.addQueryItem(WEB_QUERY_WITH_TESTTYPES, "1");
+ queryDataRequest(WEB_TESTTYPEPROJECT_PATH, args);
+}
+
void ProjectWidget::updateControlsState()
{
if (dataIsNew() && ui->tabNav->count() > 1){
@@ -413,6 +578,7 @@ void ProjectWidget::updateControlsState()
// Move projects list to first tab
ui->tabSessionTypes->layout()->removeWidget(ui->lstSessionTypes);
+ ui->tabTestTypes->layout()->removeWidget(ui->lstTestTypes);
ui->tabDashboard->layout()->removeWidget(ui->frameButtons);
QLabel* lbl = new QLabel(tr("Types de séances associés"));
@@ -423,6 +589,10 @@ void ProjectWidget::updateControlsState()
ui->tabDashboard->layout()->addWidget(lbl);
ui->tabDashboard->layout()->addWidget(ui->lstSessionTypes);
+ lbl = new QLabel(tr("Types de tests associés"));
+ lbl->setFont(labelFont);
+ ui->tabDashboard->layout()->addWidget(lbl);
+ ui->tabDashboard->layout()->addWidget(ui->lstTestTypes);
ui->tabDashboard->layout()->addWidget(ui->frameButtons);
ui->frameActions->hide(); // Can't add participant when creating new project
@@ -434,6 +604,13 @@ void ProjectWidget::updateControlsState()
queryDataRequest(WEB_SESSIONTYPESITE_PATH, args);
}
+ // Query test types
+ if (m_listTestTypes_items.isEmpty()){
+ QUrlQuery args;
+ args.addQueryItem(WEB_QUERY_ID_SITE, m_data->getFieldValue("id_site").toString());
+ queryDataRequest(WEB_TESTTYPESITE_PATH, args);
+ }
+
}else{
bool is_project_admin = m_comManager->isCurrentUserProjectAdmin(m_data->getId());
@@ -444,6 +621,7 @@ void ProjectWidget::updateControlsState()
ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabUsersDetails), is_project_admin);
ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabDevices), is_project_admin);
ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabSessionTypes), is_project_admin);
+ ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabTestTypes), is_project_admin);
ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabServicesDetails), is_site_admin || !m_services_tabs.isEmpty());
ui->btnNewGroup->setEnabled(is_project_admin);
@@ -467,6 +645,7 @@ void ProjectWidget::updateFieldsValue()
if (m_data){
ui->wdgProject->fillFormFromData(m_data->toJson());
ui->lblTitle->setText(m_data->getName());
+ ui->icoTitle->setPixmap(QPixmap(m_data->getIconStateFilename()));
if (dataIsNew() && m_data->hasFieldName("id_site")){
// New project - locked to that site
@@ -477,6 +656,19 @@ void ProjectWidget::updateFieldsValue()
bool ProjectWidget::validateData()
{
+ bool editedProjectEnabled = ui->wdgProject->getFieldValue("project_enabled").toBool();
+
+ if (!editedProjectEnabled && m_data->getFieldValue("project_enabled").toBool()){
+ // We changed from "enabled" to "disabled". User confirmation required before proceeding.
+ GlobalMessageBox msg;
+ GlobalMessageBox::StandardButton rval = msg.showYesNo(tr("Confirmation - désactivation"), tr("Le project sera désactivé.") + "\n\r" +
+ tr("Tous les participants seront aussi désactivés et les appareils associés à ceux-ci seront désassociés.") + "\n\r" +
+ tr("Êtes-vous sûrs de vouloir continuer?"));
+ if (rval != GlobalMessageBox::Yes){
+ undoButtonClicked();
+ return false;
+ }
+ }
return ui->wdgProject->validateFormData();
}
@@ -540,6 +732,25 @@ void ProjectWidget::processProjectAccessReply(QList access, QUrlQuery
}
}
+void ProjectWidget::processParticipantsReply(QList participants, QUrlQuery reply_query)
+{
+ if (!m_data)
+ return;
+
+ // Check if that reply is for us or not.
+ if (!reply_query.hasQueryItem(WEB_QUERY_ID_PROJECT))
+ return;
+
+ if (reply_query.queryItemValue(WEB_QUERY_ID_PROJECT).toInt() != m_data->getId())
+ return;
+
+ // Only update state for now...
+ for (int i=0; i devices)
{
if (!m_data)
@@ -607,40 +818,12 @@ void ProjectWidget::processServiceProjectsReply(QList services_project
for (int i=0; ilstServices->count(); i++){
QListWidgetItem* item = ui->lstServices->item(i);
if (item->checkState() == Qt::Unchecked){
- if (std::find(m_listServicesProjects_items.cbegin(), m_listServicesProjects_items.cend(), item) != m_listServicesProjects_items.cend()){
- m_listServicesProjects_items.remove(m_listServicesProjects_items.key(item));
+ int item_key = m_listServicesProjects_items.key(item, -1);
+ if (item_key > 0){
+ m_listServicesProjects_items.remove(item_key);
}
}
}
-
- // Remove service tabs not present anymore
- /*if (!dataIsNew()){
- QList tabs_to_del;
- for(QWidget* tab: qAsConst(m_services_tabs)){
- if (!ids_service.contains(m_services_tabs.key(tab))){
- tabs_to_del.append(tab);
- }
- }
- for(QWidget *tab: tabs_to_del){
- ui->tabNav->removeTab(ui->tabNav->indexOf(tab));
- tab->deleteLater();
- m_services_tabs.remove(m_services_tabs.key(tab));
- }
- }*/
-
- /*bool services_empty = m_services.isEmpty();
- foreach(TeraData service, services){
- if(service.getFieldValue("id_project").toInt() == m_data->getId()){
- updateService(&service);
- }
- }
-
- if (services_empty){
- QUrlQuery args;
- args.addQueryItem(WEB_QUERY_ID_PROJECT, QString::number(m_data->getId()));
- args.addQueryItem(WEB_QUERY_WITH_USERGROUPS, "1"); // Includes user groups without any access
- queryDataRequest(WEB_SERVICEACCESSINFO_PATH, args);
- }*/
}
void ProjectWidget::processSessionTypeProjectReply(QList stp_list, QUrlQuery reply_query)
@@ -656,8 +839,9 @@ void ProjectWidget::processSessionTypeProjectReply(QList stp_list, QUr
for (int i=0; ilstSessionTypes->count(); i++){
QListWidgetItem* item = ui->lstSessionTypes->item(i);
if (item->checkState() == Qt::Unchecked){
- if (std::find(m_listSessionTypesProjects_items.cbegin(), m_listSessionTypesProjects_items.cend(), item) != m_listSessionTypesProjects_items.cend()){
- m_listSessionTypesProjects_items.remove(m_listSessionTypesProjects_items.key(item));
+ int item_key = m_listSessionTypesProjects_items.key(item, -1);
+ if (item_key > 0){
+ m_listSessionTypesProjects_items.remove(item_key);
}
}
}
@@ -670,6 +854,34 @@ void ProjectWidget::processSessionTypeSiteReply(QList sts_list, QUrlQu
}
}
+void ProjectWidget::processTestTypeProjectReply(QList ttp_list, QUrlQuery reply_query)
+{
+ foreach(TeraData tt_project, ttp_list){
+ updateTestTypeProject(&tt_project);
+ }
+
+ // New list received - disable save button
+ ui->btnUpdateTestTypes->setEnabled(false);
+
+ // Update used list from what is checked right now
+ for (int i=0; ilstTestTypes->count(); i++){
+ QListWidgetItem* item = ui->lstTestTypes->item(i);
+ if (item->checkState() == Qt::Unchecked){
+ int item_key = m_listTestTypesProjects_items.key(item, -1);
+ if (item_key > 0){
+ m_listTestTypesProjects_items.remove(item_key);
+ }
+ }
+ }
+}
+
+void ProjectWidget::processTestTypeSiteReply(QList tts_list, QUrlQuery reply_query)
+{
+ foreach(TeraData tt_site, tts_list){
+ updateTestTypeSite(&tt_site);
+ }
+}
+
void ProjectWidget::processStatsReply(TeraData stats, QUrlQuery reply_query)
{
// Check if stats are for us
@@ -694,70 +906,20 @@ void ProjectWidget::processStatsReply(TeraData stats, QUrlQuery reply_query)
QVariantList parts_list = stats.getFieldValue("participants").toList();
- for(const QVariant &part:qAsConst(parts_list)){
+ /*ui->tableSummary->setRowCount(parts_list.count());
+ int current_row = 0;*/
+ for(const QVariant &part:std::as_const(parts_list)){
QVariantMap part_info = part.toMap();
- int part_id = part_info["id_participant"].toInt();
-
- ui->tableSummary->setRowCount(ui->tableSummary->rowCount()+1);
- int current_row = ui->tableSummary->rowCount()-1;
- QTableWidgetItem* item = new QTableWidgetItem(QIcon(TeraData::getIconFilenameForDataType(TERADATA_PARTICIPANT)),
- part_info["participant_name"].toString());
- m_tableParticipants_items[part_id] = item;
- ui->tableSummary->setItem(current_row, 0, item);
-
- item = new QTableWidgetItem();
- QString status;
- if (part_info["participant_enabled"].toBool() == true){
- status = tr("Actif");
- item->setForeground(Qt::green);
- }else{
- status = tr("Inactif");
- item->setForeground(Qt::red);
- }
- item->setText(status);
- item->setTextAlignment(Qt::AlignCenter);
- ui->tableSummary->setItem(current_row, 1, item);
-
- item = new TableNumberWidgetItem(part_info["participant_sessions_count"].toString());
- item->setTextAlignment(Qt::AlignCenter);
- ui->tableSummary->setItem(current_row, 2, item);
-
- item = new TableDateWidgetItem(part_info["participant_first_session"].toDateTime().toLocalTime().toString("dd-MM-yyyy hh:mm:ss"));
- item->setTextAlignment(Qt::AlignCenter);
- ui->tableSummary->setItem(current_row, 3, item);
-
- QDateTime last_session_datetime = part_info["participant_last_session"].toDateTime().toLocalTime();
- item = new TableDateWidgetItem(last_session_datetime.toString("dd-MM-yyyy hh:mm:ss"));
- if (part_info["participant_enabled"].toBool() == true && last_session_datetime.isValid()){
- // Set background color
- QColor back_color = TeraForm::getGradientColor(0, 7, 14, static_cast(last_session_datetime.daysTo(QDateTime::currentDateTime())));
- back_color.setAlphaF(0.5);
- item->setBackground(back_color);
- }
- item->setTextAlignment(Qt::AlignCenter);
- ui->tableSummary->setItem(current_row, 4, item);
-
- QString last_connect;
- QDateTime last_connect_datetime;
- if (part_info.contains("participant_last_online")){
- last_connect_datetime = part_info["participant_last_online"].toDateTime().toLocalTime();
- if (last_connect_datetime.isValid())
- last_connect = last_connect_datetime.toString("dd-MM-yyyy hh:mm:ss");
- }
- item = new TableDateWidgetItem(last_connect);
- item->setTextAlignment(Qt::AlignCenter);
-
- if (part_info["participant_enabled"].toBool() == true && last_connect_datetime.isValid()){
- // Set background color
- QColor back_color = TeraForm::getGradientColor(0, 5, 10, static_cast(last_connect_datetime.daysTo(QDateTime::currentDateTime())));
- back_color.setAlphaF(0.5);
- item->setBackground(back_color);
- }
- ui->tableSummary->setItem(current_row, 5, item);
+ TeraData data(TeraDataTypes::TERADATA_PARTICIPANT);
+ data.fromMap(part_info);
+ updateParticipant(&data);
}
- ui->tableSummary->resizeColumnsToContents();
ui->tableSummary->sortByColumn(4, Qt::DescendingOrder); // Sort by last session date
+ ui->tableSummary->resizeColumnsToContents();
}
+
+ // Connect signal to receive participants updates from now on
+ connect(m_comManager, &ComManager::participantsReceived, this, &ProjectWidget::processParticipantsReply);
}
void ProjectWidget::processPostOKReply(QString path)
@@ -765,6 +927,13 @@ void ProjectWidget::processPostOKReply(QString path)
if (path == WEB_PROJECTINFO_PATH){
// Update current user access list for the newly created project
m_comManager->doUpdateCurrentUser();
+ if (m_refreshProjectParticipants){
+ // Also refresh participants list to show disabled participants
+ m_refreshProjectParticipants = false;
+ QUrlQuery args;
+ args.addQueryItem(WEB_QUERY_ID_PROJECT, QString::number(m_data->getId()));
+ queryDataRequest(WEB_PARTICIPANTINFO_PATH, args);
+ }
}
if (path == WEB_SESSIONTYPEPROJECT_PATH || path == WEB_TESTTYPEPROJECT_PATH){
// Also update associated services
@@ -812,7 +981,7 @@ void ProjectWidget::btnUpdateAccess_clicked()
QMap::iterator i;
//for (int i=0; irow();
QComboBox* combo_roles = dynamic_cast(ui->tableUserGroups->cellWidget(row,1));
@@ -1033,25 +1202,18 @@ void ProjectWidget::on_tabNav_currentChanged(int index)
if (current_tab == ui->tabSessionTypes){
// Session types
- /*if (!ui->wdgSessionTypes->layout()){
- QHBoxLayout* layout = new QHBoxLayout();
- layout->setMargin(0);
- ui->wdgSessionTypes->setLayout(layout);
- }
- if (ui->wdgSessionTypes->layout()->count() == 0){
- args.addQueryItem(WEB_QUERY_ID_PROJECT, QString::number(m_data->getId()));
- DataListWidget* stlist_editor = new DataListWidget(m_comManager, TERADATA_SESSIONTYPE, WEB_SESSIONTYPEPROJECT_PATH, args, QStringList(), ui->wdgSessionTypes);
- // m_limited = true = user only, not project admin
- stlist_editor->setPermissions(!m_limited, !m_limited);
- stlist_editor->setFilterText(tr("Seuls les types de séance associés au projet sont affichés."));
- ui->wdgSessionTypes->layout()->addWidget(stlist_editor);
- }*/
-
if (m_listSessionTypesProjects_items.isEmpty()){
querySessionTypesProject();
}
}
+ if (current_tab == ui->tabTestTypes){
+ // Test types
+ if (m_listTestTypesProjects_items.isEmpty()){
+ queryTestTypesProject();
+ }
+ }
+
if (current_tab == ui->tabServicesDetails){
ui->tabManageServices->setCurrentIndex(0);
}
@@ -1108,22 +1270,8 @@ void ProjectWidget::on_btnUpdateSessionTypes_clicked()
item_obj.insert("id_session_type", session_type_id);
st_projects.append(item_obj);
}
- /*if (item->checkState() == Qt::Unchecked){
- // Unselected
- if (std::find(m_listSessionTypesProjects_items.cbegin(), m_listSessionTypesProjects_items.cend(), item) != m_listSessionTypesProjects_items.cend()){
- removed_sts = true;
- }
- }*/
}
- /*if (removed_sts){
- GlobalMessageBox msgbox;
- int rval = msgbox.showYesNo(tr("Suppression de type de séance associé"), tr("Au moins un type de séance a été retiré de ce project. S'il y a des types de séances qui utilisent ce service, elles ne seront plus accessibles.\nSouhaitez-vous continuer?"));
- if (rval != GlobalMessageBox::Yes){
- return;
- }
- }*/
-
project_obj.insert("sessiontypes", st_projects);
base_obj.insert("project", project_obj);
document.setObject(base_obj);
@@ -1271,3 +1419,65 @@ void ProjectWidget::on_btnManageUsers_clicked()
m_diag_editor->open();
}
+
+void ProjectWidget::on_chkShowInactive_stateChanged(int state)
+{
+ for(QTableWidgetItem* item: m_tableParticipants_items){
+ int row = item->row();
+ if (ui->chkShowInactive->isChecked()){
+ if (ui->tableSummary->isRowHidden(row))
+ ui->tableSummary->showRow(row);
+ }else{
+ bool active = ui->tableSummary->item(row, 1)->foreground() != Qt::red;
+ if (!active){
+ ui->tableSummary->hideRow(row);
+ }
+ }
+ }
+ ui->tableSummary->resizeColumnsToContents();
+}
+
+
+void ProjectWidget::on_lstTestTypes_itemChanged(QListWidgetItem *item)
+{
+ // Check for changed items
+ bool has_changes = false;
+ if (m_listTestTypesProjects_items.key(item) > 0 && item->checkState() == Qt::Unchecked){
+ // Item deselected
+ has_changes = true;
+ }else{
+ if (m_listTestTypesProjects_items.key(item, -1) <= 0 && item->checkState() == Qt::Checked){
+ // Item selected
+ has_changes = true;
+ }
+ }
+
+ ui->btnUpdateTestTypes->setEnabled(has_changes);
+}
+
+
+void ProjectWidget::on_btnUpdateTestTypes_clicked()
+{
+ QJsonDocument document;
+ QJsonObject base_obj;
+ QJsonObject project_obj;
+ QJsonArray tt_projects;
+
+ project_obj.insert("id_project", m_data->getId());
+ for (int i=0; ilstTestTypes->count(); i++){
+ QListWidgetItem* item = ui->lstTestTypes->item(i);
+ int test_type_id = m_listTestTypes_items.key(item, 0);
+ if (item->checkState() == Qt::Checked){
+ // New item selected
+ QJsonObject item_obj;
+ item_obj.insert("id_test_type", test_type_id);
+ tt_projects.append(item_obj);
+ }
+ }
+
+ project_obj.insert("testtypes", tt_projects);
+ base_obj.insert("project", project_obj);
+ document.setObject(base_obj);
+ postDataRequest(WEB_TESTTYPEPROJECT_PATH, document.toJson());
+}
+
diff --git a/client/src/editors/ProjectWidget.h b/client/src/editors/ProjectWidget.h
index 93fb78fc..2b6ddbaf 100644
--- a/client/src/editors/ProjectWidget.h
+++ b/client/src/editors/ProjectWidget.h
@@ -34,15 +34,16 @@ class ProjectWidget : public DataEditorWidget
private slots:
void processFormsReply(QString form_type, QString data);
void processProjectAccessReply(QList access, QUrlQuery reply_query);
+ void processParticipantsReply(QList participants, QUrlQuery reply_query);
void processDevicesReply(QList devices);
void processDevicesProjectsReply(QList devices_projects);
void processServiceProjectsReply(QList services);
void processSessionTypeProjectReply(QList stp_list, QUrlQuery reply_query);
void processSessionTypeSiteReply(QList sts_list, QUrlQuery reply_query);
+ void processTestTypeProjectReply(QList ttp_list, QUrlQuery reply_query);
+ void processTestTypeSiteReply(QList tts_list, QUrlQuery reply_query);
void processStatsReply(TeraData stats, QUrlQuery reply_query);
-
void processPostOKReply(QString path);
-
void deleteDataReply(QString path, int del_id);
void btnUpdateAccess_clicked();
@@ -51,56 +52,58 @@ private slots:
void on_icoUsers_clicked();
void on_icoSessions_clicked();
void on_btnUserGroups_clicked();
- void userGroupsEditor_finished();
+ void userGroupsEditor_finished();
void usersEditor_finished();
void on_tableSummary_itemDoubleClicked(QTableWidgetItem *item);
-
void on_lstServices_itemChanged(QListWidgetItem *item);
-
void on_tabNav_currentChanged(int index);
void on_tabManageUsers_currentChanged(int index);
void on_tabManageServices_currentChanged(int index);
void on_btnUpdateSessionTypes_clicked();
-
void on_lstSessionTypes_itemChanged(QListWidgetItem *item);
-
-
void on_treeDevices_itemChanged(QTreeWidgetItem *item, int column);
-
void on_btnUpdateDevices_clicked();
-
void on_btnNewParticipant_clicked();
void on_btnNewGroup_clicked();
void on_btnDelete_clicked();
-
void on_tableSummary_itemSelectionChanged();
-
void on_btnManageUsers_clicked();
+ void on_chkShowInactive_stateChanged(int state);
+
+ void on_lstTestTypes_itemChanged(QListWidgetItem *item);
+
+ void on_btnUpdateTestTypes_clicked();
+
private:
- Ui::ProjectWidget *ui;
+ Ui::ProjectWidget *ui;
+
+ QHash m_tableUsers_items;
+ QMap m_tableUserGroups_items;
+ QHash m_tableParticipants_items;
+ QHash m_listGroups_items;
+
+ QHash m_treeDevices_items;
+ QHash m_treeDevicesProjects_items;
- QMap m_tableUsers_items;
- QMap m_tableUserGroups_items;
- QMap m_tableParticipants_items;
- QMap m_listGroups_items;
+ QHash m_listServicesProjects_items;
+ QHash m_listServices_items;
+ QHash m_services_keys;
- QMap m_treeDevices_items;
- QMap m_treeDevicesProjects_items;
+ QHash m_listSessionTypesProjects_items;
+ QHash m_listSessionTypes_items;
- QMap m_listServicesProjects_items;
- QMap m_listServices_items;
- QMap m_services_keys;
+ QHash m_listTestTypesProjects_items;
+ QHash m_listTestTypes_items;
- QMap m_listSessionTypesProjects_items;
- QMap m_listSessionTypes_items;
+ QHash m_services_tabs;
- QMap m_services_tabs;
+ BaseDialog* m_diag_editor;
- BaseDialog* m_diag_editor;
+ bool m_refreshProjectParticipants;
void connectSignals();
void initUI();
@@ -112,9 +115,13 @@ private slots:
void updateServiceProject(const TeraData* sp);
void updateSessionTypeProject(const TeraData* stp);
void updateSessionTypeSite(const TeraData* sts);
+ void updateTestTypeProject(const TeraData* ttp);
+ void updateTestTypeSite(const TeraData* tts);
+ void updateParticipant(const TeraData* participant);
void queryServicesProject();
void querySessionTypesProject();
+ void queryTestTypesProject();
void queryUserGroupsProjectAccess();
void queryUsers();
diff --git a/client/src/editors/ProjectWidget.ui b/client/src/editors/ProjectWidget.ui
index 12af75a5..4f6e36aa 100644
--- a/client/src/editors/ProjectWidget.ui
+++ b/client/src/editors/ProjectWidget.ui
@@ -162,7 +162,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- 0
+ 3
@@ -195,6 +195,12 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
0
+
+
+ 16777215
+ 150
+
+
-
@@ -227,6 +233,12 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
+
+ 0
+ 0
+
+
-
@@ -285,10 +297,19 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
+
+ 0
+ 0
+
+
Résumé
+
+ 15
+
-
@@ -491,6 +512,13 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ -
+
+
+ Qt::Horizontal
+
+
+
-
-
@@ -562,6 +590,13 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ -
+
+
+ Afficher les participants inactifs
+
+
+
@@ -709,7 +744,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
QTabWidget::West
- 0
+ 1
@@ -815,6 +850,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
true
+
+ false
+
Utilisateur
@@ -955,6 +993,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
true
+
+ false
+
Groupe Utilisateur
@@ -1010,6 +1051,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
+ QAbstractItemView::NoEditTriggers
+
24
@@ -1046,6 +1090,56 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+
+
+
+ :/icons/test_type.png:/icons/test_type.png
+
+
+ Types de tests
+
+
+ -
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+
+ 24
+ 24
+
+
+
+
+ -
+
+
+
+ 0
+ 32
+
+
+
+ PointingHandCursor
+
+
+ Mettre à jour les types de tests associés
+
+
+
+ :/icons/save.png:/icons/save.png
+
+
+
+ 24
+ 24
+
+
+
+
+
+
@@ -1061,14 +1155,17 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
QAbstractItemView::NoEditTriggers
- QAbstractItemView::NoSelection
+ QAbstractItemView::SingleSelection
- 20
- 20
+ 24
+ 24
+
+ 0
+
false
@@ -1141,6 +1238,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
+ QAbstractItemView::NoEditTriggers
+
24
@@ -1184,14 +1284,19 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+
+
+
+ 0
+ 0
+ 100
+ 30
+
+
+
+
-
- TeraForm
- QWidget
-
- 1
-
ClickableLabel
QLabel
@@ -1201,6 +1306,12 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
clicked()
+
+ TeraForm
+ QWidget
+
+ 1
+
diff --git a/client/src/editors/ServiceConfigWidget.cpp b/client/src/editors/ServiceConfigWidget.cpp
index dcea5a1c..38879a1f 100644
--- a/client/src/editors/ServiceConfigWidget.cpp
+++ b/client/src/editors/ServiceConfigWidget.cpp
@@ -7,7 +7,6 @@ ServiceConfigWidget::ServiceConfigWidget(ComManager *comMan, const QString id_fi
{
ui->setupUi(this);
-
setAttribute(Qt::WA_StyledBackground); //Required to set a background image
setLimited(false);
@@ -119,7 +118,7 @@ void ServiceConfigWidget::updateFieldsValue(){
QVariantList specifics = m_data->getFieldValue("service_config_specifics").toList();
if (!specifics.isEmpty()){
ui->cmbSpecific->addItem(tr("Globale"));
- for (const QVariant &specific_id:qAsConst(specifics)){
+ for (const QVariant &specific_id:std::as_const(specifics)){
ui->cmbSpecific->addItem(specific_id.toString());
}
ui->frameSpecific->show();
@@ -146,7 +145,7 @@ void ServiceConfigWidget::updateService(const TeraData *service)
// New service with a config
item = new QListWidgetItem(QIcon(TeraData::getIconFilenameForDataType(TERADATA_SERVICE_CONFIG)), service_name);
item->setToolTip(service_name);
- item->setSizeHint(QSize(ui->lstServiceConfig->width(), 64));
+ //item->setSizeHint(QSize(ui->lstServiceConfig->width(), 64));
ui->lstServiceConfig->addItem(item);
m_listServices_items[id_service] = item;
}
@@ -156,8 +155,7 @@ void ServiceConfigWidget::updateService(const TeraData *service)
bool ServiceConfigWidget::validateData(){
bool valid = false;
- valid = ui->wdgServiceConfig->validateFormData() & ui->wdgServiceConfigConfig->validateFormData() ;
-
+ valid = ui->wdgServiceConfig->validateFormData() && ui->wdgServiceConfigConfig->validateFormData() ;
return valid;
}
@@ -290,7 +288,7 @@ void ServiceConfigWidget::on_btnSave_clicked()
if (!invalids.isEmpty()){
QString msg = tr("Les champs suivants doivent être complétés:") +" ";
- for (const QString &field:qAsConst(invalids)){
+ for (const QString &field:std::as_const(invalids)){
msg += "- " + field + "
";
}
msg += "
";
@@ -307,22 +305,21 @@ void ServiceConfigWidget::on_btnUndo_clicked()
undoData();
}
-void ServiceConfigWidget::on_cmbSpecific_currentIndexChanged(const QString ¤t_id)
+void ServiceConfigWidget::on_cmbSpecific_currentIndexChanged(const int ¤t_index)
{
if (isLoading())
return;
-
// Reload data for requested config
int id_service = m_listServices_items.key(ui->lstServiceConfig->currentItem());
QUrlQuery args;
args.addQueryItem(m_idFieldName, QString::number(m_idFieldValue));
args.addQueryItem(WEB_QUERY_ID_SERVICE, QString::number(id_service));
if (ui->cmbSpecific->currentIndex()>0){
- args.addQueryItem(WEB_QUERY_ID_SPECIFIC, current_id);
- m_specificId = current_id;
+ args.addQueryItem(WEB_QUERY_ID_SPECIFIC, ui->cmbSpecific->currentText());
+ m_specificId = ui->cmbSpecific->currentText();
}else{
m_specificId.clear();
}
queryDataRequest(WEB_SERVICECONFIGINFO_PATH, args);
-
}
+
diff --git a/client/src/editors/ServiceConfigWidget.h b/client/src/editors/ServiceConfigWidget.h
index ab78edae..ccef6dde 100644
--- a/client/src/editors/ServiceConfigWidget.h
+++ b/client/src/editors/ServiceConfigWidget.h
@@ -57,7 +57,7 @@ private slots:
void on_lstServiceConfig_itemClicked(QListWidgetItem *item);
void on_btnSave_clicked();
void on_btnUndo_clicked();
- void on_cmbSpecific_currentIndexChanged(const QString ¤t_id);
+ void on_cmbSpecific_currentIndexChanged(const int ¤t_index);
};
#endif // SERVICECONFIGWIDGET_H
diff --git a/client/src/editors/ServiceConfigWidget.ui b/client/src/editors/ServiceConfigWidget.ui
index 988ca834..000a8702 100644
--- a/client/src/editors/ServiceConfigWidget.ui
+++ b/client/src/editors/ServiceConfigWidget.ui
@@ -16,20 +16,8 @@
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
+
+
-
@@ -39,31 +27,46 @@
- 115
+ 150
16777215
QAbstractItemView::NoEditTriggers
+
+ false
+
+
+ Qt::IgnoreAction
+
+
+ QAbstractItemView::SelectRows
+
- 32
- 32
+ 48
+ 48
+
+ Qt::ElideRight
+
QListView::Static
- QListView::TopToBottom
+ QListView::LeftToRight
+
+
+ true
-
- QListView::Fixed
+
+ QListView::Batched
- 100
+ 150
90
@@ -76,6 +79,9 @@
true
+
+ false
+
Qt::AlignCenter
@@ -135,8 +141,8 @@
0
0
- 609
- 389
+ 556
+ 371
diff --git a/client/src/editors/ServiceWidget.cpp b/client/src/editors/ServiceWidget.cpp
index 143cb34d..11b37f61 100644
--- a/client/src/editors/ServiceWidget.cpp
+++ b/client/src/editors/ServiceWidget.cpp
@@ -150,11 +150,8 @@ void ServiceWidget::postServiceRoles()
QJsonObject base_obj;
QJsonArray roles;
- for (const QString &role_name:qAsConst(m_serviceRoles)){
+ for (const QString &role_name:std::as_const(m_serviceRoles)){
int role_id = m_serviceRoles.key(role_name);
-/* for (int i=0; icheckState(0) == Qt::Checked){
QJsonObject data_obj;
@@ -198,7 +195,7 @@ void ServiceWidget::postServiceProjects()
QJsonObject base_obj;
QJsonArray projects;
- for(QTreeWidgetItem* item: qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeProjects_items)){
int project_id = m_treeProjects_items.key(item);
if (item->checkState(0) == Qt::Checked){
QJsonObject data_obj;
diff --git a/client/src/editors/ServiceWidget.ui b/client/src/editors/ServiceWidget.ui
index 1e191e97..927bc751 100644
--- a/client/src/editors/ServiceWidget.ui
+++ b/client/src/editors/ServiceWidget.ui
@@ -246,6 +246,9 @@
-
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
diff --git a/client/src/editors/SessionTypeWidget.cpp b/client/src/editors/SessionTypeWidget.cpp
index 2858c5a7..3a7c1983 100644
--- a/client/src/editors/SessionTypeWidget.cpp
+++ b/client/src/editors/SessionTypeWidget.cpp
@@ -20,6 +20,7 @@ SessionTypeWidget::SessionTypeWidget(ComManager *comMan, const TeraData *data, Q
connectSignals();
// Query form definition
+ ui->wdgSessionType->setComManager(m_comManager);
queryDataRequest(WEB_FORMS_PATH, QUrlQuery(WEB_FORMS_QUERY_SESSION_TYPE));
if (!data->isNew()){
QUrlQuery args(WEB_FORMS_QUERY_SESSION_TYPE_CONFIG);
@@ -27,7 +28,6 @@ SessionTypeWidget::SessionTypeWidget(ComManager *comMan, const TeraData *data, Q
queryDataRequest(WEB_FORMS_PATH, args);
}
- ui->wdgSessionType->setComManager(m_comManager);
setData(data);
}
@@ -51,7 +51,7 @@ void SessionTypeWidget::saveData(bool signal){
QJsonArray sites;
// Sites
- for(QTreeWidgetItem* item:qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* item:std::as_const(m_treeSites_items)){
if (item->checkState(0) == Qt::Checked){
int site_id = m_treeSites_items.key(item);
QJsonObject data_obj;
@@ -67,7 +67,7 @@ void SessionTypeWidget::saveData(bool signal){
}
// Projects
- for(QTreeWidgetItem* item:qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* item:std::as_const(m_treeProjects_items)){
if (item->checkState(0) == Qt::Checked){
int project_id = m_treeProjects_items.key(item);
QJsonObject data_obj;
@@ -238,7 +238,7 @@ void SessionTypeWidget::postSessionTypeSites()
QJsonObject base_obj;
QJsonArray sites;
- for(QTreeWidgetItem* item: qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeSites_items)){
int site_id = m_treeSites_items.key(item);
if (item->checkState(0) == Qt::Checked){
QJsonObject data_obj;
@@ -261,7 +261,7 @@ void SessionTypeWidget::postSessionTypeProjects()
QJsonObject base_obj;
QJsonArray projects;
- for(QTreeWidgetItem* item: qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeProjects_items)){
int proj_id = m_treeProjects_items.key(item);
if (item->checkState(0) == Qt::Checked){
QJsonObject data_obj;
@@ -293,7 +293,7 @@ bool SessionTypeWidget::validateProjects()
{
if (!m_comManager->isCurrentUserSuperAdmin()){
bool at_least_one_selected = false;
- for(QTreeWidgetItem* site_item:qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* site_item:std::as_const(m_treeSites_items)){
if (site_item->checkState(0) == Qt::Checked){
at_least_one_selected = true;
break;
diff --git a/client/src/editors/SessionTypeWidget.ui b/client/src/editors/SessionTypeWidget.ui
index 00cd1026..d51f586e 100644
--- a/client/src/editors/SessionTypeWidget.ui
+++ b/client/src/editors/SessionTypeWidget.ui
@@ -135,7 +135,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- :/icons/session_type.png
+ :/icons/session_type.png
true
@@ -163,7 +163,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
:/icons/info.png:/icons/info.png
@@ -227,7 +227,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
Éditer
-
+
:/icons/edit.png:/icons/edit.png
@@ -272,7 +272,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
Sauvegarder
-
+
:/icons/save.png:/icons/save.png
@@ -298,7 +298,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
Annuler
-
+
:/icons/undo.png:/icons/undo.png
@@ -316,7 +316,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
:/icons/site-icon.png:/icons/site-icon.png
@@ -331,6 +331,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
0
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -368,7 +371,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
Mettre à jour les sites / projets associés
-
+
:/icons/save.png:/icons/save.png
@@ -383,7 +386,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
:/icons/config.png:/icons/config.png
@@ -418,7 +421,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
Mettre à jour la configuration
-
+
:/icons/save.png:/icons/save.png
@@ -443,8 +446,6 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
1
-
-
-
+
diff --git a/client/src/editors/SessionWidget.cpp b/client/src/editors/SessionWidget.cpp
index 74a9a7b1..7628d9b0 100644
--- a/client/src/editors/SessionWidget.cpp
+++ b/client/src/editors/SessionWidget.cpp
@@ -98,7 +98,7 @@ void SessionWidget::saveData(bool signal){
if (ui->wdgSessionInvitees->getDevicesInSessionCount() > 0){
QJsonArray data_list;
QList ids = ui->wdgSessionInvitees->getDevicesIdsInSession();
- for(const int &data_id:qAsConst(ids)){
+ for(const int &data_id:std::as_const(ids)){
data_list.append(QJsonValue(data_id));
}
session_data.insert("session_devices_ids", data_list);
@@ -107,7 +107,7 @@ void SessionWidget::saveData(bool signal){
if (ui->wdgSessionInvitees->getParticipantsInSessionCount() > 0){
QJsonArray data_list;
QList ids = ui->wdgSessionInvitees->getParticipantsIdsInSession();
- for(const int &data_id:qAsConst(ids)){
+ for(const int &data_id:std::as_const(ids)){
data_list.append(QJsonValue(data_id));
}
session_data.insert("session_participants_ids", data_list);
@@ -116,7 +116,7 @@ void SessionWidget::saveData(bool signal){
if (ui->wdgSessionInvitees->getUsersInSessionCount() > 0){
QJsonArray data_list;
QList ids = ui->wdgSessionInvitees->getUsersIdsInSession();
- for(const int &data_id:qAsConst(ids)){
+ for(const int &data_id:std::as_const(ids)){
data_list.append(QJsonValue(data_id));
}
session_data.insert("session_users_ids", data_list);
@@ -248,7 +248,7 @@ void SessionWidget::updateSessionParticipants()
if (m_data->hasFieldName("session_participants")){
QVariantList session_parts_list = m_data->getFieldValue("session_participants").toList();
QList participants;
- for(const QVariant &session_part:qAsConst(session_parts_list)){
+ for(const QVariant &session_part:std::as_const(session_parts_list)){
QVariantMap part_info = session_part.toMap();
TeraData part(TERADATA_PARTICIPANT);
part.fromMap(part_info);
@@ -291,7 +291,7 @@ void SessionWidget::updateSessionUsers()
QVariantList session_users_list = m_data->getFieldValue("session_users").toList();
QList users;
- for(const QVariant &session_user:qAsConst(session_users_list)){
+ for(const QVariant &session_user:std::as_const(session_users_list)){
QVariantMap user_info = session_user.toMap();
TeraData user(TERADATA_USER);
user.fromMap(user_info);
@@ -330,7 +330,7 @@ void SessionWidget::updateSessionDevices()
QVariantList session_devices_list = m_data->getFieldValue("session_devices").toList();
QList devices;
- for(const QVariant &session_device:qAsConst(session_devices_list)){
+ for(const QVariant &session_device:std::as_const(session_devices_list)){
QVariantMap device_info = session_device.toMap();
TeraData device(TERADATA_DEVICE);
device.fromMap(device_info);
@@ -560,7 +560,7 @@ void SessionWidget::sessionInviteesChanged(QStringList user_uuids, QStringList p
if (ui->wdgSessionInvitees->getDevicesInSessionCount() > 0){
QList ids = ui->wdgSessionInvitees->getDevicesIdsInSession();
- for(const int &data_id:qAsConst(ids)){
+ for(const int &data_id:std::as_const(ids)){
data_list.append(QJsonValue(data_id));
}
}
@@ -573,7 +573,7 @@ void SessionWidget::sessionInviteesChanged(QStringList user_uuids, QStringList p
if (ui->wdgSessionInvitees->getParticipantsInSessionCount() > 0){
QList ids = ui->wdgSessionInvitees->getParticipantsIdsInSession();
- for(const int &data_id:qAsConst(ids)){
+ for(const int &data_id:std::as_const(ids)){
data_list.append(QJsonValue(data_id));
}
}
@@ -584,7 +584,7 @@ void SessionWidget::sessionInviteesChanged(QStringList user_uuids, QStringList p
}
if (ui->wdgSessionInvitees->getUsersInSessionCount() > 0){
QList ids = ui->wdgSessionInvitees->getUsersIdsInSession();
- for(const int &data_id:qAsConst(ids)){
+ for(const int &data_id:std::as_const(ids)){
data_list.append(QJsonValue(data_id));
}
}
diff --git a/client/src/editors/SessionWidget.ui b/client/src/editors/SessionWidget.ui
index ebb89dad..0fa2119b 100644
--- a/client/src/editors/SessionWidget.ui
+++ b/client/src/editors/SessionWidget.ui
@@ -165,36 +165,36 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 200
+ 30
+
+
+
+
+ 10
+ true
+
+
+
+ État de la séance
+
+
+ Qt::AlignCenter
+
+
+
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 30
-
-
-
-
- 10
- true
-
-
-
- État de la séance
-
-
- Qt::AlignCenter
-
-
-
-
@@ -774,12 +774,6 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
- TeraForm
- QWidget
-
- 1
-
ClickableLabel
QLabel
@@ -789,6 +783,12 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
clicked()
+
+ TeraForm
+ QWidget
+
+ 1
+
SessionInviteWidget
QWidget
diff --git a/client/src/editors/SiteWidget.cpp b/client/src/editors/SiteWidget.cpp
index 06706f4a..4f5c1f00 100644
--- a/client/src/editors/SiteWidget.cpp
+++ b/client/src/editors/SiteWidget.cpp
@@ -3,12 +3,13 @@
#include "editors/DataListWidget.h"
-SiteWidget::SiteWidget(ComManager *comMan, const TeraData *data, QWidget *parent) :
+SiteWidget::SiteWidget(ComManager *comMan, const TeraData *data, const bool configMode, QWidget *parent) :
DataEditorWidget(comMan, data, parent),
ui(new Ui::SiteWidget)
{
m_diag_editor = nullptr;
m_devicesCount = 0;
+ m_configMode = configMode;
ui->setupUi(this);
@@ -79,6 +80,7 @@ void SiteWidget::connectSignals()
connect(m_comManager, &ComManager::deviceSitesReceived, this, &SiteWidget::processDeviceSiteAccessReply);
connect(m_comManager, &ComManager::servicesSitesReceived, this, &SiteWidget::processServiceSiteAccessReply);
connect(m_comManager, &ComManager::sessionTypesSitesReceived, this, &SiteWidget::processSessionTypeSiteAccessReply);
+ connect(m_comManager, &ComManager::testTypesSitesReceived, this, &SiteWidget::processTestTypeSiteAccessReply);
connect(m_comManager, &ComManager::statsReceived, this, &SiteWidget::processStatsReply);
connect(ui->btnUpdateRoles, &QPushButton::clicked, this, &SiteWidget::btnUpdateAccess_clicked);
@@ -150,12 +152,19 @@ void SiteWidget::updateControlsState()
ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabDevices), is_site_admin /*(is_site_admin && m_devicesCount>0) || is_super_admin*/);
ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabServices), is_site_admin);
ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabSessionTypes), is_site_admin);
+ ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabTestTypes), is_site_admin);
ui->btnUpdateServices->setVisible(is_super_admin);
ui->btnUpdateDevices->setVisible(is_super_admin);
- ui->btnEditDevices->setVisible(is_site_admin);
- /*ui->btnUpdateRoles->setVisible(is_site_admin);
- ui->btnUserGroups->setVisible(is_site_admin);*/
+ ui->btnUpdateSessionTypes->setVisible(is_super_admin);
+ ui->btnUpdateTestTypes->setVisible(is_super_admin);
+ ui->btnEditDevices->setVisible(is_site_admin && !m_configMode);
+
+ ui->lblAdminSessionTypes->setVisible(!is_super_admin);
+ ui->lblAdminTestTypes->setVisible(!is_super_admin);
+
+ ui->btnEditSessionTypes->setVisible(!m_configMode && is_super_admin);
+ ui->btnUserGroups->setVisible(!m_configMode);
ui->grpSummary->setVisible(!dataIsNew());
if (dataIsNew()){
@@ -225,10 +234,20 @@ void SiteWidget::querySessionTypeSiteAccess()
queryDataRequest(WEB_SESSIONTYPESITE_PATH, args);
}
+void SiteWidget::queryTestTypeSiteAccess()
+{
+ // Query session types for this site
+ QUrlQuery args;
+ args.addQueryItem(WEB_QUERY_ID_SITE, QString::number(m_data->getId()));
+ args.addQueryItem(WEB_QUERY_WITH_TESTTYPES, "1");
+ queryDataRequest(WEB_TESTTYPESITE_PATH, args);
+}
+
void SiteWidget::processFormsReply(QString form_type, QString data)
{
if (form_type == WEB_FORMS_QUERY_SITE){
- ui->wdgSite->buildUiFromStructure(data);
+ if (!ui->wdgSite->formHasStructure())
+ ui->wdgSite->buildUiFromStructure(data);
return;
}
}
@@ -264,8 +283,9 @@ void SiteWidget::processServiceSiteAccessReply(QList service_sites, QU
for (int i=0; ilstServices->count(); i++){
QListWidgetItem* item = ui->lstServices->item(i);
if (item->checkState() == Qt::Unchecked){
- if (std::find(m_listServicesSites_items.cbegin(), m_listServicesSites_items.cend(), item) != m_listServicesSites_items.cend()){
- m_listServicesSites_items.remove(m_listServicesSites_items.key(item));
+ int item_key = m_listServicesSites_items.key(item, -1);
+ if (item_key > 0){
+ m_listServicesSites_items.remove(item_key);
}
}
}
@@ -284,8 +304,9 @@ void SiteWidget::processDeviceSiteAccessReply(QList device_sites, QUrl
for (int i=0; ilstDevices->count(); i++){
QListWidgetItem* item = ui->lstDevices->item(i);
if (item->checkState() == Qt::Unchecked){
- if (std::find(m_listDevicesSites_items.cbegin(), m_listDevicesSites_items.cend(), item) != m_listDevicesSites_items.cend()){
- m_listDevicesSites_items.remove(m_listDevicesSites_items.key(item));
+ int item_key = m_listDevicesSites_items.key(item, -1);
+ if (item_key > 0){
+ m_listDevicesSites_items.remove(item_key);
}
}
}
@@ -304,8 +325,9 @@ void SiteWidget::processSessionTypeSiteAccessReply(QList st_sites, QUr
for (int i=0; ilstSessionTypes->count(); i++){
QListWidgetItem* item = ui->lstSessionTypes->item(i);
if (item->checkState() == Qt::Unchecked){
- if (std::find(m_listSessionTypeSites_items.cbegin(), m_listSessionTypeSites_items.cend(), item) != m_listSessionTypeSites_items.cend()){
- m_listSessionTypeSites_items.remove(m_listSessionTypeSites_items.key(item));
+ int item_key = m_listSessionTypeSites_items.key(item, -1);
+ if (item_key > 0){
+ m_listSessionTypeSites_items.remove(item_key);
}
}
}
@@ -314,6 +336,27 @@ void SiteWidget::processSessionTypeSiteAccessReply(QList st_sites, QUr
ui->btnUpdateSessionTypes->setEnabled(false);
}
+void SiteWidget::processTestTypeSiteAccessReply(QList tt_sites, QUrlQuery reply_query)
+{
+ for(const TeraData &tt_site: tt_sites){
+ updateTestTypeSite(&tt_site);
+ }
+
+ // Update used list from what is checked right now
+ for (int i=0; ilstTestTypes->count(); i++){
+ QListWidgetItem* item = ui->lstTestTypes->item(i);
+ if (item->checkState() == Qt::Unchecked){
+ int item_key = m_listTestTypeSites_items.key(item, -1);
+ if (item_key > 0){
+ m_listTestTypeSites_items.remove(item_key);
+ }
+ }
+ }
+
+ // New list received - disable save button
+ ui->btnUpdateTestTypes->setEnabled(false);
+}
+
void SiteWidget::processStatsReply(TeraData stats, QUrlQuery reply_query)
{
@@ -456,6 +499,44 @@ void SiteWidget::updateSessionTypeSite(const TeraData *st_site)
}
}
+void SiteWidget::updateTestTypeSite(const TeraData *tt_site)
+{
+ int id_site = tt_site->getFieldValue("id_site").toInt();
+
+ if (id_site != m_data->getId() && id_site>0)
+ return; // Not for us
+
+ int id_test_type = tt_site->getFieldValue("id_test_type").toInt();
+ QString tt_name = tt_site->getFieldValue("test_type_name").toString();
+ QListWidgetItem* item;
+
+ if (m_listTestTypes_items.contains(id_test_type)){
+ item = m_listTestTypes_items[id_test_type];
+ }else{
+ item = new QListWidgetItem(QIcon(TeraData::getIconFilenameForDataType(TeraDataTypes::TERADATA_TESTTYPE)), tt_name);
+ ui->lstTestTypes->addItem(item);
+ m_listTestTypes_items[id_test_type] = item;
+ }
+
+ if (!tt_name.isEmpty())
+ item->setText(tt_name);
+
+ int id_test_type_site = tt_site->getId();
+ if (id_test_type_site > 0){
+ if (m_comManager->isCurrentUserSuperAdmin())
+ item->setCheckState(Qt::Checked);
+ if (!m_listTestTypeSites_items.contains(id_test_type_site)){
+ m_listTestTypeSites_items[id_test_type_site] = item;
+ }
+ }else{
+ if (m_comManager->isCurrentUserSuperAdmin())
+ item->setCheckState(Qt::Unchecked);
+ if (m_listTestTypeSites_items.contains(id_test_type_site)){
+ m_listTestTypeSites_items.remove(id_test_type_site);
+ }
+ }
+}
+
void SiteWidget::processPostOKReply(QString path)
{
if (path == WEB_SITEINFO_PATH){
@@ -479,7 +560,7 @@ void SiteWidget::btnUpdateAccess_clicked()
QJsonObject base_obj;
QJsonArray roles;
- for (QTableWidgetItem* item: qAsConst(m_tableUserGroups_items)){
+ for (QTableWidgetItem* item: std::as_const(m_tableUserGroups_items)){
int user_group_id = m_tableUserGroups_items.key(item);
int row = item->row();
// }
@@ -598,27 +679,13 @@ void SiteWidget::on_tabNav_currentChanged(int index)
if (m_listDevices_items.isEmpty()){
queryDeviceSiteAccess();
}
- // Devices
- /*if (!ui->wdgDevices->layout()){
- QHBoxLayout* layout = new QHBoxLayout();
- layout->setMargin(0);
- ui->wdgDevices->setLayout(layout);
- }
- if (ui->wdgDevices->layout()->count() == 0){
- args.addQueryItem(WEB_QUERY_WITH_PARTICIPANTS, "");
- args.addQueryItem(WEB_QUERY_WITH_SITES, "");
- DataListWidget* deviceslist_editor = new DataListWidget(m_comManager, TERADATA_DEVICE, args, QStringList("device_participants.participant_name"), ui->wdgUsers);
- deviceslist_editor->setPermissions(isSiteAdmin(), m_comManager->isCurrentUserSuperAdmin());
- deviceslist_editor->setFilterText(tr("Seuls les appareils associés au site sont affichés."));
- ui->wdgDevices->layout()->addWidget(deviceslist_editor);
- }*/
}
if (current_tab == ui->tabUsersDetails){
// Users
if (!ui->wdgUsers->layout()){
QHBoxLayout* layout = new QHBoxLayout();
- layout->setMargin(0);
+ layout->setContentsMargins(0,0,0,0);
ui->wdgUsers->setLayout(layout);
}
if (ui->wdgUsers->layout()->count() == 0){
@@ -639,21 +706,13 @@ void SiteWidget::on_tabNav_currentChanged(int index)
if (current_tab == ui->tabSessionTypes){
// Session types
- /*if (!ui->wdgSessionTypes->layout()){
- QHBoxLayout* layout = new QHBoxLayout();
- layout->setMargin(0);
- ui->wdgSessionTypes->setLayout(layout);
- }
- if (ui->wdgSessionTypes->layout()->count() == 0){
- DataListWidget* stlist_editor = new DataListWidget(m_comManager, TERADATA_SESSIONTYPE, WEB_SESSIONTYPESITE_PATH, args, QStringList(), ui->wdgSessionTypes);
- // m_limited = true = user only, not project admin
- stlist_editor->setPermissions(!m_limited, !m_limited);
- stlist_editor->setFilterText(tr("Seuls les types de séances associés au site sont affichés."));
- ui->wdgSessionTypes->layout()->addWidget(stlist_editor);
- }*/
querySessionTypeSiteAccess();
}
+ if (current_tab == ui->tabTestTypes){
+ queryTestTypeSiteAccess();
+ }
+
}
@@ -690,8 +749,10 @@ void SiteWidget::on_btnUpdateServices_clicked()
item_obj.insert("id_service", service_id);
services_sites.append(item_obj);
}else{
- if (std::find(m_listServicesSites_items.cbegin(), m_listServicesSites_items.cend(), item) != m_listServicesSites_items.cend()){
- removed_services = true;
+ if (!removed_services){
+ if (m_listServicesSites_items.key(item, 0) > 0){
+ removed_services = true;
+ }
}
}
}
@@ -783,8 +844,10 @@ void SiteWidget::on_btnUpdateDevices_clicked()
item_obj.insert("id_device", device_id);
devices_sites.append(item_obj);
}else{
- if (std::find(m_listDevicesSites_items.cbegin(), m_listDevicesSites_items.cend(), item) != m_listDevicesSites_items.cend()){
- removed_devices = true;
+ if (!removed_devices){
+ if (m_listDevicesSites_items.key(item, 0) > 0){
+ removed_devices = true;
+ }
}
}
}
@@ -806,7 +869,7 @@ void SiteWidget::on_btnUpdateDevices_clicked()
void SiteWidget::on_txtSearchDevices_textChanged(const QString &search_text)
{
- for(QListWidgetItem* item: qAsConst(m_listDevices_items)){
+ for(QListWidgetItem* item: std::as_const(m_listDevices_items)){
item->setHidden(!item->text().contains(search_text, Qt::CaseInsensitive));
}
}
@@ -843,7 +906,7 @@ void SiteWidget::on_btnEditDevices_clicked()
void SiteWidget::on_lstSessionTypes_itemChanged(QListWidgetItem *item)
{
- if (!isSiteAdmin())
+ if (!m_comManager->isCurrentUserSuperAdmin())
return;
// Check for changed items
@@ -886,8 +949,10 @@ void SiteWidget::on_btnUpdateSessionTypes_clicked()
item_obj.insert("id_session_type", st_id);
st_sites.append(item_obj);
}else{
- if (std::find(m_listSessionTypes_items.cbegin(), m_listSessionTypes_items.cend(), item) != m_listSessionTypes_items.cend()){
- removed_sts = true;
+ if (!removed_sts){
+ if (m_listSessionTypes_items.key(item, 0) > 0){
+ removed_sts = true;
+ }
}
}
}
@@ -928,3 +993,71 @@ void SiteWidget::on_btnEditSessionTypes_clicked()
m_diag_editor->open();
}
+
+void SiteWidget::on_lstTestTypes_itemChanged(QListWidgetItem *item)
+{
+ if (!m_comManager->isCurrentUserSuperAdmin())
+ return;
+
+ // Check for changed items
+ bool has_changes = false;
+ if (m_listTestTypeSites_items.key(item) > 0 && item->checkState() == Qt::Unchecked){
+ // Item deselected
+ has_changes = true;
+ }else{
+ if (m_listTestTypeSites_items.key(item) <= 0 && item->checkState() == Qt::Checked){
+ // Item selected
+ has_changes = true;
+ }
+ }
+
+ if (item->checkState() == Qt::Checked){
+ item->setForeground(Qt::green);
+ }else{
+ item->setForeground(Qt::red);
+ }
+
+ ui->btnUpdateTestTypes->setEnabled(has_changes);
+}
+
+
+void SiteWidget::on_btnUpdateTestTypes_clicked()
+{
+ QJsonDocument document;
+ QJsonObject base_obj;
+ QJsonObject site_obj;
+ QJsonArray tt_sites;
+ bool removed_tts = false;
+
+ site_obj.insert("id_site", m_data->getId());
+ for (int i=0; ilstTestTypes->count(); i++){
+ QListWidgetItem* item = ui->lstTestTypes->item(i);
+ int tt_id = m_listTestTypes_items.key(item, 0);
+ if (item->checkState() == Qt::Checked){
+ // New item selected
+ QJsonObject item_obj;
+ item_obj.insert("id_test_type", tt_id);
+ tt_sites.append(item_obj);
+ }else{
+ if (!removed_tts){
+ if (m_listTestTypeSites_items.key(item, 0) > 0){
+ removed_tts = true;
+ }
+ }
+ }
+ }
+
+ if (removed_tts){
+ GlobalMessageBox msgbox;
+ int rval = msgbox.showYesNo(tr("Suppression de types de tests associés"), tr("Au moins un type de test a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser.\nSouhaitez-vous continuer?"));
+ if (rval != GlobalMessageBox::Yes){
+ return;
+ }
+ }
+
+ site_obj.insert("testtypes", tt_sites);
+ base_obj.insert("site", site_obj);
+ document.setObject(base_obj);
+ postDataRequest(WEB_TESTTYPESITE_PATH, document.toJson());
+}
+
diff --git a/client/src/editors/SiteWidget.h b/client/src/editors/SiteWidget.h
index 5f6d08c6..795c1588 100644
--- a/client/src/editors/SiteWidget.h
+++ b/client/src/editors/SiteWidget.h
@@ -18,11 +18,10 @@ class SiteWidget : public DataEditorWidget
Q_OBJECT
public:
- explicit SiteWidget(ComManager* comMan, const TeraData* data = nullptr, QWidget *parent = nullptr);
+ explicit SiteWidget(ComManager* comMan, const TeraData* data = nullptr, const bool configMode = false, QWidget *parent = nullptr);
~SiteWidget();
void saveData(bool signal=true);
-
void setData(const TeraData* data);
private slots:
@@ -31,6 +30,7 @@ private slots:
void processServiceSiteAccessReply(QList service_sites, QUrlQuery reply_query);
void processDeviceSiteAccessReply(QListdevice_sites, QUrlQuery reply_query);
void processSessionTypeSiteAccessReply(QListst_sites, QUrlQuery reply_query);
+ void processTestTypeSiteAccessReply(QListtt_sites, QUrlQuery reply_query);
void processStatsReply(TeraData stats, QUrlQuery reply_query);
void processPostOKReply(QString path);
@@ -55,11 +55,13 @@ private slots:
void on_btnEditDevices_clicked();
void on_lstSessionTypes_itemChanged(QListWidgetItem *item);
-
void on_btnUpdateSessionTypes_clicked();
-
void on_btnEditSessionTypes_clicked();
+ void on_lstTestTypes_itemChanged(QListWidgetItem *item);
+
+ void on_btnUpdateTestTypes_clicked();
+
private:
Ui::SiteWidget *ui;
@@ -74,9 +76,13 @@ private slots:
QMap m_listSessionTypeSites_items;
QMap m_listSessionTypes_items;
+ QMap m_listTestTypeSites_items;
+ QMap m_listTestTypes_items;
+
BaseDialog* m_diag_editor;
int m_devicesCount;
+ bool m_configMode;
void connectSignals();
@@ -84,6 +90,7 @@ private slots:
void updateServiceSite(const TeraData* service_site);
void updateDeviceSite(const TeraData* device_site);
void updateSessionTypeSite(const TeraData* st_site);
+ void updateTestTypeSite(const TeraData* tt_site);
void updateControlsState();
void updateFieldsValue();
@@ -95,6 +102,7 @@ private slots:
void queryServiceSiteAccess();
void queryDeviceSiteAccess();
void querySessionTypeSiteAccess();
+ void queryTestTypeSiteAccess();
};
#endif // SITEWIDGET_H
diff --git a/client/src/editors/SiteWidget.ui b/client/src/editors/SiteWidget.ui
index f03ea2ec..eb6a3340 100644
--- a/client/src/editors/SiteWidget.ui
+++ b/client/src/editors/SiteWidget.ui
@@ -20,106 +20,14 @@
Form
- /*
-QPushButton#btnConnect{background-color:rgb(80,180,80)}
-QWidget{background-color: rgba(0,0,0,0);color:white;border-radius:5px}
-QWidget#mainWidget{background-color:rgba(128,128,128,25%);}
-QWidget#frmProfile,QWidget#pageProfile{background-color:rgba(108,8,156,25%);}
-QPlainTextEdit,QLineEdit,QListWidget,QComboBox,QTextEdit,QSpinBox{background-color: rgba(255,255,255,50%); color: black;}
-
-QTableWidget{
-background-color: rgba(0,0,0,50%);
-color: white;
-border: 1px solid rgba(255,255,255,50%);
-}
-
-QLabel#lblLastOnline{color:lightblue;}
-QLabel#lblError,QLabel#lblCamMissing,QLabel#lblAudioMissing{color:red; background-color:rgba(255,0,0,30%);}
-
-QLineEdit:!enabled, QListWidget:!enabled,QComboBox:!enabled,QTextEdit:!enabled,QPlainTextEdit:!enabled{background-color: rgba(0,0,0,30%);color:white;border:0}
-QDateEdit::down-arrow:!enabled,QTimeEdit::down-arrow:!enabled,QDateEdit::up-arrow:!enabled,QTimeEdit::up-arrow:!enabled,QComboBox::drop-down:!enabled{background-color:rgba(0,0,0,0%);}
-
-QTextEdit#txtProfile{background-color: rgba(255,255,255,80%);color:black;border:0}
-QTextEdit:!enabled#txtProfile{background-color: rgba(255,255,255,60%);color:black;border:0}
-
-QFrame#frmSelUser{background-color:rgba(100,100,200,50%);}
-QFrame#frmAudio,QFrame#frmCam1,QFrame#frmCam2,QFrame#frmSensors,QFrame#frmWebRTC,QFrame#frmVirtualCam,QFrame#frmExternalPrograms{background-color:rgba(100,100,200,35%);}
-
-QCheckBox::indicator:unchecked:!enabled { background-color:rgba(128,0,0,100%);}
-QCheckBox::indicator:checked:!enabled { background-color:green;}
-QCheckBox::indicator:unchecked{ background-color:red;border-radius:3px;}
-QCheckBox::indicator:checked {background-color:rgb(0,255,0);border-radius:3px;}
-QCheckBox:checked{color:lightgreen;background-color:rgba(0,0,0,0%);}
-QCheckBox:!checked{color:red;background-color:rgba(0,0,0,0%);}
-
-QPushButton{background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #2198c0, stop: 1 #0d5ca6);}
-QPushButton:checked{background-color:rgb(128,128,128); border:1px solid rgba(255,255,255,50%);}
-QPushButton:hover,QPushButton:checked{background-color: rgba(255,255,255,75%);color:black;}
-
-QToolButton:hover{background-color: rgba(255,255,255,50);}
-
-QTreeWidget::branch:closed:has-children:has-siblings {
- border-image: none;
- image: url(:/pictures/controls/branch_closed.png);
- }
-
- QTreeView::branch:open:has-children:!has-siblings,
- QTreeView::branch:open:has-children:has-siblings {
- border-image: none;
- image:url(:/pictures/controls/branch_opened.png);
- }
-
-QWidget#lineOnline{background-color:blue;}
-QWidget#lineOffline{background-color:red;}
-QWidget#lineBoth{background-color:rgb(255,0,255);}
-
-
-QTabWidget::pane {
- background-color: rgba(128,128,140,25%);
- border-radius: 5px;
- border: 2px solid rgba(128,128,140,50%);
- }
-
- QTabWidget::tab-bar {
- left: 5px;
- }
-
-
- QTabBar::tab,QTableWidget::tab,QHeaderView::section {
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 rgba(128,128,140,50%), stop: 1.0 rgba(128,128,140,25%));
- border: 2px solid rgba(128,128,140,50%);
- border-bottom: 0px;
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
- padding: 2px;
-min-height:25px;
- }
-
- QTabBar::tab:selected, QTabBar::tab:hover {
-
-background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 rgba(128,128,140,70%), stop: 1.0 rgba(128,128,140,50%));
- }
-
- QTabBar::tab:selected {
- border-color:rgba(128,128,140,60%);
- border-bottom-color:rgba(128,128,140,60%);
- }
-
- QTabBar::tab:!selected {
- margin-top: 2px;
- }
-*/
-
-
+
10
- 1
+ 9
-
@@ -171,7 +79,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- 0
+ 3
@@ -314,7 +222,7 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- 10
+ 15
-
@@ -776,6 +684,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
3
+
+ true
+
200
@@ -785,6 +696,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
true
+
+ false
+
Groupe utilisateur
@@ -845,6 +759,19 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
-
+
+
+
+ 0
+ 32
+
+
+
+ Pour modifier les types de séances associés à ce site, veuillez contacter votre administrateur
+
+
+
-
@@ -888,12 +815,27 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
+ Qt::NoFocus
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ QAbstractItemView::NoSelection
+
+
+ QAbstractItemView::SelectRows
+
24
24
+
+ false
+
-
@@ -924,6 +866,85 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+
+
+
+ :/icons/test_type.png:/icons/test_type.png
+
+
+ Types de tests
+
+
+ -
+
+
-
+
+
+
+ 0
+ 32
+
+
+
+ Pour modifier les types de tests associés à ce site, veuillez contacter votre administrateur
+
+
+
+
+
+ -
+
+
+ Qt::NoFocus
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ QAbstractItemView::NoSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+
+ 24
+ 24
+
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 32
+
+
+
+ PointingHandCursor
+
+
+ Mettre à jour les types de tests associés
+
+
+
+ :/icons/save.png:/icons/save.png
+
+
+
+ 24
+ 24
+
+
+
+
+
+
@@ -1008,6 +1029,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -1070,6 +1094,15 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
+
+ Qt::NoFocus
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ QAbstractItemView::NoSelection
+
24
@@ -1111,12 +1144,6 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-
- TeraForm
- QWidget
-
- 1
-
ClickableLabel
QLabel
@@ -1126,6 +1153,12 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
clicked()
+
+ TeraForm
+ QWidget
+
+ 1
+
diff --git a/client/src/editors/TeraForm.cpp b/client/src/editors/TeraForm.cpp
index 8d299745..aa0958d0 100644
--- a/client/src/editors/TeraForm.cpp
+++ b/client/src/editors/TeraForm.cpp
@@ -2,7 +2,9 @@
#include "ui_TeraForm.h"
#include "Logger.h"
-#include "DataEditorWidget.h"
+#include "GlobalMessageBox.h"
+#include "libs/AudioVideoUtils.h"
+
#include
#include
@@ -13,17 +15,9 @@ TeraForm::TeraForm(QWidget *parent, ComManager *com_man) :
ui->setupUi(this);
m_mainWidget = ui->toolboxMain;
- m_highlightConditionals = true;
-
- // TODO: Find out why the global stylesheet isn't correctly used by TeraForm
- /*QFile file(":/stylesheet.qss");
- file.open(QFile::ReadOnly);
- QString stylesheet = QLatin1String(file.readAll());
- setStyleSheet(stylesheet);*/
+ m_highlightConditionals = false;
// Automatically sets comManager
- /*DataEditorWidget* parent_editor = dynamic_cast(parent);
- if (parent_editor){*/
setComManager(com_man);
//}
}
@@ -48,8 +42,10 @@ void TeraForm::buildUiFromStructure(const QString &structure)
while (ui->toolboxMain->count() > 0){
ui->toolboxMain->widget(0)->deleteLater();
- ui->toolboxMain->removeItem(0);
+ //ui->toolboxMain->removeItem(0);
+ ui->toolboxMain->removeTab(0);
}
+ ui->toolboxMain->show();
QJsonObject struct_object = struct_info.object();
@@ -63,18 +59,19 @@ void TeraForm::buildUiFromStructure(const QString &structure)
if (struct_data.count() > 1){
int page_index = 0;
m_mainWidget = ui->toolboxMain;
- for (const QVariant §ion:qAsConst(struct_data)){
- if (section.canConvert(QMetaType::QVariantHash)){
+ for (const QVariant §ion:std::as_const(struct_data)){
+ if (section.canConvert()){
QVariantHash section_data = section.toHash();
//if (page_index>0){
QWidget* new_page = new QWidget(ui->toolboxMain);
new_page->setObjectName("pageSection" + QString::number(page_index+1));
new_page->setStyleSheet("QWidget#" + new_page->objectName() + "{border: 1px solid white; border-radius: 5px;}");
- ui->toolboxMain->addItem(new_page,"");
+ //ui->toolboxMain->addItem(new_page,"");
+ ui->toolboxMain->addTab(new_page, section_data["label"].toString());
//}
- ui->toolboxMain->setItemText(page_index, section_data["label"].toString());
+ //ui->toolboxMain->setItemText(page_index, section_data["label"].toString());
if (section_data.contains("items")){
- if (section_data["items"].canConvert(QMetaType::QVariantList)){
+ if (section_data["items"].canConvert()){
buildFormFromStructure(ui->toolboxMain->widget(page_index), section_data["items"].toList());
}
}
@@ -85,11 +82,12 @@ void TeraForm::buildUiFromStructure(const QString &structure)
if (struct_data.count() == 1){
// Only one section - hides the header and don't use QToolBox
ui->mainLayout->removeWidget(ui->toolboxMain);
+ ui->toolboxMain->hide();
m_mainWidget = new QFrame(this);
ui->mainLayout->addWidget(m_mainWidget);
QVariantHash section_data = struct_data.first().toHash();
if (section_data.contains("items")){
- if (section_data["items"].canConvert(QMetaType::QVariantList)){
+ if (section_data["items"].canConvert()){
buildFormFromStructure(m_mainWidget, section_data["items"].toList());
}
}
@@ -116,7 +114,7 @@ void TeraForm::fillFormFromData(const QJsonObject &data)
resetFormValues();
// Set initial values for missing fields
- for (QWidget* widget:qAsConst(m_widgets)){
+ for (QWidget* widget:std::as_const(m_widgets)){
QString field = m_widgets.key(widget);
if (!m_initialValues.contains(field)){
QVariant value;
@@ -150,10 +148,17 @@ void TeraForm::fillFormFromData(const QString &structure)
}
+void TeraForm::setSectionsPosition(const QTabWidget::TabPosition &position)
+{
+ if (dynamic_cast(ui->toolboxMain)){
+ ui->toolboxMain->setTabPosition(position);
+ }
+}
+
bool TeraForm::validateFormData(bool include_hidden)
{
bool rval = true;
- for (QWidget* item:qAsConst(m_widgets)){
+ for (QWidget* item:std::as_const(m_widgets)){
rval &= validateWidget(item, include_hidden);
}
return rval;
@@ -162,7 +167,7 @@ bool TeraForm::validateFormData(bool include_hidden)
QStringList TeraForm::getInvalidFormDataLabels(bool include_hidden)
{
QStringList rval;
- for (QWidget* item:qAsConst(m_widgets)){
+ for (QWidget* item:std::as_const(m_widgets)){
if (!validateWidget(item, include_hidden)){
rval.append(item->property("label").toString());
}
@@ -226,7 +231,7 @@ bool TeraForm::getFieldDirty(QWidget *widget)
}
QVariant value, id;
getWidgetValues(widget, &id, &value);
- if (!id.isNull())
+ if (!id.isNull() && id.isValid())
value = id;
if (dynamic_cast(widget)){
@@ -255,7 +260,7 @@ void TeraForm::hideField(const QString &field)
// Disable condition
if (widget->property("condition").isValid() && !hasHookCondition(widget)){
widget->setProperty("_condition", widget->property("condition"));
- widget->setProperty("condition", QVariant::Invalid);
+ widget->setProperty("condition", QVariant());
}
}
}
@@ -268,7 +273,7 @@ void TeraForm::showField(const QString &field)
// Enable condition
if (widget->property("_condition").isValid()){
widget->setProperty("condition", widget->property("_condition"));
- widget->setProperty("_condition", QVariant::Invalid);
+ widget->setProperty("_condition", QVariant());
}
checkConditions(widget);
}
@@ -313,7 +318,7 @@ void TeraForm::setFieldsEnabled(const QStringList &fields, const bool &enabled)
bool TeraForm::isDirty()
{
bool dirty = false;
- for(QWidget* wdg: qAsConst(m_widgets)){
+ for(QWidget* wdg: std::as_const(m_widgets)){
if (getFieldDirty(wdg)){
dirty = true;
break;
@@ -336,11 +341,11 @@ QJsonDocument TeraForm::getFormDataJson(bool include_unmodified_data)
QJsonObject data_obj;
QJsonObject base_obj;
- for(QWidget* wdg:qAsConst(m_widgets)){
+ for(QWidget* wdg:std::as_const(m_widgets)){
QString field = m_widgets.key(wdg);
QVariant value, id;
getWidgetValues(wdg, &id, &value);
- if (!id.isNull())
+ if (!id.isNull() && id.isValid())
value = id;
// Include only modified fields or ids
if ((!include_unmodified_data && getFieldDirty(field))
@@ -365,11 +370,11 @@ QJsonDocument TeraForm::getFormDataJson(bool include_unmodified_data)
TeraData* TeraForm::getFormDataObject(const TeraDataTypes data_type)
{
TeraData* rval = new TeraData(data_type);
- for(QWidget* wdg:qAsConst(m_widgets)){
+ for(QWidget* wdg:std::as_const(m_widgets)){
QString field = m_widgets.key(wdg);
QVariant value, id;
if (getWidgetValues(wdg, &id, &value)){
- if (!id.isNull())
+ if (!id.isNull() && id.isValid())
value = id;
rval->setFieldValue(field, value);
}
@@ -435,12 +440,12 @@ bool TeraForm::formHasStructure()
void TeraForm::resetFormValues()
{
QStringList keys = m_initialValues.keys();
- for (const QString& field:qAsConst(keys)){
+ for (const QString& field:std::as_const(keys)){
if (m_widgets.contains(field)){
setWidgetValue(m_widgets[field], m_initialValues[field]);
checkConditions(m_widgets[field]);
} else{
- LOG_WARNING("No widget for field: " + field, "TeraForm::resetFormValues");
+ //LOG_WARNING("No widget for field: " + field, "TeraForm::resetFormValues");
}
}
@@ -458,27 +463,24 @@ void TeraForm::buildFormFromStructure(QWidget *page, const QVariantList &structu
layout = new QFormLayout(page);
//layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
layout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
+ //layout->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint);
+ layout->setFormAlignment(Qt::AlignLeft | Qt::AlignTop);
+ layout->setAlignment(Qt::AlignLeft | Qt::AlignTop);
layout->setVerticalSpacing(3);
+
}else{
layout = static_cast(page->layout());
}
for (const QVariant &item:structure){
- if (item.canConvert(QMetaType::QVariantHash)){
+ if (item.canConvert()){
QVariantHash item_data = item.toHash();
QString item_id = item_data["id"].toString();
QWidget* item_widget = nullptr;
QLabel* item_label = new QLabel(item_data["label"].toString());
item_label->setAlignment(Qt::AlignVCenter);
- item_label->setStyleSheet("QLabel{min-height: 25px;}");
-
- /*QFrame* item_frame = new QFrame();
- QHBoxLayout* item_frame_layout = new QHBoxLayout();
- item_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
- item_frame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
- item_frame_layout->addWidget(item_label);
- item_frame->setLayout(item_frame_layout);*/
-
+ item_label->setStyleSheet("QLabel{color: #b6ddf8;}");
+ //item_label->setStyleSheet("QLabel{min-height: 25px;}");
// Build widget according to item type
QString item_type = item_data["type"].toString().toLower();
@@ -515,6 +517,9 @@ void TeraForm::buildFormFromStructure(QWidget *page, const QVariantList &structu
else if (item_type == "label"){
item_widget = createLabelWidget(item_data);
}
+ else if (item_type == "longlabel"){
+ item_widget = createLongLabelWidget(item_data);
+ }
else if (item_type == "color"){
item_widget = createColorWidget(item_data);
}
@@ -580,6 +585,7 @@ void TeraForm::buildFormFromStructure(QWidget *page, const QVariantList &structu
// Set layout alignement
layout->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ layout->update();
page->setLayout(layout);
// Set default values
@@ -588,12 +594,13 @@ void TeraForm::buildFormFromStructure(QWidget *page, const QVariantList &structu
validateFormData(true);
page->setDisabled(m_disabled);
+ updateRequiredWidgetsLabel();
}
void TeraForm::setDefaultValues()
{
- for (QWidget* item:qAsConst(m_widgets)){
+ for (QWidget* item:std::as_const(m_widgets)){
if (QComboBox* combo = dynamic_cast(item)){
combo->setCurrentIndex(0);
}
@@ -616,7 +623,7 @@ QWidget *TeraForm::createVideoInputsWidget(const QVariantHash &structure)
//item_combo->addItem(camera.description(), camera.deviceName());
item_combo->addItem(camera.description(), camera.description());
}*/
- for (const QString &camera:qAsConst(m_videoInputs)){
+ for (const QString &camera:std::as_const(m_videoInputs)){
item_combo->addItem(camera, camera);
}
@@ -641,7 +648,7 @@ QWidget *TeraForm::createAudioInputsWidget(const QVariantHash &structure)
/*for (QAudioDeviceInfo input:m_audioInputs){
item_combo->addItem(input.deviceName(), input.deviceName());
}*/
- for (const QString &input:qAsConst(m_audioInputs)){
+ for (const QString &input:std::as_const(m_audioInputs)){
item_combo->addItem(input, input);
}
@@ -660,10 +667,10 @@ QWidget *TeraForm::createArrayWidget(const QVariantHash &structure)
item_combo->addItem("", "");
if (structure.contains("values")){
- if (structure["values"].canConvert(QMetaType::QVariantList)){
+ if (structure["values"].canConvert()){
QVariantList list = structure["values"].toList();
- for (const QVariant &value:qAsConst(list)){
- if (value.canConvert(QMetaType::QVariantHash)){
+ for (const QVariant &value:std::as_const(list)){
+ if (value.canConvert()){
QVariantHash item_data = value.toHash();
item_combo->addItem(item_data["value"].toString(), item_data["id"].toString());
}
@@ -745,12 +752,27 @@ QWidget *TeraForm::createLabelWidget(const QVariantHash &structure)
QLabel* item_label = new QLabel();
item_label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ //item_label->setWordWrap(true);
//item_label->setHidden(is_hidden);
return item_label;
}
+QWidget *TeraForm::createLongLabelWidget(const QVariantHash &structure)
+{
+ QPushButton* item_button = new QPushButton();
+ item_button->setText(tr("Afficher"));
+ item_button->setIcon(QIcon(":/icons/view_on.png"));
+ item_button->setCursor(Qt::PointingHandCursor);
+
+ // Connect signal
+ connect(item_button, &QPushButton::clicked, this, &TeraForm::longLabelButtonClicked);
+
+ return item_button;
+
+}
+
QWidget *TeraForm::createListWidget(const QVariantHash &structure)
{
QListWidget* item_list = new QListWidget();
@@ -767,6 +789,10 @@ QWidget *TeraForm::createLongTextWidget(const QVariantHash &structure)
Q_UNUSED(structure)
QTextEdit* item_text = new QTextEdit();
+ /*QFontMetrics metrics(item_text->font());
+ int row_height = metrics.lineSpacing();
+ item_text->setFixedHeight(4.5 * row_height);*/
+
//item_text->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
connect(item_text, &QTextEdit::textChanged, this, &TeraForm::widgetValueChanged);
@@ -823,17 +849,17 @@ QWidget *TeraForm::createDurationWidget(const QVariantHash &structure)
void TeraForm::loadAudioInputs()
{
- m_audioInputs = Utils::getAudioDeviceNames();// QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
+ m_audioInputs = AudioVideoUtils::getAudioDeviceNames();// QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
}
void TeraForm::loadVideoInputs()
{
- m_videoInputs = Utils::getVideoDeviceNames(); //QCameraInfo::availableCameras();
+ m_videoInputs = AudioVideoUtils::getVideoDeviceNames(); //QCameraInfo::availableCameras();
}
void TeraForm::checkConditions(QWidget *item_triggering)
{
- for (QWidget* item:qAsConst(m_widgets)){
+ for (QWidget* item:std::as_const(m_widgets)){
if (!item)
continue;
if (item == item_triggering)
@@ -846,7 +872,7 @@ void TeraForm::checkConditionsForItem(QWidget *item, QWidget *item_triggering)
{
if (item->property("condition").isValid()){
// Item has a condition
- if (item->property("condition").canConvert(QMetaType::QVariantHash)){
+ if (item->property("condition").canConvert()){
QVariantHash condition = item->property("condition").toHash();
QString check_id = condition["item"].toString();
if (!check_id.isNull()){
@@ -885,8 +911,9 @@ void TeraForm::checkConditionsForItem(QWidget *item, QWidget *item_triggering)
}
}
if (op.toUpper() == "NOT NULL"){
- if (!sender_index.isNull() || !sender_value.isNull())
+ if ((!sender_index.isValid() && !sender_value.isValid()) || (!sender_value.isValid() || (sender_value.typeId() == QMetaType::QString && !sender_value.toString().isEmpty()))){
condition_met = true;
+ }
}
if (op.toUpper() == "CONTAINS"){
if (sender_index == value || sender_value.toString().contains(value.toString())){
@@ -898,7 +925,7 @@ void TeraForm::checkConditionsForItem(QWidget *item, QWidget *item_triggering)
setWidgetVisibility(item, check_item, condition_met);
// We have a hook requesting data for that specific widget...
- if (!hook.isNull()){
+ if (!hook.isNull() || hook.isValid()){
if (item_triggering == check_item){
if (sender_index.toString() != ""){
if (m_comManager){
@@ -931,7 +958,7 @@ bool TeraForm::hasHookCondition(QWidget *item)
// Check if any item a hook condition on it
if (item->property("condition").isValid()){
// Item has a condition
- if (item->property("condition").canConvert(QMetaType::QVariantHash)){
+ if (item->property("condition").canConvert()){
QVariantHash condition = item->property("condition").toHash();
if (condition.contains("hook"))
return true;
@@ -1036,6 +1063,9 @@ bool TeraForm::getWidgetValues(QWidget* widget, QVariant *id, QVariant *value)
if (btn->property("color").isValid()){
*value = btn->property("color").toString();
}
+ if (btn->property("display_text").isValid()){
+ *value = btn->property("display_text").toString();
+ }
}
if (QTimeEdit* te = dynamic_cast(widget)){
@@ -1057,7 +1087,7 @@ bool TeraForm::getWidgetValues(QWidget* widget, QVariant *id, QVariant *value)
}
- if (value->canConvert(QMetaType::QString)){
+ if (value->canConvert()){
bool ok;
QString string_val = value->toString();
string_val.toInt(&ok);
@@ -1087,7 +1117,7 @@ QVariant TeraForm::getWidgetValue(QWidget *widget)
getWidgetValues(widget, &id, &value);
- if (!id.isNull())
+ if (!id.isNull() || id.isValid())
value = id;
return value;
@@ -1108,7 +1138,7 @@ void TeraForm::setWidgetValue(QWidget *widget, const QVariant &value)
combo->setCurrentIndex(index);
}else{
// Check if we have a number, if so, suppose it is the index
- if (value.canConvert(QMetaType::Int)){
+ if (value.canConvert()){
index = value.toInt();
if (index>=0 && index+1count()){
combo->setCurrentIndex(index+1);
@@ -1127,7 +1157,7 @@ void TeraForm::setWidgetValue(QWidget *widget, const QVariant &value)
}
if (QTextEdit* text = dynamic_cast(widget)){
- if (value.canConvert(QMetaType::QVariantMap) || value.canConvert(QMetaType::QVariantHash)){
+ if (value.canConvert() || value.canConvert()){
QVariantHash data = value.toHash();
QJsonDocument doc;
doc.setObject(QJsonObject::fromVariantHash(data));
@@ -1158,6 +1188,9 @@ void TeraForm::setWidgetValue(QWidget *widget, const QVariant &value)
btn->setProperty("color", value.toString());
btn->setStyleSheet(QString("background-color: " + value.toString() + ";min-width: 32px;"));
return;
+ }else{
+ btn->setProperty("display_text", value.toString());
+ return;
}
}
@@ -1174,7 +1207,7 @@ void TeraForm::setWidgetValue(QWidget *widget, const QVariant &value)
}
if (QDateTimeEdit* dt = dynamic_cast(widget)){
- if (value.canConvert(QVariant::String)){
+ if (value.canConvert()){
if (value.toString().isEmpty()){
widget->hide();
return;
@@ -1182,7 +1215,6 @@ void TeraForm::setWidgetValue(QWidget *widget, const QVariant &value)
}
QDateTime time_value = value.toDateTime().toLocalTime();
-
if (!time_value.isValid()){
unsigned int time_s = value.toUInt();
// Consider we have a UNIX timestamp
@@ -1209,12 +1241,13 @@ void TeraForm::setWidgetRequired(QWidget *item_widget, QLabel *item_label, const
return;
item_widget->setProperty("required", required);
- if (required){
+ item_label->setProperty("required", required);
+ item_label->setProperty("label", item_label->text());
+ /*if (required){
item_label->setText("* " + item_label->text());
}else{
-
item_label->setText(" " + item_label->text());
- }
+ }*/
}
void TeraForm::updateWidgetChoices(QWidget *widget, const QList values)
@@ -1258,7 +1291,7 @@ bool TeraForm::validateWidget(QWidget *widget, bool include_hidden)
QVariant id, value;
getWidgetValues(widget, &id, &value);
//qDebug() << widget->metaObject()->className() << " - " << m_widgets.key(widget) << " - " << value;
- if (value.isNull() || value.toInt()==-1 || value.toString().isEmpty()){
+ if (value.isNull() || !value.isValid() || value.toInt()==-1 || value.toString().isEmpty()){
rval = false;
}
}
@@ -1283,6 +1316,25 @@ qreal TeraForm::doLinearInterpolation(const qreal &p1, const qreal &p2, const qr
return (p1 + (p2-p1)*value);
}
+void TeraForm::updateRequiredWidgetsLabel()
+{
+ for (QLabel* label: m_widgetsLabels){
+ if (m_disabled){
+ if (label->property("label").isValid()){
+ label->setText(label->property("label").toString());
+ }
+ }else{
+ for (QLabel* label: m_widgetsLabels){
+ if (label->property("required").toBool()){
+ label->setText("* " + label->property("label").toString());
+ }else{
+ label->setText(" " + label->property("label").toString());
+ }
+ }
+ }
+ }
+}
+
bool TeraForm::eventFilter(QObject *object, QEvent *event)
{
if(event->type() == QEvent::FocusIn) {
@@ -1344,6 +1396,21 @@ void TeraForm::colorWidgetClicked()
}
}
+void TeraForm::longLabelButtonClicked()
+{
+ QObject* sender = QObject::sender();
+ if (!sender)
+ return;
+
+ QPushButton* sender_widget = dynamic_cast(sender);
+ QString text = sender_widget->property("display_text").toString();
+
+ if (!text.isEmpty()){
+ GlobalMessageBox msgbox(this);
+ msgbox.showInfo(m_widgetsLabels.value(sender_widget)->text(), text);
+ }
+}
+
void TeraForm::hookReplyReceived(TeraDataTypes data_type, QList datas)
{
if (m_widgetsHookRequests.isEmpty())
@@ -1376,8 +1443,12 @@ void TeraForm::setDisabled(bool disable)
m_mainWidget->setDisabled(disable);
}
m_disabled = disable;
- //QWidget::setDisabled(disable);
+ // Hide "required" labels indicators
+ updateRequiredWidgetsLabel();
+
+ //QLabel* widget_label = m_widgetsLabels[widget];
+ //QWidget::setDisabled(disable);
}
@@ -1394,4 +1465,6 @@ void TeraForm::setEnabled(bool enable)
}
m_disabled = !enable;
//QWidget::setEnabled(enable);
+ // Show "required" labels indicators
+ updateRequiredWidgetsLabel();
}
diff --git a/client/src/editors/TeraForm.h b/client/src/editors/TeraForm.h
index c5b6eb85..10c217a0 100644
--- a/client/src/editors/TeraForm.h
+++ b/client/src/editors/TeraForm.h
@@ -25,13 +25,11 @@
#include
#include
-
-#include
-#include
+#include
+#include
#include "TeraData.h"
#include "managers/ComManager.h"
-#include "Utils.h"
namespace Ui {
class TeraForm;
@@ -45,9 +43,13 @@ class TeraForm : public QWidget
explicit TeraForm(QWidget *parent = nullptr, ComManager* com_man = nullptr);
~TeraForm();
+
void buildUiFromStructure(const QString& structure);
void fillFormFromData(const QJsonObject& data);
void fillFormFromData(const QString& structure);
+
+ void setSectionsPosition(const QTabWidget::TabPosition &position);
+
bool formHasData();
bool formHasStructure();
void resetFormValues();
@@ -113,6 +115,7 @@ class TeraForm : public QWidget
QWidget* createBooleanWidget(const QVariantHash& structure);
QWidget* createNumericWidget(const QVariantHash& structure);
QWidget* createLabelWidget(const QVariantHash& structure);
+ QWidget* createLongLabelWidget(const QVariantHash& structure);
QWidget* createListWidget(const QVariantHash& structure);
QWidget* createLongTextWidget(const QVariantHash& structure);
QWidget* createColorWidget(const QVariantHash& structure);
@@ -129,26 +132,25 @@ class TeraForm : public QWidget
bool getWidgetValues(QWidget *widget, QVariant *id, QVariant* value);
QVariant getWidgetValue(QWidget* widget);
void setWidgetValue(QWidget* widget, const QVariant& value);
-
void setWidgetRequired(QWidget* item_widget, QLabel* item_label, const bool& required);
-
void updateWidgetChoices(QWidget* widget, const QList values);
-
bool validateWidget(QWidget* widget, bool include_hidden=false);
static qreal doLinearInterpolation(const qreal &p1, const qreal &p2, const qreal &value);
+ void updateRequiredWidgetsLabel();
+
bool eventFilter(QObject* object, QEvent* event);
private slots:
void widgetValueChanged();
void colorWidgetClicked();
+ void longLabelButtonClicked();
// Hooks
void hookReplyReceived(TeraDataTypes data_type, QList datas);
public slots:
-
void setDisabled(bool disable);
void setEnabled(bool enable);
diff --git a/client/src/editors/TeraForm.ui b/client/src/editors/TeraForm.ui
index 4452a21e..ec390bb9 100644
--- a/client/src/editors/TeraForm.ui
+++ b/client/src/editors/TeraForm.ui
@@ -30,30 +30,16 @@
0
-
-
+
-
- QFrame::Box
+
+ QTabWidget::West
-
- QFrame::Raised
-
-
- 0
-
-
-
-
- 0
- 0
- 396
- 266
-
-
-
- Ce formulaire ne contient aucune information.
+
+
+
diff --git a/client/src/editors/TestTypeWidget.cpp b/client/src/editors/TestTypeWidget.cpp
index e271393d..5cc4716b 100644
--- a/client/src/editors/TestTypeWidget.cpp
+++ b/client/src/editors/TestTypeWidget.cpp
@@ -46,7 +46,7 @@ void TestTypeWidget::saveData(bool signal){
QJsonArray sites;
// Sites
- for(QTreeWidgetItem* item:qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* item:std::as_const(m_treeSites_items)){
if (item->checkState(0) == Qt::Checked){
int site_id = m_treeSites_items.key(item);
QJsonObject data_obj;
@@ -62,7 +62,7 @@ void TestTypeWidget::saveData(bool signal){
}
// Projects
- for(QTreeWidgetItem* item:qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* item:std::as_const(m_treeProjects_items)){
if (item->checkState(0) == Qt::Checked){
int project_id = m_treeProjects_items.key(item);
QJsonObject data_obj;
@@ -234,7 +234,7 @@ void TestTypeWidget::postTestTypeSites()
QJsonObject base_obj;
QJsonArray sites;
- for(QTreeWidgetItem* item: qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeSites_items)){
int site_id = m_treeSites_items.key(item);
if (item->checkState(0) == Qt::Checked){
QJsonObject data_obj;
@@ -257,7 +257,7 @@ void TestTypeWidget::postTestTypeProjects()
QJsonObject base_obj;
QJsonArray projects;
- for(QTreeWidgetItem* item: qAsConst(m_treeProjects_items)){
+ for(QTreeWidgetItem* item: std::as_const(m_treeProjects_items)){
int proj_id = m_treeProjects_items.key(item);
if (item->checkState(0) == Qt::Checked){
QJsonObject data_obj;
@@ -289,7 +289,7 @@ bool TestTypeWidget::validateProjects()
{
if (!m_comManager->isCurrentUserSuperAdmin()){
bool at_least_one_selected = false;
- for(QTreeWidgetItem* site_item:qAsConst(m_treeSites_items)){
+ for(QTreeWidgetItem* site_item:std::as_const(m_treeSites_items)){
if (site_item->checkState(0) == Qt::Checked){
at_least_one_selected = true;
break;
diff --git a/client/src/editors/TestTypeWidget.ui b/client/src/editors/TestTypeWidget.ui
index 71766835..a80c0061 100644
--- a/client/src/editors/TestTypeWidget.ui
+++ b/client/src/editors/TestTypeWidget.ui
@@ -331,6 +331,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
0
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
diff --git a/client/src/editors/UserGroupWidget.cpp b/client/src/editors/UserGroupWidget.cpp
index bc80b3e5..87d7c9e8 100644
--- a/client/src/editors/UserGroupWidget.cpp
+++ b/client/src/editors/UserGroupWidget.cpp
@@ -1,14 +1,12 @@
#include "UserGroupWidget.h"
#include "ui_UserGroupWidget.h"
-#include "editors/DataListWidget.h"
-
UserGroupWidget::UserGroupWidget(ComManager *comMan, const TeraData *data, QWidget *parent) :
DataEditorWidget(comMan, data, parent),
ui(new Ui::UserGroupWidget)
{
- ui->setupUi(this);
+ ui->setupUi(this);
setAttribute(Qt::WA_StyledBackground); //Required to set a background image
// Use base class to manage editing
@@ -45,7 +43,7 @@ void UserGroupWidget::saveData(bool signal)
// Sites
QJsonArray sites;
- for(QTableWidgetItem* site: qAsConst(m_tableSites_items)){
+ for(QTableWidgetItem* site: std::as_const(m_tableSites_items)){
//for (int i=0; irow();
@@ -62,7 +60,7 @@ void UserGroupWidget::saveData(bool signal)
// Projects
QJsonArray projects;
//for (int i=0; irow();
QComboBox* combo_roles = dynamic_cast(ui->tableProjects->cellWidget(row,2));
@@ -106,8 +104,10 @@ void UserGroupWidget::connectSignals()
connect(m_comManager, &ComManager::formReceived, this, &UserGroupWidget::processFormsReply);
connect(m_comManager, &ComManager::siteAccessReceived, this, &UserGroupWidget::processSiteAccessReply);
connect(m_comManager, &ComManager::projectAccessReceived, this, &UserGroupWidget::processProjectAccessReply);
+ connect(m_comManager, &ComManager::servicesAccessReceived, this, &UserGroupWidget::processServiceAccessReply);
connect(m_comManager, &ComManager::sitesReceived, this, &UserGroupWidget::processSitesReply);
connect(m_comManager, &ComManager::projectsReceived, this, &UserGroupWidget::processProjectsReply);
+ connect(m_comManager, &ComManager::servicesRolesReceived, this, &UserGroupWidget::processServiceRolesReply);
connect(m_comManager, &ComManager::userUserGroupsReceived, this, &UserGroupWidget::processUserUserGroupsReply);
connect(m_comManager, &ComManager::postResultsOK, this, &UserGroupWidget::processPostOKReply);
connect(m_comManager, &ComManager::deleteResultsOK, this, &UserGroupWidget::processDeleteReply);
@@ -188,11 +188,13 @@ void UserGroupWidget::updateProjectAccess(const TeraData *access)
item = new QTableWidgetItem(QIcon(access->getIconFilenameForDataType(TERADATA_SITE)),
access->getFieldValue("site_name").toString());
- ui->tableProjects->setItem(current_row, 0, item);
+ ui->tableProjects->setItem(current_row, 1, item);
item = new QTableWidgetItem(QIcon(access->getIconFilenameForDataType(TERADATA_PROJECT)),
access->getFieldValue("project_name").toString());
- ui->tableProjects->setItem(current_row, 1, item);
+ ui->tableProjects->setItem(current_row, 0, item);
combo_roles = buildRolesComboBox();
+ connect(combo_roles, static_cast(&QComboBox::currentIndexChanged),
+ this, &UserGroupWidget::comboProjectRole_changed);
ui->tableProjects->setCellWidget(current_row, 2, combo_roles);
m_tableProjects_items.insert(id_project, item);
m_tableProjectSite_items.insert(id_site, item);
@@ -223,6 +225,47 @@ void UserGroupWidget::updateProjectAccess(const TeraData *access)
}
+void UserGroupWidget::updateServiceRole(const TeraData *access)
+{
+ QTableWidgetItem* item;
+ int id_service = access->getFieldValue("id_service").toInt();
+ QString service_role;
+ if (access->hasFieldName("service_role_name"))
+ service_role = access->getFieldValue("service_role_name").toString();
+ QComboBox* combo_roles;
+ if (m_tableServices_items.contains(id_service)){
+ item = m_tableServices_items[id_service];
+ combo_roles = dynamic_cast(ui->tableServices->cellWidget(item->row(), 1));
+ }else{
+ // Not there - must add the service and role
+ int current_row = ui->tableServices->rowCount();
+ ui->tableServices->setRowCount(ui->tableServices->rowCount()+1);
+ item = new QTableWidgetItem(QIcon(access->getIconFilenameForDataType(TERADATA_SERVICE)),
+ access->getFieldValue("service_name").toString());
+
+ ui->tableServices->setItem(current_row, 0, item);
+ QMap current_role;
+ current_role.insert(access->getId(), access->getName());
+ combo_roles = buildRolesComboBox(current_role);
+ connect(combo_roles, static_cast(&QComboBox::currentIndexChanged),
+ this, &UserGroupWidget::comboServiceRole_changed);
+ combo_roles->setProperty("id_service_access", 0);
+ ui->tableServices->setCellWidget(current_row, 1, combo_roles);
+ m_tableServices_items.insert(id_service, item);
+ }
+
+ if (combo_roles){
+ // Check if the role is already in the list
+ int index = combo_roles->findData(access->getId());
+ if (index == -1){
+ // Insert value in combo
+ combo_roles->addItem(getRoleName(access->getName()), access->getId());
+ }
+ /*combo_roles->setProperty("original_index", index);
+ combo_roles->setDisabled(false);*/
+ }
+}
+
void UserGroupWidget::updateUserUserGroup(const TeraData *uug)
{
int id_user_user_group = uug->getId();
@@ -305,6 +348,12 @@ void UserGroupWidget::updateFieldsValue()
ui->lblTitle->setText(m_data->getName());
}
+ if (m_tableServices_items.isEmpty()){
+ QUrlQuery args;
+ args.addQueryItem(WEB_QUERY_GLOBALS, "1");
+ queryDataRequest(WEB_SERVICEROLEINFO_PATH, args);
+ }
+
}
@@ -337,6 +386,8 @@ void UserGroupWidget::processSiteAccessReply(QList access, QUrlQuery r
updateSiteAccess(&access.at(i));
}
+ ui->btnUpdateSitesRoles->setEnabled(false);
+
}
void UserGroupWidget::processProjectAccessReply(QList access, QUrlQuery reply_query)
@@ -355,6 +406,8 @@ void UserGroupWidget::processProjectAccessReply(QList access, QUrlQuer
updateProjectAccess(&access.at(i));
}
+ ui->btnUpdateProjectsRoles->setEnabled(false);
+
}
void UserGroupWidget::processSitesReply(QList sites)
@@ -371,6 +424,38 @@ void UserGroupWidget::processProjectsReply(QList projects)
}
}
+void UserGroupWidget::processServiceRolesReply(QList roles, QUrlQuery reply_query)
+{
+ for (int i=0; i access, QUrlQuery reply_query)
+{
+ for (int i=0; ihasFieldName("id_service")){
+ // Find service item
+ QTableWidgetItem* service_row = m_tableServices_items.value(current_access->getFieldValue("id_service").toInt(), nullptr);
+ if (service_row){
+ // Get related combo box and check if id_service_role present
+ QComboBox* combo = dynamic_cast(ui->tableServices->cellWidget(service_row->row(), 1));
+ if (combo){
+ int role_index = combo->findData(current_access->getFieldValue("id_service_role").toInt());
+ if (role_index != -1){ // Found
+ combo->setCurrentIndex(role_index);
+ }
+ combo->setProperty("original_index", role_index);
+ combo->setProperty("id_service_access", current_access->getId());
+ }
+ }
+ }
+ }
+
+ ui->btnUpdateServicesRoles->setEnabled(false);
+}
+
void UserGroupWidget::processUserUserGroupsReply(QList users_user_groups)
{
for (int i=0; irow();
QComboBox* combo_roles = dynamic_cast(ui->tableSites->cellWidget(row,1));
@@ -391,12 +476,13 @@ void UserGroupWidget::processPostOKReply(QString path)
combo_roles->setProperty("original_index", combo_roles->currentIndex());
}
}
+ ui->btnUpdateSitesRoles->setEnabled(false);
}
if (path == TeraData::getPathForDataType(TERADATA_PROJECTACCESS)){
// Reset "dirty" flag on each combo box role
//for (int i=0; irow();
QComboBox* combo_roles = dynamic_cast(ui->tableProjects->cellWidget(row,2));
@@ -404,6 +490,22 @@ void UserGroupWidget::processPostOKReply(QString path)
combo_roles->setProperty("original_index", combo_roles->currentIndex());
}
}
+ ui->btnUpdateProjectsRoles->setEnabled(false);
+ }
+
+ if (path == TeraData::getPathForDataType(TERADATA_SERVICE_ACCESS)){
+ for(QTableWidgetItem* service: std::as_const(m_tableServices_items)){
+ int service_id = m_tableServices_items.key(service);
+ int row = m_tableServices_items[service_id]->row();
+ QComboBox* combo_roles = dynamic_cast(ui->tableServices->cellWidget(row,1));
+ if (combo_roles){
+ combo_roles->setProperty("original_index", combo_roles->currentIndex());
+ if (combo_roles->currentIndex() == 0){
+ combo_roles->setProperty("id_service_access", 0);
+ }
+ }
+ }
+ ui->btnUpdateServicesRoles->setEnabled(false);
}
}
@@ -418,13 +520,12 @@ void UserGroupWidget::processDeleteReply(QString path, int id)
void UserGroupWidget::btnUpdateSiteAccess_clicked()
{
-
QJsonDocument document;
QJsonObject base_obj;
QJsonArray roles;
//for (int i=0; irow();
QComboBox* combo_roles = dynamic_cast(ui->tableSites->cellWidget(row,1));
@@ -449,13 +550,12 @@ void UserGroupWidget::btnUpdateSiteAccess_clicked()
void UserGroupWidget::btnUpdateProjectAccess_clicked()
{
-
QJsonDocument document;
QJsonObject base_obj;
QJsonArray roles;
//for (int i=0; irow();
QComboBox* combo_roles = dynamic_cast(ui->tableProjects->cellWidget(row,2));
@@ -500,7 +600,7 @@ void UserGroupWidget::comboSiteRole_changed(int index)
// Find all related project items
QList project_items = m_tableProjectSite_items.values(id_site);
bool is_site_admin = combo->currentData() == "admin";
- for(QTableWidgetItem* project_item: qAsConst(project_items)){
+ for(QTableWidgetItem* project_item: std::as_const(project_items)){
// Get combo box
QComboBox* combo_role = dynamic_cast(ui->tableProjects->cellWidget(project_item->row(), 2));
if (combo_role){
@@ -520,6 +620,55 @@ void UserGroupWidget::comboSiteRole_changed(int index)
}
}
}
+ }else{
+ // Enable save button if changes
+ bool has_changes = false;
+ for (QTableWidgetItem* item: m_tableSites_items){
+ QComboBox* combo = dynamic_cast(ui->tableSites->cellWidget(item->row(), 1));
+ if (combo){
+ if (combo->currentIndex() != combo->property("original_index").toInt()){
+ has_changes = true;
+ break;
+ }
+ }
+ }
+ ui->btnUpdateSitesRoles->setEnabled(has_changes);
+ }
+}
+
+void UserGroupWidget::comboProjectRole_changed(int index)
+{
+ if (!dataIsNew()){
+ // Enable save button if changes
+ bool has_changes = false;
+ for (QTableWidgetItem* item: m_tableProjects_items){
+ QComboBox* combo = dynamic_cast(ui->tableProjects->cellWidget(item->row(), 2));
+ if (combo){
+ if (combo->currentIndex() != combo->property("original_index").toInt()){
+ has_changes = true;
+ break;
+ }
+ }
+ }
+ ui->btnUpdateProjectsRoles->setEnabled(has_changes);
+ }
+}
+
+void UserGroupWidget::comboServiceRole_changed(int index)
+{
+ if (!dataIsNew()){
+ // Enable save button if changes
+ bool has_changes = false;
+ for (QTableWidgetItem* item: m_tableServices_items){
+ QComboBox* combo = dynamic_cast(ui->tableServices->cellWidget(item->row(), 1));
+ if (combo){
+ if (combo->currentIndex() != combo->property("original_index").toInt()){
+ has_changes = true;
+ break;
+ }
+ }
+ }
+ ui->btnUpdateServicesRoles->setEnabled(has_changes);
}
}
@@ -538,6 +687,7 @@ void UserGroupWidget::on_tabNav_currentChanged(int index)
}
if (current_tab == ui->tabSites){
+ // Sites
args.addQueryItem(WEB_QUERY_WITH_EMPTY, "1");
queryDataRequest(WEB_SITEACCESS_PATH, args);
}
@@ -549,6 +699,11 @@ void UserGroupWidget::on_tabNav_currentChanged(int index)
queryDataRequest(WEB_USERUSERGROUPINFO_PATH, args);
}
}
+
+ if (current_tab == ui->tabServices){
+ // Global service access
+ queryDataRequest(WEB_SERVICEACCESSINFO_PATH, args);
+ }
}
void UserGroupWidget::on_btnUpdateUsers_clicked()
@@ -590,3 +745,35 @@ void UserGroupWidget::on_btnUpdateUsers_clicked()
}
}
+void UserGroupWidget::on_btnUpdateServicesRoles_clicked()
+{
+ QJsonDocument document;
+ QJsonObject base_obj;
+ QJsonArray roles;
+
+ for(QTableWidgetItem* service: std::as_const(m_tableServices_items)){
+ int service_id = m_tableServices_items.key(service);
+ int row = m_tableServices_items[service_id]->row();
+ QComboBox* combo_roles = dynamic_cast(ui->tableServices->cellWidget(row,1));
+ if (combo_roles->property("original_index").toInt() != combo_roles->currentIndex()){
+ int id_service_access = combo_roles->property("id_service_access").toInt();
+ QJsonObject data_obj;
+ // Ok, value was modified - must add!
+ QJsonValue role = combo_roles->currentData().toString();
+ data_obj.insert("id_user_group", m_data->getId());
+ if ((id_service_access > 0 && combo_roles->currentIndex() != 0) || (id_service_access == 0 && combo_roles->currentIndex()>0)){
+ // Only add "id_service_role" if the item is selected. When no role is selected, don't include any id_service_role
+ data_obj.insert("id_service_role", role);
+ }
+ data_obj.insert("id_service_access", id_service_access);
+ roles.append(data_obj);
+ }
+ }
+
+ if (!roles.isEmpty()){
+ base_obj.insert("service_access", roles);
+ document.setObject(base_obj);
+ postDataRequest(WEB_SERVICEACCESSINFO_PATH, document.toJson());
+ }
+}
+
diff --git a/client/src/editors/UserGroupWidget.h b/client/src/editors/UserGroupWidget.h
index eb556814..2e909a0a 100644
--- a/client/src/editors/UserGroupWidget.h
+++ b/client/src/editors/UserGroupWidget.h
@@ -5,9 +5,8 @@
#include
#include
+#include "editors/DataListWidget.h"
#include "DataEditorWidget.h"
-#include "GlobalMessageBox.h"
-#include "dialogs/BaseDialog.h"
namespace Ui {
class UserGroupWidget;
@@ -30,6 +29,8 @@ private slots:
void processProjectAccessReply(QList access, QUrlQuery reply_query);
void processSitesReply(QList sites);
void processProjectsReply(QList projects);
+ void processServiceRolesReply(QList roles, QUrlQuery reply_query);
+ void processServiceAccessReply(QList access, QUrlQuery reply_query);
void processUserUserGroupsReply(QList users_user_groups);
void processPostOKReply(QString path);
void processDeleteReply(QString path, int id);
@@ -38,23 +39,30 @@ private slots:
void btnUpdateProjectAccess_clicked();
void comboSiteRole_changed(int index);
+ void comboProjectRole_changed(int index);
+ void comboServiceRole_changed(int index);
+
void on_tabNav_currentChanged(int index);
void on_btnUpdateUsers_clicked();
+ void on_btnUpdateServicesRoles_clicked();
+
private:
Ui::UserGroupWidget *ui;
- QMap m_tableProjects_items;
- QMultiMap m_tableProjectSite_items; // Map: id_site, project item
- QMap m_tableSites_items;
+ QMap m_tableProjects_items;
+ QMultiMap m_tableProjectSite_items; // Map: id_site, project item
+ QMap m_tableSites_items;
+ QMap m_tableServices_items;
- QMap m_listUsersUserGroups_items;
- QMap m_listUsers_items;
+ QMap m_listUsersUserGroups_items;
+ QMap m_listUsers_items;
void connectSignals();
void updateSiteAccess(const TeraData* access);
void updateProjectAccess(const TeraData* access);
+ void updateServiceRole(const TeraData* access);
void updateUserUserGroup(const TeraData* uug);
void updateControlsState();
diff --git a/client/src/editors/UserGroupWidget.ui b/client/src/editors/UserGroupWidget.ui
index 92cd9693..c5cd9cc5 100644
--- a/client/src/editors/UserGroupWidget.ui
+++ b/client/src/editors/UserGroupWidget.ui
@@ -269,6 +269,9 @@
-
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -299,6 +302,9 @@
true
+
+ false
+
Site
@@ -313,6 +319,9 @@
-
+
+ false
+
0
@@ -374,6 +383,9 @@
-
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -404,14 +416,17 @@
true
+
+ false
+
- Site
+ Projet
- Projet
+ Site
@@ -423,6 +438,9 @@
-
+
+ false
+
0
@@ -449,6 +467,96 @@
+
+
+
+ :/icons/service.png:/icons/service.png
+
+
+ Accès - Services
+
+
+ -
+
+
+ Qt::NoFocus
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ false
+
+
+ false
+
+
+ QAbstractItemView::NoSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+ true
+
+
+ 2
+
+
+ 250
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+
+ Service
+
+
+
+
+ Rôle
+
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 32
+
+
+
+ PointingHandCursor
+
+
+ Mettre à jour les rôles des services
+
+
+
+ :/icons/save.png:/icons/save.png
+
+
+
+ 24
+ 24
+
+
+
+
+
+
@@ -460,6 +568,9 @@
-
+
+ Qt::NoFocus
+
24
diff --git a/client/src/editors/UserSummaryWidget.cpp b/client/src/editors/UserSummaryWidget.cpp
index 98b857a0..45fa08b5 100644
--- a/client/src/editors/UserSummaryWidget.cpp
+++ b/client/src/editors/UserSummaryWidget.cpp
@@ -11,7 +11,9 @@ UserSummaryWidget::UserSummaryWidget(ComManager *comMan, const TeraData *data, c
{
m_diag_editor = nullptr;
+#ifndef OPENTERA_WEBASSEMBLY
m_sessionLobby = nullptr;
+#endif
m_passwordJustGenerated = false;
m_idProject = id_project;
@@ -50,9 +52,11 @@ UserSummaryWidget::UserSummaryWidget(ComManager *comMan, const TeraData *data, c
UserSummaryWidget::~UserSummaryWidget()
{
delete ui;
-
- if (m_sessionLobby)
+#ifndef OPENTERA_WEBASSEMBLY
+ if (m_sessionLobby) {
m_sessionLobby->deleteLater();
+ }
+#endif
}
void UserSummaryWidget::connectSignals()
@@ -309,6 +313,7 @@ void UserSummaryWidget::ws_userEvent(UserEvent event)
updateFieldsValue();
}
+#ifndef OPENTERA_WEBASSEMBLY
void UserSummaryWidget::sessionLobbyStartSessionRequested()
{
int id_session_type = ui->cmbSessionType->currentData().toInt();
@@ -356,6 +361,7 @@ void UserSummaryWidget::on_btnNewSession_clicked()
// Show Session Lobby
m_sessionLobby->exec();
}
+#endif
void UserSummaryWidget::on_tabNav_currentChanged(int index)
{
diff --git a/client/src/editors/UserSummaryWidget.h b/client/src/editors/UserSummaryWidget.h
index 3799621c..5448597d 100644
--- a/client/src/editors/UserSummaryWidget.h
+++ b/client/src/editors/UserSummaryWidget.h
@@ -10,7 +10,9 @@
#include "TeraSessionStatus.h"
#include "Utils.h"
#include "ServiceConfigWidget.h"
+#ifndef OPENTERA_WEBASSEMBLY
#include "dialogs/SessionLobbyDialog.h"
+#endif
namespace Ui {
class UserSummaryWidget;
@@ -22,9 +24,9 @@ class UserSummaryWidget : public DataEditorWidget
public:
explicit UserSummaryWidget(ComManager* comMan, const TeraData* data = nullptr, const int &id_project = -1, QWidget *parent = nullptr);
- ~UserSummaryWidget();
+ ~UserSummaryWidget() override;
- void saveData(bool signal=true);
+ void saveData(bool signal=true) override;
void connectSignals();
@@ -34,18 +36,20 @@ class UserSummaryWidget : public DataEditorWidget
QMap m_ids_session_types;
BaseDialog* m_diag_editor;
+#ifndef OPENTERA_WEBASSEMBLY
SessionLobbyDialog* m_sessionLobby;
+#endif
int m_idProject;
bool m_passwordJustGenerated;
bool m_currentUserPasswordChanged;
- void updateControlsState();
- void updateFieldsValue();
+ void updateControlsState() override;
+ void updateFieldsValue() override;
void initUI();
- bool validateData();
+ bool validateData() override;
private slots:
void processFormsReply(QString form_type, QString data);
@@ -58,11 +62,11 @@ private slots:
void userFormValueHasFocus(QWidget* widget);
void ws_userEvent(opentera::protobuf::UserEvent event);
-
+#ifndef OPENTERA_WEBASSEMBLY
void sessionLobbyStartSessionRequested();
void sessionLobbyStartSessionCancelled();
-
void on_btnNewSession_clicked();
+#endif
void on_tabNav_currentChanged(int index);
diff --git a/client/src/editors/UserWidget.cpp b/client/src/editors/UserWidget.cpp
index 49af9c35..389f1abc 100644
--- a/client/src/editors/UserWidget.cpp
+++ b/client/src/editors/UserWidget.cpp
@@ -1,12 +1,11 @@
#include "UserWidget.h"
#include "ui_UserWidget.h"
-#include
-#include
+#include
#include
#include
-#include
+#include
#include "dialogs/PasswordStrengthDialog.h"
@@ -160,7 +159,7 @@ void UserWidget::updateControlsState(){
if (!has_site_admin_access){
// Check if we are admin in a list one site
QList id_sites = m_userSitesRole.keys();
- for(int id_site:qAsConst(id_sites)){
+ for(int id_site:std::as_const(id_sites)){
if (m_comManager->isCurrentUserSiteAdmin(id_site)){
has_site_admin_access = true;
break;
@@ -207,7 +206,7 @@ bool UserWidget::validateData(){
void UserWidget::refreshUsersUserGroups()
{
- for(QListWidgetItem* item: qAsConst(m_listUserGroups_items)){
+ for(QListWidgetItem* item: std::as_const(m_listUserGroups_items)){
if (std::find(m_listUserUserGroups_items.cbegin(), m_listUserUserGroups_items.cend(), item) != m_listUserUserGroups_items.cend()){
//if (m_listUserUserGroups_items.contains(item)){
item->setCheckState(Qt::Checked);
@@ -229,7 +228,7 @@ void UserWidget::refreshUsersUserGroups()
QJsonArray UserWidget::getSelectedGroupsAsJsonArray()
{
QJsonArray user_groups;
- for(QListWidgetItem* item: qAsConst(m_listUserGroups_items)){
+ for(QListWidgetItem* item: std::as_const(m_listUserGroups_items)){
int user_group_id = m_listUserGroups_items.key(item);
if (item->checkState() == Qt::Checked){
QJsonObject data_obj;
@@ -334,6 +333,19 @@ void UserWidget::updateProjectAccess(const TeraData *project_access)
ui->tableProjectsRoles->setItem(current_row,2,item);
}
+void UserWidget::updateServiceAccess(const TeraData *service_access)
+{
+ // We assume the table is cleared beforehand and that item isn't already present.
+ int current_row = ui->tableServicesRoles->rowCount();
+ ui->tableServicesRoles->setRowCount(ui->tableServicesRoles->rowCount()+1);
+ QTableWidgetItem* item = new QTableWidgetItem(service_access->getFieldValue("service_name").toString());
+ item->setIcon(QIcon(TeraData::getIconFilenameForDataType(TERADATA_SERVICE)));
+ ui->tableServicesRoles->setItem(current_row,0,item);
+ item = new QTableWidgetItem(getRoleName(service_access->getFieldValue("service_access_role_name").toString()));
+ ui->tableServicesRoles->setItem(current_row,1,item);
+
+}
+
void UserWidget::queryUserAccess()
{
// Roles
@@ -344,6 +356,9 @@ void UserWidget::queryUserAccess()
ui->tableSitesRoles->clearContents();
ui->tableSitesRoles->setRowCount(0);
ui->tableSitesRoles->sortItems(-1);
+ ui->tableServicesRoles->clearContents();
+ ui->tableServicesRoles->setRowCount(0);
+ ui->tableServicesRoles->sortItems(-1);
// Query sites and projects roles
if (!m_data->isNew()){
@@ -351,6 +366,9 @@ void UserWidget::queryUserAccess()
args.addQueryItem(WEB_QUERY_ID_USER, QString::number(m_data->getId()));
queryDataRequest(WEB_SITEACCESS_PATH, args);
+
+ queryDataRequest(WEB_SERVICEACCESSINFO_PATH, args);
+
args.addQueryItem(WEB_QUERY_WITH_SITES, "1");
queryDataRequest(WEB_PROJECTACCESS_PATH, args);
@@ -362,7 +380,7 @@ bool UserWidget::validateUserGroups()
//if (!m_comManager->isCurrentUserSuperAdmin()){
bool at_least_one_selected = false;
//for (int i=0; icheckState() == Qt::Checked){
at_least_one_selected = true;
break;
@@ -405,7 +423,7 @@ void UserWidget::processSitesAccessReply(QList sites)
foreach (TeraData site, sites){
updateSiteAccess(&site);
}
- ui->tableSitesRoles->resizeColumnsToContents();
+ //ui->tableSitesRoles->resizeColumnsToContents();
}
void UserWidget::processProjectsAccessReply(QList projects)
@@ -413,7 +431,17 @@ void UserWidget::processProjectsAccessReply(QList projects)
foreach (TeraData project, projects){
updateProjectAccess(&project);
}
- ui->tableProjectsRoles->resizeColumnsToContents();
+ //ui->tableProjectsRoles->resizeColumnsToContents();
+}
+
+void UserWidget::processServicesAccessReply(QList services_access)
+{
+ foreach (TeraData access, services_access){
+ // Ignore "OpenTera" service
+ if (access.getFieldValue("service_key").toString() == "OpenTeraServer")
+ continue;
+ updateServiceAccess(&access);
+ }
}
void UserWidget::processUserGroupsReply(QList user_groups, QUrlQuery query)
@@ -502,6 +530,7 @@ void UserWidget::connectSignals()
connect(m_comManager, &ComManager::usersReceived, this, &UserWidget::processUsersReply);
connect(m_comManager, &ComManager::siteAccessReceived, this, &UserWidget::processSitesAccessReply);
connect(m_comManager, &ComManager::projectAccessReceived, this, &UserWidget::processProjectsAccessReply);
+ connect(m_comManager, &ComManager::servicesAccessReceived, this, &UserWidget::processServicesAccessReply);
connect(m_comManager, &ComManager::formReceived, this, &UserWidget::processFormsReply);
connect(m_comManager, &ComManager::userGroupsReceived, this, &UserWidget::processUserGroupsReply);
connect(m_comManager, &ComManager::userUserGroupsReceived, this, &UserWidget::processUserUsersGroupsReply);
@@ -527,6 +556,7 @@ void UserWidget::initUI()
void UserWidget::on_tabMain_currentChanged(int index)
{
QUrlQuery args;
+ bool super_admin = m_data->getFieldValue("user_superadmin").toBool();
if (!ui->tabMain->currentWidget()->isEnabled())
return;
@@ -543,19 +573,21 @@ void UserWidget::on_tabMain_currentChanged(int index)
//}
// If user is super admin, disable groups
- bool super_admin = m_data->getFieldValue("user_superadmin").toBool();
ui->lblWarning->setVisible(super_admin);
ui->frameGroups->setVisible(!super_admin);
}
if (current_tab == ui->tabRoles){
queryUserAccess();
+ // If user is super admin, disable services
+ ui->lblWarning2->setVisible(super_admin);
+ ui->tableServicesRoles->setVisible(!super_admin);
}
if (current_tab == ui->tabConfig){
// Service config
if (!ui->wdgServiceConfig->layout()){
QHBoxLayout* layout = new QHBoxLayout();
- layout->setMargin(0);
+ layout->setContentsMargins(0,0,0,0);
ui->wdgServiceConfig->setLayout(layout);
}
if (ui->wdgServiceConfig->layout()->count() == 0){
@@ -605,7 +637,7 @@ void UserWidget::on_btnUpdateGroups_clicked()
QList user_user_group_to_delete;
//for (int i=0; icheckState()==Qt::Checked){
QJsonObject item_obj;
diff --git a/client/src/editors/UserWidget.h b/client/src/editors/UserWidget.h
index 35d66955..cea5644d 100644
--- a/client/src/editors/UserWidget.h
+++ b/client/src/editors/UserWidget.h
@@ -64,6 +64,7 @@ class UserWidget : public DataEditorWidget
void updateUserGroup(const TeraData* group);
void updateSiteAccess(const TeraData* site_access);
void updateProjectAccess(const TeraData* project_access);
+ void updateServiceAccess(const TeraData* service_access);
void queryUserAccess();
@@ -76,6 +77,7 @@ private slots:
void processUsersReply(QList users);
void processSitesAccessReply(QList sites);
void processProjectsAccessReply(QList projects);
+ void processServicesAccessReply(QList services_access);
void processUserGroupsReply(QList user_groups, QUrlQuery query);
void processUserUsersGroupsReply(QList user_users_groups, QUrlQuery query);
void processUserPrefsReply(QList user_prefs, QUrlQuery query);
diff --git a/client/src/editors/UserWidget.ui b/client/src/editors/UserWidget.ui
index 199f7b91..855d1681 100644
--- a/client/src/editors/UserWidget.ui
+++ b/client/src/editors/UserWidget.ui
@@ -70,7 +70,7 @@
-
- 5
+ 0
@@ -297,6 +297,9 @@
0
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -306,6 +309,12 @@
QAbstractItemView::NoSelection
+
+
+ 24
+ 24
+
+
true
@@ -408,12 +417,21 @@
-
+
+ QAbstractItemView::NoEditTriggers
+
QAbstractItemView::NoSelection
QAbstractItemView::SelectRows
+
+
+ 24
+ 24
+
+
true
@@ -486,12 +504,21 @@
-
+
+ QAbstractItemView::NoEditTriggers
+
QAbstractItemView::NoSelection
QAbstractItemView::SelectRows
+
+
+ 24
+ 24
+
+
true
@@ -524,6 +551,94 @@
+ -
+
+
-
+
+
+
+ 32
+ 32
+
+
+
+
+ 32
+ 32
+
+
+
+
+
+
+ :/icons/service.png
+
+
+ true
+
+
+
+ -
+
+
+
+ 10
+ true
+ true
+
+
+
+ Services
+
+
+
+
+
+ -
+
+
+ Cet utilisateur est un super-administrateur.
+
+
+
+ -
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ QAbstractItemView::NoSelection
+
+
+
+ 24
+ 24
+
+
+
+ 175
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+
+ Service
+
+
+
+
+ Rôle
+
+
+
+
diff --git a/client/src/kit/KitConfigDialog.h b/client/src/kit/KitConfigDialog.h
index 96d38e8f..b1bbd434 100644
--- a/client/src/kit/KitConfigDialog.h
+++ b/client/src/kit/KitConfigDialog.h
@@ -25,7 +25,7 @@ class KitConfigDialog : public QDialog
public:
explicit KitConfigDialog(ComManager* comMan, KitConfigManager* kitConfig, QWidget *parent = nullptr);
- ~KitConfigDialog();
+ ~KitConfigDialog() override;
private slots:
void on_btnClose_clicked();
diff --git a/client/src/kit/KitVideoRehabWidget.cpp b/client/src/kit/KitVideoRehabWidget.cpp
index 4e1b0ebb..95d58e0e 100644
--- a/client/src/kit/KitVideoRehabWidget.cpp
+++ b/client/src/kit/KitVideoRehabWidget.cpp
@@ -53,13 +53,11 @@ void KitVideoRehabWidget::initUi()
ui->icoLoading->setMovie(m_loadingIcon);
m_loadingIcon->start();
- QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
- QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, false);
-
m_webEngine = new QWebEngineView(ui->wdgWebEngine);
connect(m_webEngine, &QWebEngineView::loadFinished, this, &KitVideoRehabWidget::webPageLoaded);
// Create a new page
+ // DL 21/04/2023 settings are now in VideoRehabWebPage constructor
m_webPage = new VideoRehabWebPage(m_webEngine);
connect(m_webPage->getSharedObject(), &SharedObject::pageIsReady, this, &KitVideoRehabWidget::webPageReady);
connect(m_webPage->getSharedObject(), &SharedObject::videoErrorOccured, this, &KitVideoRehabWidget::webPageVideoError);
@@ -294,11 +292,11 @@ void KitVideoRehabWidget::startVirtualCamera(const QString &src)
m_virtualCamThread = new VirtualCameraThread(src);
connect(m_virtualCamThread, &VirtualCameraThread::virtualCamDisconnected, this, &KitVideoRehabWidget::virtualCameraDisconnected);
m_virtualCamThread->start();
+
}
void KitVideoRehabWidget::stopVirtualCamera()
{
- qDebug() << "KitVideoRehabWidget::stopVirtualCamera";
if (m_virtualCamThread){
m_virtualCamThread->quit();
m_virtualCamThread->wait();
diff --git a/client/src/libs/AudioVideoUtils.cpp b/client/src/libs/AudioVideoUtils.cpp
new file mode 100644
index 00000000..7bc29c11
--- /dev/null
+++ b/client/src/libs/AudioVideoUtils.cpp
@@ -0,0 +1,194 @@
+#include "AudioVideoUtils.h"
+#include
+#include
+#include
+
+#include
+
+AudioVideoUtils::AudioVideoUtils(QObject *parent) : QObject(parent) {
+
+}
+
+QStringList AudioVideoUtils::getAudioDeviceNames()
+{
+ QStringList names;
+
+
+ auto audio_devices = QMediaDevices::audioInputs();
+ //QList audio_devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
+ foreach(const QAudioDevice &input, audio_devices){
+//TODO FIX LINUX
+#if 0
+//#ifdef Q_OS_LINUX
+ // On linux, since Qt use ALSA API, we must filter the returned device list...
+ if (input.deviceName().startsWith("alsa_input") || input.deviceName() == "default"){
+ QString filtered_name = input.deviceName();
+ if (input.deviceName() != "default"){
+ QStringList name_parts = filtered_name.split(".");
+ // Removes first part - usually is "alsa_input"
+ if (name_parts.count()>1)
+ filtered_name = name_parts[1];
+
+ // Split using "_" to remove first and last part, and replace others with spaces
+ name_parts = filtered_name.split("_");
+ if (name_parts.count()>2){
+ filtered_name = "";
+ for (int i=1; i1)
+ filtered_name += " ";
+ filtered_name += name_parts[i];
+ }
+ }else{
+ // No audio name...
+ name_parts = filtered_name.split("-");
+ if (name_parts.count()>2){
+ filtered_name = name_parts[1].replace("_", ":");
+ }
+ }
+
+ }
+ names.append(filtered_name);
+ }
+#else \
+ //TODO Not sure!
+ names.append(input.description());
+#endif
+ }
+ return names;
+}
+
+QStringList AudioVideoUtils::getVideoDeviceNames()
+{
+ QStringList names;
+
+ auto inputs = QMediaDevices::videoInputs();
+ foreach (const QCameraDevice &info, inputs)
+ {
+ QString name = info.description();
+ if (!name.contains(" IR ")) // Remove infrared cameras.
+ names.append(info.description());
+ }
+#ifdef Q_OS_WINDOWS
+ // Also query virtual cameras, since they are not detected anymore by QMediaDevices
+ names.append(AudioVideoUtils::getVirtualCameras());
+
+ //names.append("OpenTeraCam");
+#endif
+ return names;
+}
+
+#ifdef Q_OS_WINDOWS
+QStringList AudioVideoUtils::getVirtualCameras()
+{
+ //qDebug() << "AudioVideoUtils::getVirtualCameras()";
+
+ IEnumMoniker *pEnum = nullptr;
+ HRESULT hr = AudioVideoUtils::enumerateCameras(&pEnum);
+
+ if (FAILED(hr))
+ {
+ //qDebug("enumerate Fails");
+ return QStringList();
+ }
+
+ IMoniker *pMoniker = nullptr;
+ QString devicePath;
+
+ for (int i = 0; pEnum->Next(1, &pMoniker, nullptr) == S_OK; i++) {
+ IBaseFilter *filter = nullptr;
+ hr = pMoniker->BindToObject(nullptr,
+ nullptr,
+ IID_IBaseFilter,
+ reinterpret_cast(&filter));
+
+ if (FAILED(hr)) {
+ pMoniker->Release();
+ pMoniker = nullptr;
+
+ continue;
+ }
+
+ CLSID clsid;
+
+ if (FAILED(filter->GetClassID(&clsid))) {
+ filter->Release();
+ pMoniker->Release();
+ pMoniker = nullptr;
+
+ continue;
+ }
+
+ filter->Release();
+
+ if (clsid != CLSID_VirtualCameraSource) {
+ pMoniker->Release();
+ pMoniker = nullptr;
+
+ continue;
+ }
+
+ IPropertyBag *pPropBag = nullptr;
+ hr = pMoniker->BindToStorage(nullptr,
+ nullptr,
+ IID_IPropertyBag,
+ reinterpret_cast(&pPropBag));
+
+ if (SUCCEEDED(hr)) {
+ VARIANT var;
+ VariantInit(&var);
+ hr = pPropBag->Read(L"FriendlyName", &var, 0);
+
+ if (SUCCEEDED(hr))
+ devicePath = QString::fromWCharArray(var.bstrVal);
+ else
+ devicePath = QString("OpenTeraCam").arg(i);
+
+ pPropBag->Release();
+ }
+
+ pMoniker->Release();
+ pMoniker = nullptr;
+
+ break;
+ }
+
+ pEnum->Release();
+
+ QStringList webcams;
+
+ if (!devicePath.isEmpty())
+ webcams << devicePath;
+
+
+ //qDebug() << "AudioVideoUtils: " << webcams;
+ return webcams;
+}
+
+HRESULT AudioVideoUtils::enumerateCameras(IEnumMoniker **ppEnum)
+{
+ // Create the System Device Enumerator.
+ ICreateDevEnum *pDevEnum = nullptr;
+ HRESULT hr = CoInitialize(nullptr);
+
+ if (SUCCEEDED(hr)) {
+
+ hr = CoCreateInstance(CLSID_SystemDeviceEnum,
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ IID_ICreateDevEnum,
+ reinterpret_cast(&pDevEnum));
+
+ if (SUCCEEDED(hr)) {
+ // Create an enumerator for the category.
+ hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, ppEnum, 0);
+
+ if (hr == S_FALSE)
+ hr = VFW_E_NOT_FOUND;
+
+ pDevEnum->Release();
+ }
+ }
+
+ return hr;
+}
+#endif
diff --git a/client/src/libs/AudioVideoUtils.h b/client/src/libs/AudioVideoUtils.h
new file mode 100644
index 00000000..454e4486
--- /dev/null
+++ b/client/src/libs/AudioVideoUtils.h
@@ -0,0 +1,31 @@
+#ifndef AUDIOVIDEOUTILS_H
+#define AUDIOVIDEOUTILS_H
+
+#include
+
+#ifdef Q_OS_WINDOWS
+ #include
+ #include
+ #include
+ #include
+ DEFINE_GUID(CLSID_VirtualCameraSource, 0x41764b79, 0x7320, 0x5669, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x43, 0x61, 0x6d);
+#endif
+
+class AudioVideoUtils: public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit AudioVideoUtils(QObject *parent = nullptr);
+
+ static QStringList getAudioDeviceNames();
+ static QStringList getVideoDeviceNames();
+
+private:
+#ifdef Q_OS_WINDOWS
+ static QStringList getVirtualCameras();
+ static HRESULT enumerateCameras(IEnumMoniker **ppEnum);
+#endif
+};
+
+#endif // AUDIOVIDEOUTILS_H
diff --git a/client/src/main.cpp b/client/src/main.cpp
index 779519c4..3bf1a8a3 100755
--- a/client/src/main.cpp
+++ b/client/src/main.cpp
@@ -3,7 +3,7 @@
*
*/
#include "ClientApp.h"
-#include
+//#include
#include
int main(int argc, char* argv[])
@@ -11,17 +11,6 @@ int main(int argc, char* argv[])
// Global settings
QCoreApplication::setOrganizationName("INTER");
QCoreApplication::setApplicationName("OpenTeraPlus");
-
-#ifdef WIN32
- //QApplication::setAttribute(Qt::AA_UseOpenGLES, true); // Force use of ANGLE instead of Desktop OpenGL - some memory leak may happen with WebRTC on Intel Graphics Cards otherwise.
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
- QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton, true);
-#endif
-
-#ifdef __APPLE__
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
-#endif
-
#ifdef QT_DEBUG
qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--autoplay-policy=no-user-gesture-required --remote-debugging-port=22222"); // Allow auto-play feature in webengine without any user interaction to test, for example, the microphone and play sounds
#else
@@ -34,10 +23,11 @@ int main(int argc, char* argv[])
#ifndef WIN32 // Don't set style on Windows - it creates some issues with combobox look.
//app->setStyle("windows");
#endif
+
//WebEngine default Settings
- /*QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
- QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
- QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);*/
+ //QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
+ //QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
+ //QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
return app.exec();
}
diff --git a/client/src/main/MainWindow.cpp b/client/src/main/MainWindow.cpp
index ff39ca4e..af8657f1 100644
--- a/client/src/main/MainWindow.cpp
+++ b/client/src/main/MainWindow.cpp
@@ -1,8 +1,7 @@
#include "MainWindow.h"
#include
-#include
+//#include
#include
-#include
#include "ui_MainWindow.h"
@@ -25,7 +24,9 @@ MainWindow::MainWindow(ComManager *com_manager, const QString ¤t_server, Q
m_diag_editor = nullptr;
m_data_editor = nullptr;
m_dashboard = nullptr;
+#ifndef OPENTERA_WEBASSEMBLY
m_inSessionWidget = nullptr;
+#endif
m_download_dialog = nullptr;
m_joinSession_dialog = nullptr;
m_currentLanguage = m_comManager->getCurrentPreferences().getLanguage();
@@ -64,7 +65,11 @@ MainWindow::~MainWindow()
bool MainWindow::isInSession()
{
+#ifndef OPENTERA_WEBASSEMBLY
return m_inSessionWidget != nullptr;
+#else
+ return false;
+#endif
}
void MainWindow::connectSignals()
@@ -92,6 +97,7 @@ void MainWindow::connectSignals()
connect(m_comManager->getWebSocketManager(), &WebSocketManager::userEventReceived, this, &MainWindow::ws_userEvent);
connect(m_comManager->getWebSocketManager(), &WebSocketManager::participantEventReceived, this, &MainWindow::ws_participantEvent);
+ connect(m_comManager->getWebSocketManager(), &WebSocketManager::deviceEventReceived, this, &MainWindow::ws_deviceEvent);
connect(m_comManager->getWebSocketManager(), &WebSocketManager::joinSessionEventReceived, this, &MainWindow::ws_joinSessionEvent);
connect(ui->projNavigator, &ProjectNavigator::dataDisplayRequest, this, &MainWindow::dataDisplayRequested);
@@ -110,6 +116,7 @@ void MainWindow::connectSignals()
void MainWindow::initUi()
{
ui->btnConfig->hide();
+ ui->lblVersion->hide();
// Setup messages
ui->wdgMessages->hide();
@@ -159,6 +166,7 @@ void MainWindow::showDataEditor(const TeraDataTypes &data_type, const TeraData*d
showDashboard(false);
+
// Save values to display them again if needed
m_currentDataType = data_type;
m_currentDataId = data->getId();
@@ -253,7 +261,7 @@ void MainWindow::showDashboard(const bool &show)
}
}
-
+#ifndef OPENTERA_WEBASSEMBLY
void MainWindow::setInSession(bool in_session, const TeraData *session_type, const int &id_session, int id_project)
{
if (!in_session && !isInSession())
@@ -288,16 +296,21 @@ void MainWindow::setInSession(bool in_session, const TeraData *session_type, con
if (in_session){
if (id_project == 0)
id_project = ui->projNavigator->getCurrentProjectId();
- m_inSessionWidget = new InSessionWidget(m_comManager, session_type, id_session, id_project);
+ m_inSessionWidget = new InSessionWidget(m_comManager, session_type, id_session, id_project, nullptr, this);
connect(m_inSessionWidget, &InSessionWidget::sessionEndedWithError, this, &MainWindow::inSession_sessionEndedWithError);
connect(m_inSessionWidget, &InSessionWidget::requestShowNotification, this, &MainWindow::addNotification);
ui->wdgMainTop->layout()->addWidget(m_inSessionWidget);
+ ui->btnEditUser->hide();
}else{
// Loads back the "previous" data type
dataDisplayRequested(m_currentDataType, m_currentDataId);
+ ui->btnEditUser->show();
}
-}
+ // Refresh user information - hiding config button at the same time
+ updateCurrentUser();
+}
+#endif
QIcon MainWindow::getGlobalEventIcon(GlobalEvent &global_event)
{
switch(global_event.getEventType()){
@@ -413,6 +426,7 @@ void MainWindow::editorDialogFinished()
ui->projNavigator->setOnHold(false);
}
+#ifndef OPENTERA_WEBASSEMBLY
void MainWindow::joinSessionDialogFinished()
{
if (m_joinSession_dialog->result() == JoinSessionDialog::Accepted){
@@ -443,6 +457,7 @@ void MainWindow::joinSessionDialogFinished()
m_joinSession_dialog->deleteLater();
m_joinSession_dialog = nullptr;
}
+#endif
void MainWindow::dataDisplayRequested(TeraDataTypes data_type, int data_id)
{
@@ -499,8 +514,12 @@ void MainWindow::dataDisplayRequested(TeraDataTypes data_type, int data_id)
void MainWindow::dataDisplayRequestedByUuid(TeraDataTypes data_type, QString data_uuid)
{
// Try to select in project navigator
- if (data_type == TERADATA_PROJECT || data_type == TERADATA_PARTICIPANT || data_type == TERADATA_GROUP)
- ui->projNavigator->selectItemByUuid(data_type, data_uuid);
+ if (data_type == TERADATA_PROJECT || data_type == TERADATA_PARTICIPANT || data_type == TERADATA_GROUP){
+ if (ui->projNavigator->selectItemByUuid(data_type, data_uuid)){
+ // Selected in the project navigator - will do its query from there!
+ return;
+ }
+ }
// Request to display a specific item by uuid.
QUrlQuery query;
@@ -543,7 +562,7 @@ void MainWindow::updateCurrentUser()
if (m_comManager->getCurrentUser().hasFieldName("user_name")){
// Ok, we have a user to update.
ui->lblUser->setText(m_comManager->getCurrentUser().getName());
- ui->btnConfig->setVisible(m_comManager->getCurrentUser().getFieldValue("user_superadmin").toBool());
+ ui->btnConfig->setVisible(m_comManager->getCurrentUser().getFieldValue("user_superadmin").toBool() && !isInSession());
}
}
@@ -722,6 +741,7 @@ void MainWindow::com_preferencesUpdated()
void MainWindow::com_sessionStarted(TeraData session_type, int id_session)
{
+#ifndef OPENTERA_WEBASSEMBLY
if (!m_inSessionWidget){
// Loads the in-session widget since none loaded yet!
setInSession(true, &session_type, id_session);
@@ -729,29 +749,35 @@ void MainWindow::com_sessionStarted(TeraData session_type, int id_session)
// Update session id in InSessionWidget
m_inSessionWidget->setSessionId(id_session);
}
+#endif
}
void MainWindow::com_sessionStartRequested(TeraData session_type)
{
+#ifndef OPENTERA_WEBASSEMBLY
// Loads the in-session widget
setInSession(true, &session_type, -1);
+#endif
}
void MainWindow::com_sessionStopped(int id_session)
{
+#ifndef OPENTERA_WEBASSEMBLY
setInSession(false, nullptr, id_session);
+#endif
}
void MainWindow::com_sessionError(QString error)
{
+#ifndef OPENTERA_WEBASSEMBLY
setInSession(false, nullptr, -1);
+#endif
GlobalMessageBox msg;
msg.showError(tr("Erreur de séance"), tr("Une erreur est survenue:\n") + error + tr("\n\nLa séance ne peut pas continuer."));
}
void MainWindow::ws_userEvent(UserEvent event)
{
-
if (event.type() == UserEvent_EventType_USER_CONNECTED){
// Don't do anything for current user!
if (event.user_uuid() == m_comManager->getCurrentUser().getUuid().toStdString())
@@ -762,9 +788,6 @@ void MainWindow::ws_userEvent(UserEvent event)
// Add a trace in events also
GlobalEvent g_event(EVENT_LOGIN, msg_text);
addGlobalEvent(g_event);
-
- // Update online users list
- //updateOnlineUser(QString::fromStdString(event.user_uuid()), true, QString::fromStdString(event.user_fullname()));
}
if (event.type() == UserEvent_EventType_USER_DISCONNECTED){
@@ -773,9 +796,6 @@ void MainWindow::ws_userEvent(UserEvent event)
GlobalEvent g_event(EVENT_LOGOUT, msg_text);
addGlobalEvent(g_event);
-
- // Update online users list
- //updateOnlineUser(QString::fromStdString(event.user_uuid()), false);
}
}
@@ -790,9 +810,6 @@ void MainWindow::ws_participantEvent(ParticipantEvent event)
// Add a trace in events also
GlobalEvent g_event(EVENT_LOGIN, msg_text);
addGlobalEvent(g_event);
-
- // Update online users list
- //updateOnlineParticipant(QString::fromStdString(event.participant_uuid()), true, QString::fromStdString(event.participant_name()));
}
}
@@ -805,15 +822,33 @@ void MainWindow::ws_participantEvent(ParticipantEvent event)
// Add a trace in events also
GlobalEvent g_event(EVENT_LOGOUT, msg_text);
addGlobalEvent(g_event);
-
- // Update online participants list
- //updateOnlineParticipant(QString::fromStdString(event.participant_uuid()), false);
}
}
}
+void MainWindow::ws_deviceEvent(DeviceEvent event)
+{
+ if (event.type() == opentera::protobuf::DeviceEvent_EventType_DEVICE_CONNECTED){
+ QString msg_text = "" + QString::fromStdString(event.device_name()) + "" + tr(" est en ligne.");
+ addNotification(NotificationWindow::TYPE_MESSAGE, msg_text, "://icons/device_online.png", "://sounds/notify_online.wav");
+
+ // Add a trace in events also
+ GlobalEvent g_event(EVENT_LOGIN, msg_text);
+ addGlobalEvent(g_event);
+ }
+
+ if (event.type() == opentera::protobuf::DeviceEvent_EventType_DEVICE_DISCONNECTED){
+ QString msg_text = "" + QString::fromStdString(event.device_name()) + "" + tr(" est hors-ligne.");
+ addNotification(NotificationWindow::TYPE_MESSAGE, msg_text, "://icons/device_offline.png", "://sounds/notify_offline.wav");
+
+ GlobalEvent g_event(EVENT_LOGOUT, msg_text);
+ addGlobalEvent(g_event);
+ }
+}
+
void MainWindow::ws_joinSessionEvent(JoinSessionEvent event)
{
+#ifndef OPENTERA_WEBASSEMBLY
if (isInSession()){
// If we are in a session, the InSession Widget will handle that event for us.
return;
@@ -837,6 +872,7 @@ void MainWindow::ws_joinSessionEvent(JoinSessionEvent event)
return;
}
}
+#endif
}
void MainWindow::inSession_sessionEndedWithError()
@@ -897,8 +933,11 @@ void MainWindow::addNotification(const NotificationWindow::NotificationType noti
connect(notify, &NotificationWindow::notificationClosed, this, &MainWindow::notificationCompleted);
if (m_comManager->getCurrentPreferences().isNotifySounds() && !soundPath.isEmpty()){
- if (!m_inSessionWidget) // Don't play sounds when in session!
- QSound::play(soundPath);
+ if (!isInSession()) {// Don't play sounds when in session!
+ m_soundPlayer.setSource(QUrl::fromLocalFile(soundPath));
+ m_soundPlayer.setVolume(0.25f);
+ m_soundPlayer.play();
+ }
}
}
@@ -1008,6 +1047,7 @@ void MainWindow::changeEvent(QEvent* event)
void MainWindow::closeEvent(QCloseEvent *event)
{
// About to close... check if we have something in progress that prevents it
+#ifndef OPENTERA_WEBASSEMBLY
if (m_inSessionWidget){
if (!m_inSessionWidget->sessionCanBeEnded()){
GlobalMessageBox msg;
@@ -1016,16 +1056,17 @@ void MainWindow::closeEvent(QCloseEvent *event)
return;
}
}
+#endif
event->accept();
}
void MainWindow::on_lblLogo_clicked()
{
- AboutDialog about(m_comManager->getServerUrl(), this);
-
+#ifndef OPENTERA_WEBASSEMBLY
+ AboutDialog about(m_comManager->getServerUrl());
about.setFixedSize(size().width()-50, size().height()-150);
- about.move(this->x()+25, this->y()+75);
-
+ //about.move(this->x()+25, this->y()+75);
about.exec();
+#endif
}
diff --git a/client/src/main/MainWindow.h b/client/src/main/MainWindow.h
index 60c26913..f6e3543d 100644
--- a/client/src/main/MainWindow.h
+++ b/client/src/main/MainWindow.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include "editors/UserWidget.h"
#include "dialogs/BaseDialog.h"
@@ -20,10 +21,16 @@
#include "data/GlobalEvent.h"
#include "data/DownloadingFile.h"
#include "TeraSessionCategory.h"
+
+#ifndef OPENTERA_WEBASSEMBLY
#include "widgets/InSessionWidget.h"
+#endif
+
#include "dialogs/JoinSessionDialog.h"
+#ifndef OPENTERA_WEBASSEMBLY
#include "dialogs/AboutDialog.h"
+#endif
// Protobuf
#include "UserEvent.pb.h"
@@ -50,6 +57,7 @@ class MainWindow : public QMainWindow
public slots:
void ws_userEvent(opentera::protobuf::UserEvent event);
void ws_participantEvent(opentera::protobuf::ParticipantEvent event);
+ void ws_deviceEvent(opentera::protobuf::DeviceEvent event);
void ws_joinSessionEvent(opentera::protobuf::JoinSessionEvent event);
private slots:
@@ -88,7 +96,10 @@ private slots:
void addGlobalEvent(GlobalEvent event);
void editorDialogFinished();
+#ifndef OPENTERA_WEBASSEMBLY
void joinSessionDialogFinished();
+#endif
+
void dataDisplayRequested(TeraDataTypes data_type, int data_id);
void dataDisplayRequestedByUuid(TeraDataTypes data_type, QString data_uuid);
void dataDeleteRequested(TeraDataTypes data_type, int data_id);
@@ -99,9 +110,7 @@ private slots:
void on_btnConfig_clicked();
void on_btnLog_toggled(bool checked);
-
void on_tableHistory_itemDoubleClicked(QTableWidgetItem *item);
-
void on_lblLogo_clicked();
private:
@@ -109,8 +118,9 @@ private slots:
void initUi();
void showDataEditor(const TeraDataTypes &data_type, const TeraData *data);
void showDashboard(const bool &show);
+#ifndef OPENTERA_WEBASSEMBLY
void setInSession(bool in_session, const TeraData *session_type, const int& id_session, int id_project=0);
-
+#endif
// Messages and notifications
void addMessage(Message::MessageType msg_type, QString msg);
void addMessage(Message &msg);
@@ -126,7 +136,9 @@ private slots:
BaseDialog* m_diag_editor;
DataEditorWidget* m_data_editor;
DashboardWidget* m_dashboard;
+#ifndef OPENTERA_WEBASSEMBLY
InSessionWidget* m_inSessionWidget;
+#endif
TransferProgressDialog* m_download_dialog;
JoinSessionDialog* m_joinSession_dialog;
TeraDataTypes m_waiting_for_data_type;
@@ -135,6 +147,7 @@ private slots:
// Message & notification system
QList m_notifications;
+ QSoundEffect m_soundPlayer;
// UI items
QMovie* m_loadingIcon;
diff --git a/client/src/main/MainWindow.ui b/client/src/main/MainWindow.ui
index 347c8468..088328da 100644
--- a/client/src/main/MainWindow.ui
+++ b/client/src/main/MainWindow.ui
@@ -6,8 +6,8 @@
0
0
- 1689
- 897
+ 950
+ 514
@@ -40,8 +40,8 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
0
0
- 1069
- 759
+ 330
+ 376
@@ -139,7 +139,7 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
- 409
+ 595
50
@@ -210,18 +210,78 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
-
-
+
+
+
+ 0
+ 0
+
+
0
32
+
+
+ 100
+ 16777215
+
+
+
+ PointingHandCursor
+
- 0.1
+ Profil
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ :/icons/software_user.png:/icons/software_user.png
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 32
+
+
+
+
+ 100
+ 16777215
+
+
+
+ PointingHandCursor
+
+
+ Admin
+
+
+
+ :/icons/config.png:/icons/config.png
+
+
+
+ 20
+ 20
+
@@ -362,6 +422,22 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
+ -
+
+
+
+ 0
+ 32
+
+
+
+ 0.1
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
@@ -377,99 +453,6 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 0
- 32
-
-
-
-
- 100
- 16777215
-
-
-
- PointingHandCursor
-
-
- Profil
-
-
-
- :/icons/software_user.png:/icons/software_user.png
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 32
-
-
-
-
- 100
- 16777215
-
-
-
- PointingHandCursor
-
-
- Admin
-
-
-
- :/icons/config.png:/icons/config.png
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
@@ -509,14 +492,14 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
- :/icons/project.png:/icons/project.png
+ :/icons/details.png:/icons/details.png
Navigateur
- 4
+ 1
4
@@ -546,6 +529,12 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
0
+
+
+ 0
+ 200
+
+
:/status/status_ok.png:/status/status_ok.png
@@ -558,7 +547,7 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
QLayout::SetMinAndMaxSize
- 4
+ 0
4
@@ -758,7 +747,7 @@ QLabel#lblLogo, QLabel#lblVersion, QLabel#lblUser{background-color:transparent;}
0
0
- 1689
+ 950
21
diff --git a/client/src/managers/AssetComManager.cpp b/client/src/managers/AssetComManager.cpp
index 982b7356..46f2ccbe 100644
--- a/client/src/managers/AssetComManager.cpp
+++ b/client/src/managers/AssetComManager.cpp
@@ -86,7 +86,7 @@ bool AssetComManager::handleDataReply(const QString &reply_path, const QString &
QList items;
if (data_list.isArray()){
QJsonArray data_list_array = data_list.array();
- for (const QJsonValue &data:qAsConst(data_list_array)){
+ for (const QJsonValue &data:std::as_const(data_list_array)){
items.append(data.toObject());
}
}else{
diff --git a/client/src/managers/BaseComManager.cpp b/client/src/managers/BaseComManager.cpp
index c6176f8a..38f34582 100644
--- a/client/src/managers/BaseComManager.cpp
+++ b/client/src/managers/BaseComManager.cpp
@@ -23,8 +23,10 @@ BaseComManager::BaseComManager(QUrl serverUrl, QObject *parent)
// Connect base signals
connect(m_netManager, &QNetworkAccessManager::finished, this, &BaseComManager::onNetworkFinished);
+#ifndef OPENTERA_WEBASSEMBLY
connect(m_netManager, &QNetworkAccessManager::sslErrors, this, &BaseComManager::onNetworkSslErrors);
connect(m_netManager, &QNetworkAccessManager::encrypted, this, &BaseComManager::onNetworkEncrypted);
+#endif
connect(m_netManager, &QNetworkAccessManager::authenticationRequired, this, &BaseComManager::onNetworkAuthenticationRequired);
}
@@ -256,7 +258,7 @@ bool BaseComManager::hasDownloadsWaiting()
void BaseComManager::updateWaitingDownloadsQueryParameter(const QString ¶meter, const QString &new_value)
{
- for(DownloadingFile* file: qAsConst(m_waitingDownloads)){
+ for(DownloadingFile* file: std::as_const(m_waitingDownloads)){
QNetworkRequest* request = m_waitingDownloads.key(file);
QUrlQuery query(request->url());
if (query.hasQueryItem(parameter)){
@@ -271,7 +273,7 @@ void BaseComManager::updateWaitingDownloadsQueryParameter(const QString ¶met
void BaseComManager::updateWaitingDownloadsQueryParameter(const QString &download_uuid, const QString ¶meter, const QString &new_value)
{
- for(DownloadingFile* file: qAsConst(m_waitingDownloads)){
+ for(DownloadingFile* file: std::as_const(m_waitingDownloads)){
if (file->getAssociatedUuid() == download_uuid){
QNetworkRequest* request = m_waitingDownloads.key(file);
QUrlQuery query(request->url());
@@ -288,28 +290,28 @@ void BaseComManager::updateWaitingDownloadsQueryParameter(const QString &downloa
void BaseComManager::abortDownloads()
{
- for(DownloadingFile* file:qAsConst(m_waitingDownloads)){
+ for(DownloadingFile* file:std::as_const(m_waitingDownloads)){
delete m_waitingDownloads.key(file);
file->deleteLater();
}
m_waitingDownloads.clear();
QList files = m_currentDownloads.values();
- for(DownloadingFile* file:qAsConst(files)){
+ for(DownloadingFile* file:std::as_const(files)){
file->abortTransfer(); // Should cascade and be deleted on_Transfer_abort
}
}
void BaseComManager::abortUploads()
{
- for(UploadingFile* file:qAsConst(m_waitingUploads)){
+ for(UploadingFile* file:std::as_const(m_waitingUploads)){
delete m_waitingUploads.key(file);
file->deleteLater();
}
m_waitingUploads.clear();
QList files = m_currentUploads.values();
- for(UploadingFile* file:qAsConst(files)){
+ for(UploadingFile* file:std::as_const(files)){
file->abortTransfer(); // Should cascade and be deleted on_Transfer_abort
}
}
@@ -367,13 +369,14 @@ void BaseComManager::onNetworkFinished(QNetworkReply *reply){
m_currentDownloads[reply]->abortTransfer();
}
- emit networkError(reply->error(), reply_msg, reply->operation(), status_code);
+ emit networkError(reply->error(), reply_msg, reply->operation(), status_code, reply->url().path(), QUrlQuery(reply->url().query()));
}
reply->deleteLater();
}
+#ifndef OPENTERA_WEBASSEMBLY
void BaseComManager::onNetworkSslErrors(QNetworkReply *reply, const QList &errors){
Q_UNUSED(reply)
Q_UNUSED(errors)
@@ -389,6 +392,8 @@ void BaseComManager::onNetworkEncrypted(QNetworkReply *reply){
Q_UNUSED(reply)
//qDebug() << QString(this->metaObject()->className()) + "::onNetworkEncrypted";
}
+#endif
+
void BaseComManager::onNetworkAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
{
diff --git a/client/src/managers/BaseComManager.h b/client/src/managers/BaseComManager.h
index 4a834521..568bfa7f 100644
--- a/client/src/managers/BaseComManager.h
+++ b/client/src/managers/BaseComManager.h
@@ -91,8 +91,12 @@ class BaseComManager : public QObject
protected slots:
virtual void onNetworkFinished(QNetworkReply *reply);
+
+#ifndef OPENTERA_WEBASSEMBLY
virtual void onNetworkSslErrors(QNetworkReply *reply, const QList &errors);
void onNetworkEncrypted(QNetworkReply *reply);
+#endif
+
void onNetworkAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
void onTransferProgress(TransferringFile* file);
@@ -101,7 +105,7 @@ protected slots:
signals:
void waitingForReply(bool waiting);
- void networkError(QNetworkReply::NetworkError, QString, QNetworkAccessManager::Operation op, int status_code);
+ void networkError(QNetworkReply::NetworkError error, QString error_str, QNetworkAccessManager::Operation op, int status_code, QString path, QUrlQuery url_query);
void networkAuthFailed();
diff --git a/client/src/managers/ComManager.cpp b/client/src/managers/ComManager.cpp
index 9f6df7be..8bf996f6 100644
--- a/client/src/managers/ComManager.cpp
+++ b/client/src/managers/ComManager.cpp
@@ -574,7 +574,7 @@ bool ComManager::handleDataReply(const QString& reply_path, const QString &reply
TeraDataTypes items_type = TeraData::getDataTypeFromPath(reply_path);
if (data_list.isArray()){
const QJsonArray data_array = data_list.array();
- for (const QJsonValue &data:data_array){
+ for (const QJsonValue data:data_array){
TeraData item_data(items_type, data);
// Check if the currently connected user was updated and not requesting a list (limited information)
@@ -697,6 +697,9 @@ bool ComManager::handleDataReply(const QString& reply_path, const QString &reply
case TERADATA_SERVICE_CONFIG:
emit servicesConfigReceived(items, reply_query);
break;
+ case TERADATA_SERVICE_ROLE:
+ emit servicesRolesReceived(items, reply_query);
+ break;
case TERADATA_STATS:
if (items.count() > 0)
emit statsReceived(items.first(), reply_query);
diff --git a/client/src/managers/ComManager.h b/client/src/managers/ComManager.h
index 8ed42270..d7184f67 100644
--- a/client/src/managers/ComManager.h
+++ b/client/src/managers/ComManager.h
@@ -7,7 +7,11 @@
#include
#include
#include
+
+#ifndef OPENTERA_WEBASSEMBLY
#include
+#endif
+
#include
#include
@@ -143,6 +147,7 @@ class ComManager : public BaseComManager
void servicesSitesReceived(QList sites_list, QUrlQuery reply_query);
void servicesAccessReceived(QList access_list, QUrlQuery reply_query);
void servicesConfigReceived(QList config_list, QUrlQuery reply_query);
+ void servicesRolesReceived(QList roles_list, QUrlQuery reply_query);
void statsReceived(TeraData stats, QUrlQuery reply_query);
void onlineUsersReceived(QList users_list, QUrlQuery reply_query);
void onlineParticipantsReceived(QList participants_list, QUrlQuery reply_query);
diff --git a/client/src/managers/ParticipantComManager.h b/client/src/managers/ParticipantComManager.h
index ee1f05b6..59f8da51 100644
--- a/client/src/managers/ParticipantComManager.h
+++ b/client/src/managers/ParticipantComManager.h
@@ -7,7 +7,9 @@
#include
#include
#include
-#include
+#ifndef OPENTERA_WEBASSEMBLY
+ #include
+#endif
#include
#include
diff --git a/client/src/managers/WebSocketManager.cpp b/client/src/managers/WebSocketManager.cpp
index c4c1305f..5b4839c9 100644
--- a/client/src/managers/WebSocketManager.cpp
+++ b/client/src/managers/WebSocketManager.cpp
@@ -18,7 +18,9 @@ WebSocketManager::WebSocketManager(QObject *parent) : QObject(parent)
connect(m_webSocket, &QWebSocket::connected, this, &WebSocketManager::onSocketConnected);
connect(m_webSocket, &QWebSocket::disconnected, this, &WebSocketManager::onSocketDisconnected);
connect(m_webSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
+#ifndef OPENTERA_WEBASSEMBLY
connect(m_webSocket, &QWebSocket::sslErrors, this, &WebSocketManager::onSocketSslErrors);
+#endif
connect(m_webSocket, &QWebSocket::textMessageReceived, this, &WebSocketManager::onSocketTextMessageReceived);
connect(m_webSocket, &QWebSocket::binaryMessageReceived, this, &WebSocketManager::onSocketBinaryMessageReceived);
@@ -136,6 +138,7 @@ void WebSocketManager::onSocketDisconnected()
emit serverDisconnected();
}
+#ifndef OPENTERA_WEBASSEMBLY
void WebSocketManager::onSocketSslErrors(const QList &errors)
{
Q_UNUSED(errors)
@@ -146,6 +149,7 @@ void WebSocketManager::onSocketSslErrors(const QList &errors)
qDebug() << "WebSocketManager::SSlErrors " << errors;
m_webSocket->ignoreSslErrors();
}
+#endif
void WebSocketManager::onSocketTextMessageReceived(const QString &message)
{
@@ -253,7 +257,6 @@ void WebSocketManager::onSocketTextMessageReceived(const QString &message)
}else{
LOG_ERROR("Unable to decode received protobuf message", "WebSocketManager::onSocketTextMessageReceived");
}
-
}
void WebSocketManager::onSocketBinaryMessageReceived(const QByteArray &message)
diff --git a/client/src/managers/WebSocketManager.h b/client/src/managers/WebSocketManager.h
index 94a616b0..5bd5d0a2 100644
--- a/client/src/managers/WebSocketManager.h
+++ b/client/src/managers/WebSocketManager.h
@@ -8,6 +8,7 @@
#include "Logger.h"
// Protobuf includes
+
#include "UserRegisterToEvent.pb.h"
#include "UserEvent.pb.h"
#include "DeviceEvent.pb.h"
@@ -20,18 +21,18 @@
#include "TeraMessage.pb.h"
#include "TeraModuleMessage.pb.h"
#include "DatabaseEvent.pb.h"
-
#include "google/protobuf/any.h"
#include "google/protobuf/util/json_util.h"
using namespace opentera::protobuf;
+
class WebSocketManager : public QObject
{
Q_OBJECT
public:
explicit WebSocketManager(QObject *parent = nullptr);
- ~WebSocketManager();
+ ~WebSocketManager() override;
void connectWebSocket(QString &socketUrl, QString &user_uuid);
void disconnectWebSocket();
@@ -57,7 +58,6 @@ class WebSocketManager : public QObject
void serverDisconnected();
void websocketError(QAbstractSocket::SocketError, QString);
void loginResult(bool logged_in);
-
void userEventReceived(UserEvent event);
void participantEventReceived(ParticipantEvent event);
void deviceEventReceived(DeviceEvent event);
@@ -66,7 +66,6 @@ class WebSocketManager : public QObject
void stopSessionEventReceived(StopSessionEvent event);
void databaseEventReceived(DatabaseEvent event);
void joinSessionReplyEventReceived(JoinSessionReplyEvent event);
-
void genericEventReceived(TeraEvent event);
@@ -74,7 +73,10 @@ private slots:
void onSocketConnected();
void onSocketDisconnected();
void onSocketError(QAbstractSocket::SocketError error);
+
+#ifndef OPENTERA_WEBASSEMBLY
void onSocketSslErrors(const QList &errors);
+#endif
void onSocketTextMessageReceived(const QString &message);
void onSocketBinaryMessageReceived(const QByteArray &message);
diff --git a/client/src/services/DanceService/DanceComManager.cpp b/client/src/services/DanceService/DanceComManager.cpp
index 56fe07e8..53075c29 100644
--- a/client/src/services/DanceService/DanceComManager.cpp
+++ b/client/src/services/DanceService/DanceComManager.cpp
@@ -77,7 +77,7 @@ bool DanceComManager::handleDataReply(const QString &reply_path, const QString &
QList items;
if (data_list.isArray()){
QJsonArray data_list_array = data_list.array();
- for (const QJsonValue &data:qAsConst(data_list_array)){
+ for (const QJsonValue &data:std::as_const(data_list_array)){
items.append(data.toObject());
}
}else{
diff --git a/client/src/services/DanceService/DanceConfigWidget.cpp b/client/src/services/DanceService/DanceConfigWidget.cpp
index 5df89186..d20869e6 100644
--- a/client/src/services/DanceService/DanceConfigWidget.cpp
+++ b/client/src/services/DanceService/DanceConfigWidget.cpp
@@ -75,7 +75,7 @@ void DanceConfigWidget::on_btnUpload_clicked()
void DanceConfigWidget::processVideosReply(QList videos)
{
- for (const QJsonObject &video:qAsConst(videos)){
+ for (const QJsonObject &video:std::as_const(videos)){
updateVideoInLibrary(video);
updateVideoInPlaylist(video);
}
@@ -107,7 +107,7 @@ void DanceConfigWidget::processPlaylistReply(QList playlists)
m_playlistIds.clear();
checkDirty();
- for (const QJsonObject &playlist:qAsConst(playlists)){
+ for (const QJsonObject &playlist:std::as_const(playlists)){
int id_video = playlist["id_video"].toInt();
m_playlistIds.append(id_video);
// Find video in available list
@@ -661,7 +661,7 @@ void DanceConfigWidget::on_btnCancel_clicked()
ui->lstPlaylist->clearContents();
ui->lstPlaylist->setRowCount(0);
- for (const int& id:qAsConst(m_playlistIds)){
+ for (const int& id:std::as_const(m_playlistIds)){
// Find video in available
for(int i=0; ilstAvailVideos->count(); i++){
if (ui->lstAvailVideos->item(i)->data(Qt::UserRole).toInt() == id){
diff --git a/client/src/services/VideoRehabService/VideoRehabSetupWidget.cpp b/client/src/services/VideoRehabService/VideoRehabSetupWidget.cpp
index cc9fd6c9..b380e992 100644
--- a/client/src/services/VideoRehabService/VideoRehabSetupWidget.cpp
+++ b/client/src/services/VideoRehabService/VideoRehabSetupWidget.cpp
@@ -36,6 +36,7 @@ VideoRehabSetupWidget::~VideoRehabSetupWidget()
m_virtualCamThread->wait();
m_virtualCamThread->deleteLater();
}
+
}
QJsonDocument VideoRehabSetupWidget::getSetupConfig()
@@ -46,6 +47,7 @@ QJsonDocument VideoRehabSetupWidget::getSetupConfig()
void VideoRehabSetupWidget::initUI()
{
ui->frameError->hide();
+ ui->widgetSetup->setComManager(m_comManager);
//// Web engine setup
m_webEngine = new QWebEngineView(ui->wdgWebEngine);
@@ -75,8 +77,8 @@ void VideoRehabSetupWidget::initUI()
m_webEngine->setSizePolicy(sizePolicy);
ui->wdgWebEngine->layout()->addWidget(m_webEngine);
- // Wait for service configuration before setting url
- //m_webEngine->setUrl(QUrl("qrc:/VideoRehabService/html/index.html"));
+ // Load url - will set correct camera when service config form will be loaded
+ m_webEngine->setUrl(QUrl("qrc:/VideoRehabService/html/index.html"));
// Hide PTZ fields in setup widget
//ui->widgetSetup->hideFields(QStringList() << "camera_ptz_type" << "camera_ptz_ip" << "camera_ptz_port" << "camera_ptz_username" << "camera_ptz_password");
@@ -186,7 +188,6 @@ void VideoRehabSetupWidget::startPTZCamera()
return;
}
-
showError(tr("Caméra PTZ"), "VideoRehabSetupWidget::startPTZCamera", tr("Type de caméra PTZ non-supporté"), true);
}
@@ -211,8 +212,9 @@ void VideoRehabSetupWidget::refreshWebpageSettings()
bool ptz = ui->widgetSetup->getFieldValue("camera_ptz").toBool();
m_webPage->getSharedObject()->setPTZCapabilities(ptz, ptz, ptz);
m_webPage->getSharedObject()->sendPTZCapabilities();
- if (ptz)
+ if (ptz) {
startPTZCamera();
+ }
// Update video source
QString video_src = ui->widgetSetup->getFieldValue("camera").toString();
@@ -306,7 +308,7 @@ void VideoRehabSetupWidget::processServiceConfigsReply(QList configs,
m_webPage->getSharedObject()->setCurrentCameraName(ui->widgetSetup->getFieldValue("camera").toString());
// Load page
- m_webEngine->setUrl(QUrl("qrc:/VideoRehabService/html/index.html"));
+ //m_webEngine->setUrl(QUrl("qrc:/VideoRehabService/html/index.html"));
}
}
@@ -403,8 +405,12 @@ void VideoRehabSetupWidget::setupFormValueChanged(QWidget *wdg, QVariant value)
startVirtualCamera(src);
}
}else{
+ /*
if (m_virtualCamThread)
+ {
stopVirtualCamera();
+ }
+ */
}
}
@@ -445,7 +451,6 @@ void VideoRehabSetupWidget::ptzCameraError(CameraInfo infos)
break;
case CameraInfo::CIE_NO_ERROR:
// Shouldn't get here, but managed in case
- return;
break;
}
diff --git a/client/src/services/VideoRehabService/VideoRehabSetupWidget.h b/client/src/services/VideoRehabService/VideoRehabSetupWidget.h
index ef6abb34..98c7910b 100644
--- a/client/src/services/VideoRehabService/VideoRehabSetupWidget.h
+++ b/client/src/services/VideoRehabService/VideoRehabSetupWidget.h
@@ -7,8 +7,9 @@
#include
#include
-#include
-#include
+#include
+#include
+#include
#include "services/BaseServiceSetupWidget.h"
diff --git a/client/src/services/VideoRehabService/VideoRehabWebPage.cpp b/client/src/services/VideoRehabService/VideoRehabWebPage.cpp
index 9ede835d..9dc06859 100644
--- a/client/src/services/VideoRehabService/VideoRehabWebPage.cpp
+++ b/client/src/services/VideoRehabService/VideoRehabWebPage.cpp
@@ -1,8 +1,18 @@
#include "VideoRehabWebPage.h"
#include "Logger.h"
+#include
VideoRehabWebPage::VideoRehabWebPage(QObject *parent): QWebEnginePage(parent)
{
+ //Set page Settings
+ auto settings = this->settings();
+ settings->setAttribute(QWebEngineSettings::PluginsEnabled, true);
+ settings->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
+ settings->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
+ settings->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
+ settings->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, false);
+
+
// Create shared object for communication with webpage
m_sharedObject = new SharedObject(this);
@@ -19,6 +29,7 @@ VideoRehabWebPage::VideoRehabWebPage(QObject *parent): QWebEnginePage(parent)
// Connect signals
connect(m_clientWrapper, &WebSocketClientWrapper::clientConnected, m_webChannel, &QWebChannel::connectTo); // Transport will be automatically connected
connect(this, &VideoRehabWebPage::featurePermissionRequested, this, &VideoRehabWebPage::featurePermissionHandler);
+ connect(this,&QWebEnginePage::certificateError, this, &VideoRehabWebPage::onCertificateError);
m_webChannel->registerObject(QStringLiteral("SharedObject"), m_sharedObject);
}
@@ -34,26 +45,22 @@ SharedObject *VideoRehabWebPage::getSharedObject() const
return m_sharedObject;
}
-bool VideoRehabWebPage::certificateError(const QWebEngineCertificateError &certificateError)
+void VideoRehabWebPage::onCertificateError(const QWebEngineCertificateError &certificateError)
{
-//#ifdef QT_DEBUG
-
- qDebug() << "Certificate error: " << certificateError.errorDescription();
- /*
- The certificateError parameter contains information about the certificate and details of the error.
- Return true to ignore the error and complete the request. Return false to stop loading the request.
- */
-
- return true; // Accept all certificates in debug
-/*#else
- // Refuse invalid certificates
- return false;
-#endif*/
+
+ //TODO do Something about certificates
+ qDebug() << "Certificate error: " << certificateError.description();
+
+ //TODO Do not accept certificates in production ?
+ auto mutableError = const_cast(certificateError);
+ mutableError.acceptCertificate();
+
}
void VideoRehabWebPage::featurePermissionHandler(const QUrl &securityOrigin, QWebEnginePage::Feature feature)
{
// TODO: Only allow specific features like webcam, micro, screenshare?
+ qDebug() << securityOrigin << " requesting: " << feature;
//Grant all features!
this->setFeaturePermission(securityOrigin,feature,QWebEnginePage::PermissionGrantedByUser);
diff --git a/client/src/services/VideoRehabService/VideoRehabWebPage.h b/client/src/services/VideoRehabService/VideoRehabWebPage.h
index 6454401f..d36c5224 100644
--- a/client/src/services/VideoRehabService/VideoRehabWebPage.h
+++ b/client/src/services/VideoRehabService/VideoRehabWebPage.h
@@ -16,15 +16,16 @@ class VideoRehabWebPage : public QWebEnginePage
Q_OBJECT
public:
VideoRehabWebPage(QObject *parent = nullptr);
- ~VideoRehabWebPage();
+ ~VideoRehabWebPage() override;
SharedObject* getSharedObject() const;
protected:
- virtual bool certificateError(const QWebEngineCertificateError &certificateError) override;
+
private slots:
void featurePermissionHandler(const QUrl &securityOrigin, QWebEnginePage::Feature feature);
+ void onCertificateError(const QWebEngineCertificateError &certificateError);
private:
SharedObject *m_sharedObject; // Shared object for communication with page itself
diff --git a/client/src/services/VideoRehabService/VideoRehabWidget.cpp b/client/src/services/VideoRehabService/VideoRehabWidget.cpp
index 537532e5..94fe7767 100644
--- a/client/src/services/VideoRehabService/VideoRehabWidget.cpp
+++ b/client/src/services/VideoRehabService/VideoRehabWidget.cpp
@@ -19,8 +19,6 @@ VideoRehabWidget::VideoRehabWidget(ComManager *comMan, QWidget *parent) :
connectSignals();
emit widgetIsReady(false); // We wait until webpage is fully loaded...
-
-
}
VideoRehabWidget::~VideoRehabWidget()
@@ -29,6 +27,7 @@ VideoRehabWidget::~VideoRehabWidget()
m_loadingIcon->deleteLater();
m_webPage->deleteLater();
m_webEngine->deleteLater();
+
if (m_virtualCamThread){
m_virtualCamThread->quit();
m_virtualCamThread->wait();
@@ -47,20 +46,16 @@ void VideoRehabWidget::initUI()
// Set and start loading
ui->frameError->hide();
setLoading(true);
- ui->wdgWebEngine->hide();
m_loadingIcon = new QMovie("://status/calling.gif");
ui->icoLoading->setMovie(m_loadingIcon);
m_loadingIcon->start();
- QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
- //QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
- QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, false);
-
- m_webEngine = new QWebEngineView(ui->wdgWebEngine);
+ m_webEngine = new QWebEngineView(/*ui->wdgWebEngine*/);
connect(m_webEngine, &QWebEngineView::loadFinished, this, &VideoRehabWidget::webPageLoaded);
// Create a new page
+ // DL new Settings are set in the page constructor
m_webPage = new VideoRehabWebPage(m_webEngine);
connect(m_webPage->getSharedObject(), &SharedObject::pageIsReady, this, &VideoRehabWidget::webPageReady);
connect(m_webPage->getSharedObject(), &SharedObject::videoErrorOccured, this, &VideoRehabWidget::webPageVideoError);
@@ -77,8 +72,8 @@ void VideoRehabWidget::initUI()
//Set page to view
m_webEngine->setPage(m_webPage);
- QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(/*QWebEngineProfile::AllowPersistentCookies*/QWebEngineProfile::NoPersistentCookies);
- QWebEngineProfile::defaultProfile()->setHttpCacheType(/*QWebEngineProfile::DiskHttpCache*/QWebEngineProfile::NoCache);
+ QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
+ QWebEngineProfile::defaultProfile()->setHttpCacheType(QWebEngineProfile::NoCache);
// Set download path
setDataSavePath();
@@ -90,9 +85,10 @@ void VideoRehabWidget::initUI()
layout->setContentsMargins(0,0,0,0);
ui->wdgWebEngine->setLayout(layout);
}
- QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
m_webEngine->setSizePolicy(sizePolicy);
ui->wdgWebEngine->layout()->addWidget(m_webEngine);
+
}
bool VideoRehabWidget::handleJoinSessionEvent(const JoinSessionEvent &event)
@@ -177,7 +173,7 @@ void VideoRehabWidget::webEngineURLChanged(QUrl url)
ui->txtURL->setText(url.toString());
}
-void VideoRehabWidget::webEngineDownloadRequested(QWebEngineDownloadItem *item)
+void VideoRehabWidget::webEngineDownloadRequested(QWebEngineDownloadRequest *item)
{
//qDebug() << "WebEngine: about to download " << item->suggestedFileName();
emit fileDownloading(true);
@@ -210,7 +206,7 @@ void VideoRehabWidget::webEngineDownloadRequested(QWebEngineDownloadItem *item)
item->setDownloadFileName(file_name);
}
- connect(item, &QWebEngineDownloadItem::finished, this, &VideoRehabWidget::webEngineDownloadCompleted);
+ connect(item, &QWebEngineDownloadRequest::isFinishedChanged, this, &VideoRehabWidget::webEngineDownloadCompleted);
item->accept();
}
@@ -220,7 +216,7 @@ void VideoRehabWidget::webEngineDownloadCompleted()
// Enable buttons
emit fileDownloading(false);
- QWebEngineDownloadItem* item = dynamic_cast(sender());
+ QWebEngineDownloadRequest* item = dynamic_cast(sender());
if (item){
if (item->receivedBytes() == 0)
return;
@@ -357,7 +353,13 @@ void VideoRehabWidget::setLoading(const bool &loading)
{
ui->frameLoading->setVisible(loading);
if (!ui->frameError->isVisible()){
- ui->wdgWebEngine->setVisible(!loading);
+ // SB Qt6 WebEngine seems to force refresh of the whole window when showing / hiding once in a while.
+ // So instead of fully hiding, we just set its maximum height.
+ if (loading)
+ ui->wdgWebEngine->setMaximumHeight(0);
+ else
+ ui->wdgWebEngine->setMaximumHeight(65535);
+ //ui->wdgWebEngine->setVisible(!loading);
}
}
@@ -383,11 +385,12 @@ void VideoRehabWidget::startVirtualCamera(const QString &src)
ui->frameError->hide();
m_virtualCamThread = new VirtualCameraThread(src);
connect(m_virtualCamThread, &VirtualCameraThread::virtualCamDisconnected, this, &VideoRehabWidget::virtualCameraDisconnected);
- m_virtualCamThread->start();
+ m_virtualCamThread->start();
}
void VideoRehabWidget::stopVirtualCamera()
{
+
qDebug() << "VideoRehabWidget::stopVirtualCamera";
if (m_virtualCamThread){
m_virtualCamThread->quit();
@@ -397,6 +400,16 @@ void VideoRehabWidget::stopVirtualCamera()
}
}
+void VideoRehabWidget::resizeEvent(QResizeEvent *event)
+{
+ // Webpage will set its content size to its initial size, thus webengine will stay at that size.
+ // This resizes the view to force a resize of the underlying page.
+ // Not perfect as multiple calls could be performed, but working for now.
+ ui->wdgWebEngine->setMaximumWidth(event->size().width()-50);
+
+ //BaseServiceWidget::resizeEvent(event);
+}
+
void VideoRehabWidget::on_btnRefresh_clicked()
{
reload();
diff --git a/client/src/services/VideoRehabService/VideoRehabWidget.h b/client/src/services/VideoRehabService/VideoRehabWidget.h
index 18fd83fe..a7e86aa2 100644
--- a/client/src/services/VideoRehabService/VideoRehabWidget.h
+++ b/client/src/services/VideoRehabService/VideoRehabWidget.h
@@ -41,7 +41,7 @@ class VideoRehabWidget : public BaseServiceWidget
private slots:
void on_txtURL_returnPressed();
void webEngineURLChanged(QUrl url);
- void webEngineDownloadRequested(QWebEngineDownloadItem* item);
+ void webEngineDownloadRequested(QWebEngineDownloadRequest* item);
void webEngineDownloadCompleted();
void webPageLoaded(bool ok);
@@ -75,6 +75,10 @@ private slots:
signals:
void fileDownloading(bool downloading);
+
+ // QWidget interface
+ protected:
+ void resizeEvent(QResizeEvent *event) override;
};
#endif // VIDEOREHABWIDGET_H
diff --git a/client/src/services/VideoRehabService/VideoRehabWidget.ui b/client/src/services/VideoRehabService/VideoRehabWidget.ui
index 79ac5ea3..4b4d58ac 100644
--- a/client/src/services/VideoRehabService/VideoRehabWidget.ui
+++ b/client/src/services/VideoRehabService/VideoRehabWidget.ui
@@ -10,6 +10,12 @@
427
+
+
+ 0
+ 0
+
+
Form
diff --git a/client/src/widgets/AssetsWidget.cpp b/client/src/widgets/AssetsWidget.cpp
index 0ffe2350..df0c5f68 100644
--- a/client/src/widgets/AssetsWidget.cpp
+++ b/client/src/widgets/AssetsWidget.cpp
@@ -214,7 +214,7 @@ void AssetsWidget::queryAssetsInfos()
QMultiMap services_assets_tokens;
// Group each assets by access url
- for(TeraData* asset: qAsConst(m_assets)){
+ for(TeraData* asset: std::as_const(m_assets)){
if (asset->hasFieldName("asset_infos_url")){
QString asset_info_str = asset->getFieldValue("asset_infos_url").toString();
if (!asset_info_str.isEmpty()){
@@ -227,7 +227,7 @@ void AssetsWidget::queryAssetsInfos()
// Query each service for their assets
QStringList service_urls = services_assets.uniqueKeys();
- for(const QString &service_url: qAsConst(service_urls)){
+ for(const QString &service_url: std::as_const(service_urls)){
QStringList asset_uuids = services_assets.values(service_url);
QStringList asset_tokens = services_assets_tokens.values(service_url);
QJsonDocument document;
@@ -677,7 +677,7 @@ void AssetsWidget::processServicesReply(QList services, QUrlQuery repl
// Check if project is in service_fields
if (service.hasFieldName("service_projects")){
QVariantList projects = service.getFieldValue("service_projects").toList();
- for (const QVariant &project:qAsConst(projects)){
+ for (const QVariant &project:std::as_const(projects)){
QVariantMap project_info = project.toMap();
if (project_info["id_project"].toInt() == m_idProject){
// Ok, we are allowed to use file transfer service
@@ -837,7 +837,7 @@ void AssetsWidget::assetComPostOK(QString path)
void AssetsWidget::processAssetsInfos(QList infos, QUrlQuery reply_query, QString reply_path)
{
- for (const QJsonObject &asset_info:qAsConst(infos)){
+ for (const QJsonObject &asset_info:std::as_const(infos)){
QString asset_uuid = asset_info["asset_uuid"].toString();
if (!m_treeAssets.contains(asset_uuid)){
@@ -1011,7 +1011,7 @@ void AssetsWidget::on_btnDownloadAll_clicked()
QStringList assets_to_download;
// Download all assets
- for(TeraData* asset:qAsConst(m_assets)){
+ for(TeraData* asset:std::as_const(m_assets)){
assets_to_download.append(asset->getUuid());
}
@@ -1029,7 +1029,7 @@ void AssetsWidget::on_treeAssets_itemExpanded(QTreeWidgetItem *item)
setLoading(true, tr("Affichage des données en cours..."));
QCoreApplication::processEvents();
QStringList assets_uuids = m_assetsSessions.values(id_session);
- for (const QString &asset_uuid: qAsConst(assets_uuids)){
+ for (const QString &asset_uuid: std::as_const(assets_uuids)){
if (m_assets.contains(asset_uuid)){
updateAsset(*m_assets[asset_uuid]);
}
@@ -1049,7 +1049,7 @@ void AssetsWidget::on_treeAssets_itemCollapsed(QTreeWidgetItem *item)
if (id_session != -1){
// Remove all assets from display
QList assets_items = item->takeChildren();
- for(QTreeWidgetItem* asset_item: qAsConst(assets_items)){
+ for(QTreeWidgetItem* asset_item: std::as_const(assets_items)){
QString asset_uuid = m_treeAssets.key(asset_item);
m_treeAssets.remove(asset_uuid);
delete asset_item;
diff --git a/client/src/widgets/ConfigWidget.cpp b/client/src/widgets/ConfigWidget.cpp
index 5f696245..7f081775 100644
--- a/client/src/widgets/ConfigWidget.cpp
+++ b/client/src/widgets/ConfigWidget.cpp
@@ -46,13 +46,14 @@ void ConfigWidget::addSection(const QString &name, const QIcon &icon, const int
tmp->setText(name);
tmp->setTextAlignment(Qt::AlignCenter);
tmp->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
- //tmp->setSizeHint(QSize(ui->lstSections->width(), 64));
tmp->setToolTip(name);
+ //tmp->setSizeHint(ui->lstSections->gridSize());
tmp->setData(Qt::UserRole, id);
}
void ConfigWidget::setupSections()
{
+ ui->lstSections->setGridSize(QSize(ui->lstSections->width()-20, ui->lstSections->gridSize().height()));
addSection(tr("Utilisateurs"), QIcon(TeraData::getIconFilenameForDataType(TERADATA_USER)), TERADATA_USER);
addSection(tr("Groupes utilisateurs"), QIcon(TeraData::getIconFilenameForDataType(TERADATA_USERGROUP)), TERADATA_USERGROUP);
addSection(tr("Sites"), QIcon("://icons/site-icon.png"), TERADATA_SITE);
diff --git a/client/src/widgets/ConfigWidget.ui b/client/src/widgets/ConfigWidget.ui
index da237cff..9a22a708 100644
--- a/client/src/widgets/ConfigWidget.ui
+++ b/client/src/widgets/ConfigWidget.ui
@@ -14,104 +14,7 @@
Form
- /*
-QPushButton#btnConnect{background-color:rgb(80,180,80)}
-QWidget{background-color: rgba(0,0,0,0);color:white;border-radius:5px}
-QWidget#mainWidget{background-color:rgba(128,128,128,25%);}
-QWidget#frmProfile,QWidget#pageProfile{background-color:rgba(108,8,156,25%);}
-QPlainTextEdit,QLineEdit,QListWidget,QComboBox,QTextEdit,QSpinBox{background-color: rgba(255,255,255,50%); color: black;}
-
-QTableWidget{
-background-color: rgba(0,0,0,50%);
-color: white;
-border: 1px solid rgba(255,255,255,50%);
-}
-
-QLabel#lblLastOnline{color:lightblue;}
-QLabel#lblError,QLabel#lblCamMissing,QLabel#lblAudioMissing{color:red; background-color:rgba(255,0,0,30%);}
-
-QLineEdit:!enabled, QListWidget:!enabled,QComboBox:!enabled,QTextEdit:!enabled,QPlainTextEdit:!enabled{background-color: rgba(0,0,0,30%);color:white;border:0}
-QDateEdit::down-arrow:!enabled,QTimeEdit::down-arrow:!enabled,QDateEdit::up-arrow:!enabled,QTimeEdit::up-arrow:!enabled,QComboBox::drop-down:!enabled{background-color:rgba(0,0,0,0%);}
-
-QTextEdit#txtProfile{background-color: rgba(255,255,255,80%);color:black;border:0}
-QTextEdit:!enabled#txtProfile{background-color: rgba(255,255,255,60%);color:black;border:0}
-
-QFrame#frmSelUser{background-color:rgba(100,100,200,50%);}
-QFrame#frmAudio,QFrame#frmCam1,QFrame#frmCam2,QFrame#frmSensors,QFrame#frmWebRTC,QFrame#frmVirtualCam,QFrame#frmExternalPrograms{background-color:rgba(100,100,200,35%);}
-
-QCheckBox::indicator:unchecked:!enabled { background-color:rgba(128,0,0,100%);}
-QCheckBox::indicator:checked:!enabled { background-color:green;}
-QCheckBox::indicator:unchecked{ background-color:red;border-radius:3px;}
-QCheckBox::indicator:checked {background-color:rgb(0,255,0);border-radius:3px;}
-QCheckBox:checked{color:lightgreen;background-color:rgba(0,0,0,0%);}
-QCheckBox:!checked{color:red;background-color:rgba(0,0,0,0%);}
-
-QPushButton{background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #2198c0, stop: 1 #0d5ca6);}
-QPushButton:checked{background-color:rgb(128,128,128); border:1px solid rgba(255,255,255,50%);}
-QPushButton:hover,QPushButton:checked{background-color: rgba(255,255,255,75%);color:black;}
-QPushButton#btnEditUser:hover{background-color: rgba(255,255,255,75%);color:black;}
-QPushButton#btnEdit,QPushButton#btnDelete,QPushButton#btnExisting{background-color: rgba(255,255,255,0%);border:0 px;}
-QPushButton#btnEdit:hover,QPushButton#btnDelete:hover,QPushButton#btnExisting:hover{background-color: rgba(255,255,255,25%);border:0 px;}
-QPushButton#btnExisting:checked{background-color:rgba(0,100,200,50%);}
-QPushButton#btnUpgrade{background-color:rgba(200,0,0,90%);}
-
-QToolButton:hover{background-color: rgba(255,255,255,50);}
-
-QTreeWidget::branch:closed:has-children:has-siblings {
- border-image: none;
- image: url(:/pictures/controls/branch_closed.png);
- }
-
- QTreeView::branch:open:has-children:!has-siblings,
- QTreeView::branch:open:has-children:has-siblings {
- border-image: none;
- image:url(:/pictures/controls/branch_opened.png);
- }
-
-QWidget#lineOnline{background-color:blue;}
-QWidget#lineOffline{background-color:red;}
-QWidget#lineBoth{background-color:rgb(255,0,255);}
-
-
-QTabWidget::pane {
- background-color: rgba(128,128,140,25%);
- border-radius: 5px;
- border: 2px solid rgba(128,128,140,50%);
- }
-
- QTabWidget::tab-bar {
- left: 5px; /
- }
-
-
- QTabBar::tab,QTableWidget::tab,QHeaderView::section {
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 rgba(128,128,140,50%), stop: 1.0 rgba(128,128,140,25%));
- border: 2px solid rgba(128,128,140,50%);
- border-bottom: 0px;
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
- padding: 2px;
-min-height:25px;
- }
-
- QTabBar::tab:selected, QTabBar::tab:hover {
-
-background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
- stop: 0 rgba(128,128,140,70%), stop: 1.0 rgba(128,128,140,50%));
- }
-
- QTabBar::tab:selected {
- border-color:rgba(128,128,140,60%);
- border-bottom-color:rgba(128,128,140,60%);
- }
-
- QTabBar::tab:!selected {
- margin-top: 2px;
- }
-*/
-
-
+
-
@@ -195,6 +98,9 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
true
+
+ QListView::Batched
+
100
@@ -205,13 +111,13 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
QListView::IconMode
- false
+ true
true
- true
+ false
Qt::AlignCenter
diff --git a/client/src/widgets/DashboardWidget.cpp b/client/src/widgets/DashboardWidget.cpp
index dd367121..737fcf4f 100644
--- a/client/src/widgets/DashboardWidget.cpp
+++ b/client/src/widgets/DashboardWidget.cpp
@@ -7,8 +7,9 @@ DashboardWidget::DashboardWidget(ComManager *comMan, int id_site, QWidget *paren
m_comManager(comMan)
{
ui->setupUi(this);
-
+#ifndef OPENTERA_WEBASSEMBLY
m_sessionLobby = nullptr;
+#endif
m_cleanupDiag = nullptr;
ui->tableUpcomingSessions->hide();
ui->tableRecentParticipants->hide();
@@ -28,10 +29,15 @@ DashboardWidget::~DashboardWidget()
qDeleteAll(m_sessions);
qDeleteAll(m_session_types);
- if (m_cleanupDiag)
+ if (m_cleanupDiag) {
m_cleanupDiag->deleteLater();
- if (m_sessionLobby)
+ }
+
+#ifndef OPENTERA_WEBASSEMBLY
+ if (m_sessionLobby) {
m_sessionLobby->deleteLater();
+ }
+#endif
delete ui;
}
@@ -152,7 +158,7 @@ void DashboardWidget::processSessionsReply(const QList sessions)
// Update values
name_item->setText(session.getName());
QDateTime session_date = session.getFieldValue("session_start_datetime").toDateTime().toLocalTime();
- date_item->setText(session_date.toString("dd-MM-yyyy hh:mm:ss"));
+ date_item->setDate(session_date);
// Type
int id_session_type = session.getFieldValue("id_session_type").toInt();
@@ -180,7 +186,7 @@ void DashboardWidget::processSessionsReply(const QList sessions)
QString project_name;
if (session.hasFieldName("session_participants")){
QVariantList participants = session.getFieldValue("session_participants").toList();
- for(const QVariant &participant: qAsConst(participants)){
+ for(const QVariant &participant: std::as_const(participants)){
QVariantHash part_data = participant.toHash();
if (project_name.isEmpty() && part_data.contains("project_name")){
@@ -195,14 +201,14 @@ void DashboardWidget::processSessionsReply(const QList sessions)
}
if (session.hasFieldName("session_users")){
QVariantList users = session.getFieldValue("session_users").toList();
- for(const QVariant &user: qAsConst(users)){
+ for(const QVariant &user: std::as_const(users)){
QVariantHash user_data = user.toHash();
invitees.append(user_data["user_name"].toString());
}
}
if (session.hasFieldName("session_devices")){
QVariantList devices = session.getFieldValue("session_devices").toList();
- for(const QVariant &device: qAsConst(devices)){
+ for(const QVariant &device: std::as_const(devices)){
QVariantHash device_data = device.toHash();
invitees.append(device_data["device_name"].toString());
}
@@ -253,6 +259,9 @@ void DashboardWidget::processSessionTypesReply(const QList session_typ
// Refresh data
refreshData();
+
+ // Disconnect signal since we don't need it anymore
+ disconnect(m_comManager, &ComManager::sessionTypesReceived, this, &DashboardWidget::processSessionTypesReply);
}
void DashboardWidget::processParticipantsReply(const QList participants, const QUrlQuery reply_query)
@@ -346,6 +355,7 @@ void DashboardWidget::processStatsReply(const TeraData stats, const QUrlQuery re
ui->treeWarnings->clear();
int warnings = 0;
int total_warnings = 0;
+ ui->treeWarnings->setColumnWidth(0, 48);
if (stats.hasFieldName("warning_participants_count")){
warnings = stats.getFieldValue("warning_participants_count").toInt();
if (warnings > 0){
@@ -357,11 +367,11 @@ void DashboardWidget::processStatsReply(const TeraData stats, const QUrlQuery re
QToolButton* manage_btn = createManageWarningButton();
manage_btn->setProperty("data", stats.getFieldValue("warning_participants"));
manage_btn->setProperty("data_type", TERADATA_PARTICIPANT);
- ui->treeWarnings->setItemWidget(item, 0, manage_btn);
+ ui->treeWarnings->setItemWidget(item, 0, manage_btn);
// Participants details
QVariantList participants = stats.getFieldValue("warning_participants").toList();
- for (const QVariant &part: qAsConst(participants)){
+ for (const QVariant &part: std::as_const(participants)){
QVariantHash part_data = part.toHash();
QString data_str;
data_str = part_data["participant_name"].toString();
@@ -393,7 +403,7 @@ void DashboardWidget::processStatsReply(const TeraData stats, const QUrlQuery re
// Participants details
QVariantList participants = stats.getFieldValue("warning_nosession_participants").toList();
- for (const QVariant &part: qAsConst(participants)){
+ for (const QVariant &part: std::as_const(participants)){
QVariantHash part_data = part.toHash();
QString data_str;
data_str = part_data["participant_name"].toString();
@@ -426,7 +436,7 @@ void DashboardWidget::processStatsReply(const TeraData stats, const QUrlQuery re
// Users details
QVariantList users = stats.getFieldValue("warning_users").toList();
- for (const QVariant &user: qAsConst(users)){
+ for (const QVariant &user: std::as_const(users)){
QVariantHash user_data = user.toHash();
QString data_str;
data_str = user_data["user_fullname"].toString();
@@ -455,7 +465,7 @@ void DashboardWidget::processStatsReply(const TeraData stats, const QUrlQuery re
// Users details
QVariantList users = stats.getFieldValue("warning_neverlogged_users").toList();
- for (const QVariant &user: qAsConst(users)){
+ for (const QVariant &user: std::as_const(users)){
QVariantHash user_data = user.toHash();
QString data_str;
data_str = user_data["user_fullname"].toString();
@@ -486,7 +496,7 @@ void DashboardWidget::processStatsReply(const TeraData stats, const QUrlQuery re
ui->btnAttention->setText(tr("Attention requise") + " (" + QString::number(total_warnings) + ")");
}
-
+#ifndef OPENTERA_WEBASSEMBLY
void DashboardWidget::sessionLobbyStartSessionCancelled()
{
if (m_sessionLobby){
@@ -509,6 +519,7 @@ void DashboardWidget::sessionLobbyStartSessionRequested()
m_sessionLobby->deleteLater();
m_sessionLobby = nullptr;
}
+#endif
void DashboardWidget::cleanupDialogCompleted()
{
@@ -567,6 +578,7 @@ void DashboardWidget::updateUiSpacing()
}
}
+#ifndef OPENTERA_WEBASSEMBLY
void DashboardWidget::showSessionLobby(const int &id_session_type, const int &id_session)
{
if (m_sessionLobby)
@@ -598,7 +610,7 @@ void DashboardWidget::showSessionLobby(const int &id_session_type, const int &id
QList ids;
if (session->hasFieldName("session_participants")){
QVariantList session_participants = session->getFieldValue("session_participants").toList();
- for(const QVariant &participant: qAsConst(session_participants)){
+ for(const QVariant &participant: std::as_const(session_participants)){
TeraData part_data(TERADATA_PARTICIPANT, participant.toJsonValue());
participants.append(part_data);
ids.append(part_data.getId());
@@ -612,7 +624,7 @@ void DashboardWidget::showSessionLobby(const int &id_session_type, const int &id
QList users;
if (session->hasFieldName("session_users")){
QVariantList session_users = session->getFieldValue("session_users").toList();
- for(const QVariant &user: qAsConst(session_users)){
+ for(const QVariant &user: std::as_const(session_users)){
TeraData user_data(TERADATA_USER, user.toJsonValue());
users.append(user_data);
ids.append(user_data.getId());
@@ -626,7 +638,7 @@ void DashboardWidget::showSessionLobby(const int &id_session_type, const int &id
QList devices;
if (session->hasFieldName("session_devices")){
QVariantList session_devices = session->getFieldValue("session_devices").toList();
- for(const QVariant &device: qAsConst(session_devices)){
+ for(const QVariant &device: std::as_const(session_devices)){
TeraData device_data(TERADATA_DEVICE, device.toJsonValue());
devices.append(device_data);
ids.append(device_data.getId());
@@ -644,13 +656,15 @@ void DashboardWidget::showSessionLobby(const int &id_session_type, const int &id
// Show Session Lobby
m_sessionLobby->exec();
}
+#endif
QToolButton *DashboardWidget::createManageWarningButton()
{
QToolButton* manage_btn = new QToolButton();
manage_btn->setIcon(QIcon("://icons/config.png"));
manage_btn->setIconSize(QSize(20,20));
- manage_btn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+ manage_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ manage_btn->setFixedSize(28, 28);
manage_btn->setToolTip(tr("Gérer"));
manage_btn->setCursor(Qt::PointingHandCursor);
manage_btn->setStyleSheet("QToolButton::hover{background-color:transparent;}");
@@ -663,13 +677,14 @@ QToolButton *DashboardWidget::createManageWarningButton()
void DashboardWidget::on_tableUpcomingSessions_itemDoubleClicked(QTableWidgetItem *item)
{
+#ifndef OPENTERA_WEBASSEMBLY
int current_row = item->row();
QTableWidgetItem* base_item = ui->tableUpcomingSessions->item(current_row, 1);
-
if (m_listSessions_items.contains(base_item)){
int id_session = m_listSessions_items.value(base_item);
showSessionLobby(m_sessions[id_session]->getFieldValue("id_session_type").toInt(), id_session);
}
+#endif
}
diff --git a/client/src/widgets/DashboardWidget.h b/client/src/widgets/DashboardWidget.h
index 5d01c535..72f23fd4 100644
--- a/client/src/widgets/DashboardWidget.h
+++ b/client/src/widgets/DashboardWidget.h
@@ -11,7 +11,10 @@
#include "widgets/TableDateWidgetItem.h"
+#ifndef OPENTERA_WEBASSEMBLY
#include "dialogs/SessionLobbyDialog.h"
+#endif
+
#include "dialogs/CleanUpDialog.h"
#include "GlobalMessageBox.h"
@@ -43,9 +46,10 @@ private slots:
void processSessionTypesReply(const QList session_types);
void processParticipantsReply(const QList participants, const QUrlQuery reply_query);
void processStatsReply(const TeraData stats, const QUrlQuery reply_query);
-
+#ifndef OPENTERA_WEBASSEMBLY
void sessionLobbyStartSessionCancelled();
void sessionLobbyStartSessionRequested();
+#endif
void cleanupDialogCompleted();
void on_tableUpcomingSessions_itemDoubleClicked(QTableWidgetItem *item);
@@ -62,7 +66,9 @@ private slots:
ComManager* m_comManager;
int m_siteId;
+#ifndef OPENTERA_WEBASSEMBLY
SessionLobbyDialog* m_sessionLobby;
+#endif
CleanUpDialog* m_cleanupDiag;
QHash m_listSessions_items;
@@ -76,9 +82,9 @@ private slots:
void refreshData();
void updateUiSpacing();
-
+#ifndef OPENTERA_WEBASSEMBLY
void showSessionLobby(const int &id_session_type, const int &id_session);
-
+#endif
QToolButton *createManageWarningButton();
};
diff --git a/client/src/widgets/DashboardWidget.ui b/client/src/widgets/DashboardWidget.ui
index 2881725c..47cbc671 100644
--- a/client/src/widgets/DashboardWidget.ui
+++ b/client/src/widgets/DashboardWidget.ui
@@ -46,7 +46,7 @@ text-align:left;
0
- -14
+ -528
704
948
@@ -120,7 +120,6 @@ text-align:left;
9
- 75
true
@@ -195,7 +194,6 @@ text-align:left;
9
- 75
true
@@ -212,6 +210,9 @@ text-align:left;
-
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -331,7 +332,6 @@ text-align:left;
9
- 75
true
@@ -416,6 +416,9 @@ text-align:left;
-
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -514,7 +517,6 @@ text-align:left;
9
- 75
true
@@ -587,6 +589,9 @@ text-align:left;
-
+
+ Qt::NoFocus
+
QAbstractItemView::NoEditTriggers
@@ -656,6 +661,10 @@ text-align:left;
ClickableLabel
QLabel
+
+ clicked()
+ clicked()
+
diff --git a/client/src/widgets/HistoryCalendarWidget.cpp b/client/src/widgets/HistoryCalendarWidget.cpp
index a3d61891..090c223e 100644
--- a/client/src/widgets/HistoryCalendarWidget.cpp
+++ b/client/src/widgets/HistoryCalendarWidget.cpp
@@ -14,7 +14,7 @@ HistoryCalendarWidget::~HistoryCalendarWidget(){
qDeleteAll(m_ids_session_types);
}
-void HistoryCalendarWidget::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const{
+void HistoryCalendarWidget::paintCell(QPainter *painter, const QRect &rect, QDate date) const{
QPen pen;
QBrush brush;
brush.setColor(Qt::transparent);
@@ -37,16 +37,27 @@ void HistoryCalendarWidget::paintCell(QPainter *painter, const QRect &rect, cons
//return;
}*/
- if (date==QDate::currentDate()){
- pen.setColor(Qt::cyan);
+ QFont painter_font = painter->font();
+ if (date==QDate::currentDate() && date <= maximumDate()){
+ pen.setColor(Qt::red);
+ painter_font.setBold(true);
painter->setPen(pen);
painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
+ }else{
+ painter_font.setBold(false);
}
+ painter->setFont(painter_font);
// Check for sessions on that date
- if (!m_sessions.contains(date) || date.month() != monthShown()){
+ if (!m_sessions.contains(date) || date.month() != monthShown() || date > maximumDate() || date < minimumDate()){
// Paint with default format
- QCalendarWidget::paintCell (painter, rect, date);
+ if (date >= minimumDate() && date <= maximumDate()){
+ pen.setColor(Qt::gray);
+ painter->setPen(pen);
+ painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
+ }/*else{
+ QCalendarWidget::paintCell(painter, rect, date);
+ }*/
return;
}
// Check to be sure that we don't have all filtered out sessions types for that date
@@ -66,11 +77,13 @@ void HistoryCalendarWidget::paintCell(QPainter *painter, const QRect &rect, cons
LOG_WARNING("No session type match - ignoring.", "HistoryCalendarWidget::paintCell");
}
}
- int count = 0;
int total = display_colors.count(); //m_sessions->at(m_dates.value(date))->sessionsTypesCount(*m_displayTypes);
if (total==0){
// All session types filtered for today, paint with default
- QCalendarWidget::paintCell (painter, rect, date);
+ pen.setColor(Qt::gray);
+ painter->setPen(pen);
+ painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
+
return;
}
@@ -105,7 +118,8 @@ void HistoryCalendarWidget::paintCell(QPainter *painter, const QRect &rect, cons
//qDebug() << date.toString() << ": Count = " << QString::number(count) << ", Total = " << QString::number(total);
//for (int i=0; idrawRect(rect.adjusted(2,
static_cast(ratio*rect.height()+2),
static_cast(-2*static_cast(rect.width())/3-2),
- static_cast(rect.height()/static_cast(total)-2)));
+ -2 //static_cast(rect.height()/static_cast(total)-2)
+ )
+ );
count++;
}
- // Check if we need to display any indicator warning for that session
- /*for (int i=0; icount(); i++){
- if (sessions->at(i)->hasTechAlert()){
- painter->drawImage(rect.adjusted((float)rect.width()/2,2,-2,-(float)rect.height()/2),QImage(":/pictures/icons/warning.png"));
- }
- }*/
-
pen.setColor(Qt::black);
painter->setPen(pen);
painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
diff --git a/client/src/widgets/HistoryCalendarWidget.h b/client/src/widgets/HistoryCalendarWidget.h
index 50a318bb..f03b0dfa 100644
--- a/client/src/widgets/HistoryCalendarWidget.h
+++ b/client/src/widgets/HistoryCalendarWidget.h
@@ -15,7 +15,7 @@ class HistoryCalendarWidget : public QCalendarWidget
explicit HistoryCalendarWidget(QWidget *parent=nullptr);
~HistoryCalendarWidget();
- void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const;
+ void paintCell(QPainter *painter, const QRect &rect, QDate date) const override;
//void setEvents1(QList* events);
//void setEvents2(QList* events);
diff --git a/client/src/widgets/InSessionWidget.cpp b/client/src/widgets/InSessionWidget.cpp
index 485bca32..047e5179 100644
--- a/client/src/widgets/InSessionWidget.cpp
+++ b/client/src/widgets/InSessionWidget.cpp
@@ -260,8 +260,13 @@ void InSessionWidget::on_btnEndSession_clicked()
void InSessionWidget::on_btnInSessionInfos_toggled(bool checked)
{
+ int mainWidth = ui->widgetMain->width();
ui->tabInfos->setVisible(checked);
-
+ if (checked){
+ ui->widgetMain->setMaximumWidth(mainWidth - ui->tabInfos->width());
+ }else{
+ ui->widgetMain->setMaximumWidth(mainWidth + ui->tabInfos->width());
+ }
}
void InSessionWidget::processSessionsReply(QList sessions)
@@ -282,7 +287,7 @@ void InSessionWidget::processSessionsReply(QList sessions)
/*if (session.hasFieldName("session_participants")){
item_list = session.getFieldValue("session_participants").toList();
- for(const QVariant &session_part:qAsConst(item_list)){
+ for(const QVariant &session_part:std::as_const(item_list)){
QVariantMap part_info = session_part.toMap();
ui->wdgInvitees->addRequiredParticipant(part_info["id_participant"].toInt());
}
@@ -291,7 +296,7 @@ void InSessionWidget::processSessionsReply(QList sessions)
if (session.hasFieldName("session_users")){
item_list = session.getFieldValue("session_users").toList();
- for(const QVariant &session_user:qAsConst(item_list)){
+ for(const QVariant &session_user:std::as_const(item_list)){
QVariantMap user_info = session_user.toMap();
int id_user = user_info["id_user"].toInt();
if (id_user == m_comManager->getCurrentUser().getId())
@@ -302,7 +307,7 @@ void InSessionWidget::processSessionsReply(QList sessions)
/*if (session.hasFieldName("session_devices")){
item_list = session.getFieldValue("session_devices").toList();
- for(const QVariant &session_device:qAsConst(item_list)){
+ for(const QVariant &session_device:std::as_const(item_list)){
QVariantMap device_info = session_device.toMap();
ui->wdgInvitees->addRequiredDevice(device_info["id_device"].toInt());
}
@@ -367,6 +372,17 @@ void InSessionWidget::ws_JoinSessionEvent(JoinSessionEvent event)
// Forward to widget
if (m_serviceWidget){
+ // SB Qt6 WebEngineView seems to cause issue when loading / displaying... Bug?
+ // This patch this behaviour and ensures that the session always starts in maximized mode
+ QWidget* parent = parentWidget();
+ while(parent){
+ parent = parent->parentWidget();
+ if (QString::fromStdString(parent->metaObject()->className()) == "MainWindow"){
+ parent->showNormal();
+ parent->showMaximized();
+ break;
+ }
+ }
bool result = m_serviceWidget->handleJoinSessionEvent(event);
if (result){
// If we have a result here, it's that the join was accepted for the first time.
@@ -458,17 +474,17 @@ void InSessionWidget::connectSignals()
void InSessionWidget::initUI()
{
+ ui->btnEndSession->hide();
+ ui->grpSavePath->hide();
ui->wdgInvitees->setConfirmOnRemove(true);
ui->wdgInvitees->setComManager(m_comManager);
//ui->wdgInvitees->showAvailableInvitees(true);
- ui->btnInSessionInfos->setChecked(true);
+ ui->btnInSessionInfos->setChecked(false);
+ ui->tabInfos->hide();
ui->tabInfos->setCurrentIndex(0);
- ui->btnEndSession->hide();
- ui->grpSavePath->hide();
-
// Clean up, if needed
if (m_serviceWidget){
m_serviceWidget->deleteLater();
@@ -485,7 +501,7 @@ void InSessionWidget::initUI()
bool handled = false;
if (service_key == "VideoRehabService"){
// Main widget = QWebEngine
- m_serviceWidget = new VideoRehabWidget(m_comManager, this);
+ m_serviceWidget = new VideoRehabWidget(m_comManager);
setMainWidget(m_serviceWidget);
m_serviceToolsWidget = new VideoRehabToolsWidget(m_comManager, m_serviceWidget, this);
setToolsWidget(m_serviceToolsWidget);
diff --git a/client/src/widgets/InSessionWidget.ui b/client/src/widgets/InSessionWidget.ui
index 9a17eb47..6d76b2c4 100644
--- a/client/src/widgets/InSessionWidget.ui
+++ b/client/src/widgets/InSessionWidget.ui
@@ -11,24 +11,12 @@
- Form
+ OpenTeraPlus - Séance
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
@@ -184,195 +172,197 @@
-
-
-
-
- 0
- 0
-
-
-
- Qt::Horizontal
-
-
-
-
- 0
- 0
-
-
-
-
- 300
- 16777215
-
-
-
- QTabWidget::West
-
-
- 1
-
-
-
- 20
- 20
-
-
-
-
-
- :/icons/patient.png:/icons/patient.png
-
-
- Invités
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
-
-
-
-
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 400
+ 16777215
+
+
+
+ QTabWidget::West
+
+
+ 0
+
+
+
+ 20
+ 20
+
+
+
+
+
+ :/icons/patient.png:/icons/patient.png
+
+
+ Invités
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+ :/icons/config.png:/icons/config.png
+
+
+ Paramètres
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Données
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Répertoire d'enregistrement
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 32
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ PointingHandCursor
+
+
+ Défaut
+
+
+
+ :/icons/leave.png:/icons/leave.png
+
+
+
+ 24
+ 24
+
+
+
+
+ -
+
+
+
+ 0
+ 32
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ PointingHandCursor
+
+
+ Parcourir...
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
-
-
-
- :/icons/config.png:/icons/config.png
-
-
- Paramètres
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Données
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Répertoire d'enregistrement
-
-
-
- -
-
-
- true
-
-
-
- -
-
-
-
-
-
-
- 0
- 32
-
-
-
-
- 16777215
- 16777215
-
-
-
- PointingHandCursor
-
-
- Défaut
-
-
-
- :/icons/leave.png:/icons/leave.png
-
-
-
- 24
- 24
-
-
-
-
- -
-
-
-
- 0
- 32
-
-
-
-
- 16777215
- 16777215
-
-
-
- PointingHandCursor
-
-
- Parcourir...
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
-
-
-
- 0
- 0
-
-
-
-
-
+
+
-
diff --git a/client/src/widgets/LogViewWidget.cpp b/client/src/widgets/LogViewWidget.cpp
index c74fc14f..b8e74a03 100644
--- a/client/src/widgets/LogViewWidget.cpp
+++ b/client/src/widgets/LogViewWidget.cpp
@@ -18,7 +18,7 @@ LogViewWidget::LogViewWidget(QWidget *parent):
// Init levels combo box
int level_id = LogEvent::LogLevel_MIN;
QStringList names = getLogLevelNames();
- for(const QString &name:qAsConst(names)){
+ for(const QString &name:std::as_const(names)){
ui->cmbLevel->addItem(name, level_id++);
/*if (level_id == LogEvent::LOGLEVEL_INFO){
ui->cmbLevel->setCurrentIndex(ui->cmbLevel->count()-1);
@@ -384,6 +384,9 @@ QString LogViewWidget::getOSIcon(const QString &os)
if (compare_os.contains("android"))
return "://icons/logs/os_android.png";
+ if (compare_os.contains("chrome"))
+ return "://icons/logs/browser_chrome.png";
+
return "";
}
diff --git a/client/src/widgets/NotificationWindow.cpp b/client/src/widgets/NotificationWindow.cpp
index 93640c20..09ebba66 100644
--- a/client/src/widgets/NotificationWindow.cpp
+++ b/client/src/widgets/NotificationWindow.cpp
@@ -146,7 +146,8 @@ void NotificationWindow::paintEvent(QPaintEvent *)
{
//this is mandatory for the style sheet to take effect
QStyleOption opt;
- opt.init(this);
+ //TODO Verify
+ //opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
diff --git a/client/src/widgets/NotificationWindow.h b/client/src/widgets/NotificationWindow.h
index d3fa5763..8bfc8f16 100644
--- a/client/src/widgets/NotificationWindow.h
+++ b/client/src/widgets/NotificationWindow.h
@@ -5,7 +5,7 @@
#include
#include
#include
-#include
+//#include
#include
#include "ui_notification.h"
diff --git a/client/src/widgets/OnlineManagerWidget.cpp b/client/src/widgets/OnlineManagerWidget.cpp
index eb7d2896..2403fc9f 100644
--- a/client/src/widgets/OnlineManagerWidget.cpp
+++ b/client/src/widgets/OnlineManagerWidget.cpp
@@ -124,9 +124,10 @@ void OnlineManagerWidget::refreshOnlines()
QUrlQuery args;
m_comManager->doGet(WEB_ONLINEDEVICEINFO_PATH, args);
- m_comManager->doGet(WEB_ONLINEPARTICIPANTINFO_PATH, args);
m_comManager->doGet(WEB_ONLINEUSERINFO_PATH, args);
-
+ args.addQueryItem(WEB_QUERY_WITH_PROJECTS, "1");
+ args.addQueryItem(WEB_QUERY_WITH_SITES, "1");
+ m_comManager->doGet(WEB_ONLINEPARTICIPANTINFO_PATH, args);
}
void OnlineManagerWidget::updateCounts()
@@ -190,9 +191,27 @@ void OnlineManagerWidget::updateOnlineParticipant(const TeraData *online_partici
if (online_participant->isOnline()/* || online_participant.isBusy()*/){ // Not online and not busy = don't need to add!
participant_item = new QTreeWidgetItem(m_baseParticipants);
participant_item->setIcon(0, QIcon(online_participant->getIconStateFilename()));
- participant_item->setText(0, online_participant->getName());
+ QString name = online_participant->getName();
+ QString project;
+ if (online_participant->hasFieldName("project_name")){
+ project = online_participant->getFieldValue("project_name").toString();
+ }
+ QString site;
+ if (online_participant->hasFieldName("site_name")){
+ site = online_participant->getFieldValue("site_name").toString();
+ }
+ if (!project.isEmpty()){
+ name += " (" + project + ")";
+ }
+ participant_item->setText(0, name);
#ifdef QT_DEBUG
- participant_item->setToolTip(0, uuid);
+ QString tooltip = uuid;
+ if (!site.isEmpty() && !project.isEmpty())
+ tooltip += "\n" + site + "\n" + project;
+ participant_item->setToolTip(0, tooltip);
+#else
+ if (!site.isEmpty() && !project.isEmpty())
+ participant_item->setToolTip(0, site + "\n" + project);
#endif
m_onlineParticipants[uuid] = participant_item;
}
@@ -265,11 +284,13 @@ void OnlineManagerWidget::createOnlineUser(const QString &uuid, const QString &n
m_onlineUsersData[uuid] = new_data;
}
-void OnlineManagerWidget::createOnlineParticipant(const QString& uuid, const QString& name)
+void OnlineManagerWidget::createOnlineParticipant(const QString& uuid, const QString& name, const QString &site, const QString &project)
{
TeraData new_data(TERADATA_ONLINE_PARTICIPANT);
new_data.setName(name);
new_data.setUuid(uuid);
+ new_data.setFieldValue("site_name", site);
+ new_data.setFieldValue("project_name", project);
m_onlineParticipantsData[uuid] = new_data;
}
@@ -320,7 +341,7 @@ void OnlineManagerWidget::ws_participantEvent(ParticipantEvent event)
return;*/
if (!m_onlineParticipantsData.contains(uuid)){
- createOnlineParticipant(uuid, QString::fromStdString(event.participant_name()));
+ createOnlineParticipant(uuid, QString::fromStdString(event.participant_name()), QString::fromStdString(event.participant_site_name()), QString::fromStdString(event.participant_project_name()));
}
TeraData* participant_data = &m_onlineParticipantsData[uuid];
@@ -397,7 +418,13 @@ void OnlineManagerWidget::processOnlineParticipants(QList participants
{
foreach(TeraData online_participant, participants){
if (!m_onlineParticipantsData.contains(online_participant.getUuid())){
- createOnlineParticipant(online_participant.getUuid(), online_participant.getName());
+ QString project;
+ if (online_participant.hasFieldName("project_name"))
+ project = online_participant.getFieldValue("project_name").toString();
+ QString site;
+ if (online_participant.hasFieldName("site_name"))
+ site = online_participant.getFieldValue("site_name").toString();
+ createOnlineParticipant(online_participant.getUuid(), online_participant.getName(), site, project);
}
TeraData* part_data = &m_onlineParticipantsData[online_participant.getUuid()];
part_data->setOnline(online_participant.isOnline());
diff --git a/client/src/widgets/OnlineManagerWidget.h b/client/src/widgets/OnlineManagerWidget.h
index 2f18aa11..93ce5104 100644
--- a/client/src/widgets/OnlineManagerWidget.h
+++ b/client/src/widgets/OnlineManagerWidget.h
@@ -54,7 +54,7 @@ class OnlineManagerWidget : public QWidget
void updateOnlineDevice(const TeraData *online_device);
void createOnlineUser(const QString& uuid, const QString& name);
- void createOnlineParticipant(const QString& uuid, const QString& name);
+ void createOnlineParticipant(const QString& uuid, const QString& name, const QString& site, const QString& project);
void createOnlineDevice(const QString& uuid, const QString& name);
private slots:
diff --git a/client/src/widgets/OnlineManagerWidget.ui b/client/src/widgets/OnlineManagerWidget.ui
index deb78aa2..58cfeb4c 100644
--- a/client/src/widgets/OnlineManagerWidget.ui
+++ b/client/src/widgets/OnlineManagerWidget.ui
@@ -229,6 +229,12 @@
-
+
+ QAbstractItemView::NoEditTriggers
+
+
+ false
+
QAbstractItemView::NoSelection
diff --git a/client/src/widgets/ProjectNavigator.cpp b/client/src/widgets/ProjectNavigator.cpp
index d2ccec0c..b2ec22e8 100644
--- a/client/src/widgets/ProjectNavigator.cpp
+++ b/client/src/widgets/ProjectNavigator.cpp
@@ -194,7 +194,7 @@ bool ProjectNavigator::selectItemByName(const TeraDataTypes &data_type, const QS
if (data_type == TERADATA_GROUP){
foreach(QTreeWidgetItem* item, m_groups_items){
if (item->text(0) == name){
- ui->treeNavigator->setCurrentItem(item);
+ setCurrentItem(item);
currentNavItemChanged(item, nullptr);
return true;
}
@@ -204,7 +204,7 @@ bool ProjectNavigator::selectItemByName(const TeraDataTypes &data_type, const QS
if (data_type == TERADATA_PROJECT){
foreach(QTreeWidgetItem* item, m_projects_items){
if (item->text(0) == name){
- ui->treeNavigator->setCurrentItem(item);
+ setCurrentItem(item);
currentNavItemChanged(item, nullptr);
return true;
}
@@ -214,7 +214,7 @@ bool ProjectNavigator::selectItemByName(const TeraDataTypes &data_type, const QS
if (data_type == TERADATA_PARTICIPANT){
foreach(QTreeWidgetItem* item, m_participants_items){
if (item->text(0) == name){
- ui->treeNavigator->setCurrentItem(item);
+ setCurrentItem(item);
currentNavItemChanged(item, nullptr);
return true;
}
@@ -224,7 +224,7 @@ bool ProjectNavigator::selectItemByName(const TeraDataTypes &data_type, const QS
if (data_type == TERADATA_USER){
foreach(QTreeWidgetItem* item, m_users_items){
if (item->text(0) == name){
- ui->treeNavigator->setCurrentItem(item);
+ setCurrentItem(item);
currentNavItemChanged(item, nullptr);
return true;
}
@@ -234,7 +234,7 @@ bool ProjectNavigator::selectItemByName(const TeraDataTypes &data_type, const QS
if (data_type == TERADATA_DEVICE){
foreach(QTreeWidgetItem* item, m_devices_items){
if (item->text(0) == name){
- ui->treeNavigator->setCurrentItem(item);
+ setCurrentItem(item);
currentNavItemChanged(item, nullptr);
return true;
}
@@ -250,7 +250,7 @@ bool ProjectNavigator::selectItemByUuid(const TeraDataTypes &data_type, const QS
if (m_participants.contains(uuid)){
QTreeWidgetItem* item = m_participants_items[m_participants[uuid].getId()];
if (item){
- ui->treeNavigator->setCurrentItem(item);
+ setCurrentItem(item);
currentNavItemChanged(item, nullptr);
return true;
}
@@ -353,21 +353,7 @@ TeraDataTypes ProjectNavigator::getCurrentItemType()
{
QTreeWidgetItem* item = getCurrentItem();
- if (item){
- if (m_devices_items.key(item, -1) >= 0){
- return TERADATA_DEVICE;
- }
- if (m_groups_items.key(item, -1) >= 0){
- return TERADATA_GROUP;
- }
- if (m_participants_items.key(item, -1) >= 0){
- return TERADATA_PARTICIPANT;
- }
- if (m_users_items.key(item, -1) >= 0){
- return TERADATA_USER;
- }
- }
- return TERADATA_NONE;
+ return getItemType(item);
}
int ProjectNavigator::getCurrentItemId()
@@ -386,6 +372,9 @@ int ProjectNavigator::getCurrentItemId()
if (id == -1){
id = m_users_items.key(item, -1);
}
+ if (id == -1){
+ id = m_projects_items.key(item, -1);
+ }
return id;
}
return -1;
@@ -534,7 +523,14 @@ void ProjectNavigator::updateProject(const TeraData *project)
}
item->setText(0, project->getName());
- item->setIcon(0, QIcon(TeraData::getIconFilenameForDataType(TERADATA_PROJECT)));
+ item->setIcon(0, QIcon(project->getIconStateFilename()));
+ if (project->isEnabled() || !project->hasEnabledField()){
+ item->setForeground(0, Qt::white);
+ item->setData(0, Qt::UserRole, true); // Enabled status
+ }else{
+ item->setForeground(0, Qt::gray);
+ item->setData(0, Qt::UserRole, false); // Disabled status
+ }
if (m_currentProjectId == id_project && m_currentProjectId >0 && !m_selectionHold){
// Load details
@@ -696,6 +692,7 @@ void ProjectNavigator::updateGroup(const TeraData *group)
}
item->setText(0, group->getName());
+ item->setForeground(0, m_projects_items[id_project]->foreground(0));
item->setIcon(0, QIcon(TeraData::getIconFilenameForDataType(TERADATA_GROUP)));
if (m_currentGroupId == id_group && m_currentGroupId >0 && !item->isExpanded()){
@@ -900,6 +897,12 @@ void ProjectNavigator::updateParticipant(const TeraData *participant)
}
item->setText(0, participant->getName());
+ if (participant->isEnabled()){
+ item->setForeground(0, Qt::white);
+ }else{
+ item->setForeground(0, Qt::gray);
+ }
+
if (participant->hasBusyStateField() || participant->hasOnlineStateField())
item->setIcon(0, QIcon(participant->getIconStateFilename()));
m_participants[participant->getUuid()] = *participant;
@@ -926,7 +929,7 @@ void ProjectNavigator::updateUser(const TeraData *user, const int& id_project)
if (id_project >=0){
// Check if already exists for that project
bool exists = false;
- for (QTreeWidgetItem* item:qAsConst(items)){
+ for (QTreeWidgetItem* item:std::as_const(items)){
QTreeWidgetItem* project = getProjectForItem(item);
if (project){
if (m_projects_items.key(project) == id_project){
@@ -964,7 +967,7 @@ void ProjectNavigator::updateUser(const TeraData *user, const int& id_project)
}
}
- for (QTreeWidgetItem* item:qAsConst(items)){
+ for (QTreeWidgetItem* item:std::as_const(items)){
item->setText(0, user->getName());
item->setIcon(0, QIcon(user->getIconStateFilename()));
}
@@ -982,7 +985,7 @@ void ProjectNavigator::updateDevice(const TeraData *device, const int &id_projec
if (id_project >=0){
// Check if already exists for that project
bool exists = false;
- for (QTreeWidgetItem* item:qAsConst(items)){
+ for (QTreeWidgetItem* item:std::as_const(items)){
QTreeWidgetItem* project = getProjectForItem(item);
if (project){
if (m_projects_items.key(project) == id_project){
@@ -1019,7 +1022,7 @@ void ProjectNavigator::updateDevice(const TeraData *device, const int &id_projec
}
}
- for (QTreeWidgetItem* item:qAsConst(items)){
+ for (QTreeWidgetItem* item:std::as_const(items)){
item->setText(0, device->getName());
item->setIcon(0, QIcon(device->getIconStateFilename()));
}
@@ -1133,6 +1136,18 @@ QTreeWidgetItem *ProjectNavigator::getProjectForItem(const QTreeWidgetItem *item
}
+QTreeWidgetItem *ProjectNavigator::getParticipantGroupForItem(const QTreeWidgetItem *item)
+{
+ QTreeWidgetItem* group = nullptr;
+ QTreeWidgetItem* item_parent = item->parent();
+ if (item_parent){
+ if (m_groups_items.key(item_parent,0) > 0){
+ group = item_parent;
+ }
+ }
+ return group;
+}
+
bool ProjectNavigator::isParticipantFiltered(const QString &part_uuid)
{
// No participant with that uuid!
@@ -1148,7 +1163,6 @@ bool ProjectNavigator::isParticipantFiltered(const QString &part_uuid)
}
// Check for text filtering
-
if (ui->btnSearch->isChecked() && !filtered){
filtered = !m_participants[part_uuid].getName().contains(ui->txtNavSearch->text(), Qt::CaseInsensitive);
}
@@ -1164,6 +1178,21 @@ bool ProjectNavigator::isAdvancedView()
void ProjectNavigator::setCurrentItem(QTreeWidgetItem *item)
{
ui->treeNavigator->setCurrentItem(item);
+ TeraDataTypes item_type = getItemType(item);
+ if (item_type == TERADATA_GROUP || item_type == TERADATA_PARTICIPANT){
+ // Make sure current project id is correct
+ QTreeWidgetItem* project = getProjectForItem(item);
+ if (project){
+ m_currentProjectId = m_projects_items.key(project);
+ }
+ }
+ if (item_type == TERADATA_PARTICIPANT){
+ // Make sure group id is correct, if available
+ QTreeWidgetItem* group = getParticipantGroupForItem(item);
+ if (group){
+ m_currentGroupId = m_groups_items.key(group);
+ }
+ }
updateAvailableActions(item);
}
@@ -1186,6 +1215,16 @@ void ProjectNavigator::selectItem(QTreeWidgetItem *item)
int id = m_participants_items.key(item);
setCurrentItem(m_participants_items[id]);
m_currentParticipantUuid = getParticipantUuid(id);
+ /*QTreeWidgetItem* project = getProjectForItem(ui->treeNavigator->currentItem());
+ if (project){
+ m_currentProjectId = m_projects_items.key(project);
+ }
+
+ QTreeWidgetItem* group = getParticipantGroupForItem(ui->treeNavigator->currentItem());
+ if (group){
+ m_currentGroupId = m_groups_items.key(group);
+ }*/
+
return;
}
}
@@ -1258,24 +1297,20 @@ void ProjectNavigator::updateAvailableActions(QTreeWidgetItem* current_item)
TeraDataTypes ProjectNavigator::getItemType(QTreeWidgetItem *item)
{
- if (std::find(m_projects_items.cbegin(), m_projects_items.cend(), item) != m_projects_items.cend()){
- return TERADATA_PROJECT;
+ if (m_devices_items.key(item, -1) >= 0){
+ return TERADATA_DEVICE;
}
-
- if (std::find(m_groups_items.cbegin(), m_groups_items.cend(), item) != m_groups_items.cend()){
+ if (m_groups_items.key(item, -1) >= 0){
return TERADATA_GROUP;
}
-
- if (std::find(m_participants_items.cbegin(), m_participants_items.cend(), item) != m_participants_items.cend()){
+ if (m_participants_items.key(item, -1) >= 0){
return TERADATA_PARTICIPANT;
}
-
- if (std::find(m_users_items.cbegin(), m_users_items.cend(), item) != m_users_items.cend()){
+ if (m_users_items.key(item, -1) >= 0){
return TERADATA_USER;
}
-
- if (std::find(m_devices_items.cbegin(), m_devices_items.cend(), item) != m_devices_items.cend()){
- return TERADATA_DEVICE;
+ if (m_projects_items.key(item, -1) >= 0){
+ return TERADATA_PROJECT;
}
if (isAdvancedView() && item){
@@ -1370,8 +1405,8 @@ void ProjectNavigator::deleteItemRequested()
tr("Êtes-vous sûrs de vouloir supprimer """) + ui->treeNavigator->currentItem()->text(0) + """?");
if (answer == QMessageBox::Yes){
// We must delete!
- TeraDataTypes item_type = getItemType(ui->treeNavigator->currentItem());
- int id_todel = ui->treeNavigator->currentItem()->data(0, Qt::UserRole).toInt();
+ TeraDataTypes item_type = getCurrentItemType(); //getItemType(ui->treeNavigator->currentItem());
+ int id_todel = getCurrentItemId();
emit dataDeleteRequest(item_type, id_todel);
}
}
@@ -1842,9 +1877,16 @@ void ProjectNavigator::on_btnFilterActive_toggled(bool checked)
item->setHidden(filtered);
}
}
+
+ // Filter disabled projects
+ foreach(QTreeWidgetItem* item, m_projects_items){
+ bool enabled = item->data(0, Qt::UserRole).toBool();
+ item->setHidden(!enabled && checked);
+ }
+
// Update counts for all projects
/*if (isAdvancedView()){
- for(QTreeWidgetItem* item_project:qAsConst(m_projects_items)){
+ for(QTreeWidgetItem* item_project:std::as_const(m_projects_items)){
if (item_project->isExpanded()){
updateCountsForProject(m_projects_items.key(item_project));
}
diff --git a/client/src/widgets/ProjectNavigator.h b/client/src/widgets/ProjectNavigator.h
index d25a9399..237e65f8 100644
--- a/client/src/widgets/ProjectNavigator.h
+++ b/client/src/widgets/ProjectNavigator.h
@@ -91,6 +91,7 @@ class ProjectNavigator : public QWidget
QTreeWidgetItem* getProjectItem(const int& id_project, const TeraDataTypes& data_type = TERADATA_NONE);
QTreeWidgetItem* getProjectForItem(const QTreeWidgetItem *item);
+ QTreeWidgetItem* getParticipantGroupForItem(const QTreeWidgetItem* item);
bool isParticipantFiltered(const QString &part_uuid);
bool isAdvancedView();
diff --git a/client/src/widgets/ProjectNavigator.ui b/client/src/widgets/ProjectNavigator.ui
index c66c8b44..5f31b0c3 100644
--- a/client/src/widgets/ProjectNavigator.ui
+++ b/client/src/widgets/ProjectNavigator.ui
@@ -15,16 +15,16 @@
- 0
+ 2
- 0
+ 5
- 0
+ 2
- 0
+ 5
-
@@ -381,7 +381,7 @@
- :/icons/details.png:/icons/details.png
+ :/icons/navtree.png:/icons/navtree.png
@@ -448,15 +448,14 @@
PointingHandCursor
- Afficher / masquer les participants inactifs
+ Afficher / masquer les éléments inactifs
...
- :/icons/patient.png
- :/icons/patient_installed.png:/icons/patient.png
+ :/icons/filter.png:/icons/filter.png
diff --git a/client/src/widgets/ProjectNavigatorTree.cpp b/client/src/widgets/ProjectNavigatorTree.cpp
index f956d101..07c98f51 100644
--- a/client/src/widgets/ProjectNavigatorTree.cpp
+++ b/client/src/widgets/ProjectNavigatorTree.cpp
@@ -18,7 +18,7 @@ void ProjectNavigatorTree::dropEvent(QDropEvent *event)
}
QTreeWidgetItem* dropped_item = currentItem();
- QTreeWidgetItem* target_item = itemAt(event->pos());
+ QTreeWidgetItem* target_item = itemAt(event->position().toPoint());
if (!target_item){
event->ignore();
@@ -53,7 +53,7 @@ void ProjectNavigatorTree::dragMoveEvent(QDragMoveEvent *event)
}
// Check allowed types
- QTreeWidgetItem* target_item = itemAt(event->pos());
+ QTreeWidgetItem* target_item = itemAt(event->position().toPoint());
if (target_item){
if (dragged_item->parent() == target_item){
event->ignore();
diff --git a/client/src/widgets/ResultMessageWidget.cpp b/client/src/widgets/ResultMessageWidget.cpp
index 9ba9eed2..f157db4f 100644
--- a/client/src/widgets/ResultMessageWidget.cpp
+++ b/client/src/widgets/ResultMessageWidget.cpp
@@ -43,7 +43,7 @@ bool ResultMessageWidget::hasMessagesWaiting(const Message::MessageType &msg_typ
return m_messages.isEmpty();
// Otherwise, we look for message of that type in the queue
- for (Message msg:qAsConst(m_messages)){
+ for (Message msg:std::as_const(m_messages)){
if (msg.getMessageType() == msg_type)
return true;
}
diff --git a/client/src/widgets/SessionInviteWidget.cpp b/client/src/widgets/SessionInviteWidget.cpp
index ed6e59df..58c4018f 100644
--- a/client/src/widgets/SessionInviteWidget.cpp
+++ b/client/src/widgets/SessionInviteWidget.cpp
@@ -1050,6 +1050,6 @@ void SessionInviteWidget::on_txtSearchInvitees_textChanged(const QString &arg1)
{
Q_UNUSED(arg1)
// Check if search field is empty
- setSearching(ui->txtSearchInvitees->text().count()>0);
+ setSearching(ui->txtSearchInvitees->text().size()>0);
updateFilters();
}
diff --git a/client/src/widgets/SessionInviteWidget.h b/client/src/widgets/SessionInviteWidget.h
index c9f7385f..9a6dc6eb 100644
--- a/client/src/widgets/SessionInviteWidget.h
+++ b/client/src/widgets/SessionInviteWidget.h
@@ -9,7 +9,7 @@
#include "GlobalMessageBox.h"
#include "managers/ComManager.h"
-#define MAX_INVITEES_IN_SESSION 5
+#define MAX_INVITEES_IN_SESSION 6
namespace Ui {
class SessionInviteWidget;
diff --git a/client/src/widgets/SessionInviteWidget.ui b/client/src/widgets/SessionInviteWidget.ui
index 2e5e66f5..e8790d3e 100644
--- a/client/src/widgets/SessionInviteWidget.ui
+++ b/client/src/widgets/SessionInviteWidget.ui
@@ -253,7 +253,7 @@
- 0
+ 6
0
diff --git a/client/src/widgets/SessionsListWidget.cpp b/client/src/widgets/SessionsListWidget.cpp
index d7bdc45d..0e0bf007 100644
--- a/client/src/widgets/SessionsListWidget.cpp
+++ b/client/src/widgets/SessionsListWidget.cpp
@@ -164,7 +164,7 @@ const TeraData *SessionsListWidget::hasResumableSession(const int &id_session_ty
{
TeraData *rval = nullptr;
// Check if we have a session that can be resumed for that date
- for(TeraData* session:qAsConst(m_ids_sessions)){
+ for(TeraData* session:std::as_const(m_ids_sessions)){
if (id_session_type == session->getFieldValue("id_session_type").toInt()){
int session_status = session->getFieldValue("session_status").toInt();
if (session_status == TeraSessionStatus::STATUS_INPROGRESS || session_status == TeraSessionStatus::STATUS_NOTSTARTED){
@@ -387,14 +387,20 @@ void SessionsListWidget::on_btnNextCal_clicked()
void SessionsListWidget::updateCalendars(QDate left_date)
{
ui->calMonth1->setCurrentPage(left_date.year(),left_date.month());
+ ui->calMonth1->setMinimumDate(QDate(left_date.year(),left_date.month(), 1));
+ ui->calMonth1->setMaximumDate(QDate(left_date.year(),left_date.month(), left_date.daysInMonth()));
ui->lblMonth1->setText(Utils::toCamelCase(QLocale().monthName(left_date.month())) + " " + QString::number(left_date.year()));
left_date = left_date.addMonths(1);
ui->calMonth2->setCurrentPage(left_date.year(),left_date.month());
+ ui->calMonth2->setMinimumDate(QDate(left_date.year(),left_date.month(), 1));
+ ui->calMonth2->setMaximumDate(QDate(left_date.year(),left_date.month(), left_date.daysInMonth()));
ui->lblMonth2->setText(Utils::toCamelCase(QLocale().monthName(left_date.month())) + " " + QString::number(left_date.year()));
left_date = left_date.addMonths(1);
ui->calMonth3->setCurrentPage(left_date.year(),left_date.month());
+ ui->calMonth3->setMinimumDate(QDate(left_date.year(),left_date.month(), 1));
+ ui->calMonth3->setMaximumDate(QDate(left_date.year(),left_date.month(), left_date.daysInMonth()));
ui->lblMonth3->setText(Utils::toCamelCase(QLocale().monthName(left_date.month())) + " " + QString::number(left_date.year()));
// Check if we must enable the previous month button
@@ -409,7 +415,7 @@ void SessionsListWidget::updateCalendars(QDate left_date)
QDate SessionsListWidget::getMinimumSessionDate()
{
QDate min_date = QDate::currentDate();
- for (TeraData* session:qAsConst(m_ids_sessions)){
+ for (TeraData* session:std::as_const(m_ids_sessions)){
QDate session_date = session->getFieldValue("session_start_datetime").toDateTime().toLocalTime().date();
if (session_date < min_date)
min_date = session_date;
@@ -420,13 +426,12 @@ QDate SessionsListWidget::getMinimumSessionDate()
QDate SessionsListWidget::getMaximumSessionDate()
{
- QDate max_date = QDate::currentDate();
- for (TeraData* session:qAsConst(m_ids_sessions)){
+ QDate max_date;
+ for (TeraData* session:std::as_const(m_ids_sessions)){
QDate session_date = session->getFieldValue("session_start_datetime").toDateTime().toLocalTime().date();
if (session_date > max_date)
max_date = session_date;
}
-
return max_date;
}
@@ -456,6 +461,7 @@ void SessionsListWidget::newSessionRequest(const QDateTime &session_datetime)
m_diag_editor->setWindowTitle(tr("Séance"));
m_diag_editor->setMinimumSize(this->width(), this->height());
+
connect(ses_widget, &SessionWidget::closeRequest, m_diag_editor, &QDialog::accept);
connect(ses_widget, &SessionWidget::dataWasChanged, m_diag_editor, &QDialog::accept);
connect(ses_widget, &SessionWidget::dataWasDeleted, m_diag_editor, &QDialog::accept);
@@ -475,7 +481,7 @@ void SessionsListWidget::setSessionsLoading(const bool &loading)
void SessionsListWidget::querySessions()
{
if (m_totalSessions == 0){
- qWarning() << "SessionsListWidget::querySessions(): No sessions to query - aborting!";
+ //qWarning() << "SessionsListWidget::querySessions(): No sessions to query - aborting!";
return;
}
ui->tableSessions->setSortingEnabled(false);
@@ -847,7 +853,7 @@ void SessionsListWidget::currentCalendarDateChanged(QDate current_date)
// Select all the sessions in the list that fits with that date
QTableWidgetItem* first_item = nullptr;
//foreach(TeraData* session, m_ids_sessions){
- for(TeraData* session: qAsConst(m_ids_sessions)){
+ for(TeraData* session: std::as_const(m_ids_sessions)){
if (session->getFieldValue("session_start_datetime").toDateTime().toLocalTime().date() == current_date){
QTableWidgetItem* session_item = m_listSessions_items.value(session->getId());
if (session_item){
diff --git a/client/src/widgets/SessionsListWidget.ui b/client/src/widgets/SessionsListWidget.ui
index 9ec204ea..413f2ade 100644
--- a/client/src/widgets/SessionsListWidget.ui
+++ b/client/src/widgets/SessionsListWidget.ui
@@ -7,7 +7,7 @@
0
0
852
- 453
+ 524
@@ -64,7 +64,7 @@
0
0
850
- 451
+ 536
@@ -104,7 +104,7 @@
16777215
- 200
+ 225
@@ -384,7 +384,7 @@
-
-
+
0
0
@@ -478,7 +478,7 @@
-
-
+
0
0
@@ -486,7 +486,7 @@
0
- 0
+ 150
@@ -541,7 +541,7 @@
-
-
+
0
0
diff --git a/client/src/widgets/TableDateWidgetItem.cpp b/client/src/widgets/TableDateWidgetItem.cpp
index 6d0c2264..a2fba2d5 100644
--- a/client/src/widgets/TableDateWidgetItem.cpp
+++ b/client/src/widgets/TableDateWidgetItem.cpp
@@ -1,18 +1,36 @@
#include "TableDateWidgetItem.h"
+TableDateWidgetItem::TableDateWidgetItem(const QDateTime &date)
+{
+ setDate(date);
+}
bool TableDateWidgetItem::operator<(const QTableWidgetItem &other) const
{
- QString current_value = this->text();
+ const TableDateWidgetItem* other_item = dynamic_cast(&other);
+ QDateTime other_date;
+ if (!other_item->m_date.isValid()){
+ other_date = QDateTime::fromString(other.text(), "dd-MM-yyyy hh:mm:ss");
+ }else{
+ other_date = other_item->m_date;
+ }
+
+ /*QString current_value = this->text();
QString other_value = other.text();
// Convert to date and compate
- return (QDateTime::fromString(current_value, "dd-MM-yyyy hh:mm:ss") < QDateTime::fromString(other_value, "dd-MM-yyyy hh:mm:ss"));
+ return (QDateTime::fromString(current_value, "dd-MM-yyyy hh:mm:ss") < QDateTime::fromString(other_value, "dd-MM-yyyy hh:mm:ss"));*/
+
+
+ if (m_date.isValid())
+ return (m_date < other_date);
+ else
+ return (QDateTime::fromString(text(), "dd-MM-yyyy hh:mm:ss") < other_date);
}
void TableDateWidgetItem::setDate(const QVariant &date_var)
{
- QDateTime date_value = date_var.toDateTime().toLocalTime();
- setText(date_value.toString("dd-MM-yyyy hh:mm:ss"));
+ m_date = date_var.toDateTime().toLocalTime();
+ setText(m_date.toString("dd-MM-yyyy hh:mm:ss"));
}
diff --git a/client/src/widgets/TableDateWidgetItem.h b/client/src/widgets/TableDateWidgetItem.h
index f803057c..4e044a42 100644
--- a/client/src/widgets/TableDateWidgetItem.h
+++ b/client/src/widgets/TableDateWidgetItem.h
@@ -4,16 +4,22 @@
#include
#include
#include
+#include
class TableDateWidgetItem : public QTableWidgetItem
{
-public:
+ public:
+
+ using QTableWidgetItem::QTableWidgetItem; // Use base class constructors
+ explicit TableDateWidgetItem(const QDateTime& date);
- using QTableWidgetItem::QTableWidgetItem; // Use base class constructors
+ bool operator<(const QTableWidgetItem &other) const override;
- bool operator<(const QTableWidgetItem &other) const override;
+ void setDate(const QVariant &date_var);
- void setDate(const QVariant &date_var);
+ private:
+ QDateTime m_date;
};
+
#endif // TABLEDATEWIDGETITEM_H
diff --git a/client/src/widgets/TestsWidget.cpp b/client/src/widgets/TestsWidget.cpp
index 15cb5974..dedeffa9 100644
--- a/client/src/widgets/TestsWidget.cpp
+++ b/client/src/widgets/TestsWidget.cpp
@@ -323,6 +323,149 @@ void TestsWidget::updateTestsCountLabel()
ui->btnDownloadAll->setEnabled(m_tests.count()>0);
}
+void TestsWidget::downloadTests(const QList tests)
+{
+
+ if (tests.isEmpty()) return;
+
+ GlobalMessageBox msg(this);
+
+ // Query for file to save
+ QString full_path;
+ QString filename = ""; // Generate default filename
+ if (tests.first()->hasFieldName("test_participant")){
+ QString clean_name = Utils::removeNonAlphanumerics(tests.first()->getFieldValue("test_participant").toString());
+ filename += clean_name;
+ if (!filename.endsWith("_"))
+ filename += "_";
+ }
+ if (m_viewMode == VIEWMODE_SESSION){
+ if (tests.first()->hasFieldName("test_session_name")){
+ QString clean_name = Utils::removeNonAlphanumerics(tests.first()->getFieldValue("test_session_name").toString());
+ filename += clean_name;
+ if (!filename.endsWith("_"))
+ filename += "_";
+ }
+ }
+ filename += "tests.csv";
+
+ m_fileDialog.selectFile(filename);
+ m_fileDialog.setFileMode(QFileDialog::AnyFile);
+ m_fileDialog.setWindowTitle(tr("Fichier à enregistrer"));
+ m_fileDialog.setAcceptMode(QFileDialog::AcceptSave);
+
+ if (m_fileDialog.exec()){
+ QStringList selected_files = m_fileDialog.selectedFiles();
+ if (selected_files.isEmpty())
+ return;
+ full_path = selected_files.first();
+ }else{
+ return;
+ }
+
+ // Get all variables in the json fields
+ QStringList columns;
+ QStringList variables;
+ for (TeraData* test:std::as_const(tests)){
+ // Parse json result
+ if (test->hasFieldName("test_summary")){
+ QJsonDocument test_summary_doc = QJsonDocument::fromJson(test->getFieldValue("test_summary").toString().toUtf8());
+ if (!test_summary_doc.isNull()){
+ QVariantMap test_summary = test_summary_doc.object().toVariantMap();
+ QVariantMap::const_iterator test_result = test_summary.constBegin();
+ while (test_result != test_summary.constEnd()) {
+ if (!variables.contains(test_result.key()))
+ variables << test_result.key();
+ ++test_result;
+ }
+ }
+ }
+
+ }
+
+ columns << "Participant" << "User" << "Device" << "Service" << "Session" << "TestType" << "Status" << "Name" << "Date" << "Time"; // Basic columns
+
+ // Format and save to csv
+ QFile csv_file(full_path);
+
+ if (csv_file.open(QIODevice::WriteOnly| QIODevice::Text)){
+ QTextStream csv_writer(&csv_file);
+
+ for (const QString &col: std::as_const(columns))
+ csv_writer << col << '\t';
+
+ for (const QString &var: std::as_const(variables))
+ csv_writer << var << '\t';
+ csv_writer << Qt::endl;
+
+ for (TeraData* test:tests){
+
+ // Creator
+ if (test->hasFieldName("test_participant")){
+ csv_writer << test->getFieldValue("test_participant").toString();
+ }
+ csv_writer << '\t';
+ if (test->hasFieldName("test_user")){
+ csv_writer << test->getFieldValue("test_user").toString();
+ }
+ csv_writer << '\t';
+ if (test->hasFieldName("test_device")){
+ csv_writer << test->getFieldValue("test_device").toString();
+ }
+ csv_writer << '\t';
+ if (test->hasFieldName("test_service")){
+ csv_writer << test->getFieldValue("test_service").toString();
+ }
+ csv_writer << '\t';
+
+ // Test infos
+ if (test->hasFieldName("test_session_name")){
+ csv_writer << test->getFieldValue("test_session_name").toString();
+ }
+ csv_writer << '\t';
+ if (test->hasFieldName("id_test_type")){
+ csv_writer << test->getFieldValue("id_test_type").toString();
+ }
+ csv_writer << '\t';
+ if (test->hasFieldName("test_status")){
+ csv_writer << test->getFieldValue("test_status").toString();
+ }
+ csv_writer << '\t';
+ if (test->hasFieldName("test_name")){
+ csv_writer << test->getFieldValue("test_name").toString();
+ }
+ csv_writer << '\t';
+ if (test->hasFieldName("test_datetime")){
+ csv_writer << test->getFieldValue("test_datetime").toDateTime().toString("yyyy-MM-dd");
+ csv_writer << '\t';
+ csv_writer << test->getFieldValue("test_datetime").toDateTime().toString("hh:mm:ss");
+ }
+ csv_writer << '\t';
+ if (test->hasFieldName("test_summary")){
+ QJsonDocument test_summary_doc = QJsonDocument::fromJson(test->getFieldValue("test_summary").toString().toUtf8());
+ if (!test_summary_doc.isNull()){
+ QVariantMap test_summary = test_summary_doc.object().toVariantMap();
+ for (const QString &var: std::as_const(variables)){
+ if (test_summary.contains(var)){
+ csv_writer < tests, QUrlQuery reply_query)
{
if (reply_query.hasQueryItem(WEB_QUERY_WITH_ONLY_TOKEN)){
@@ -368,7 +511,7 @@ void TestsWidget::processServicesReply(QList services, QUrlQuery reply
// Check if project is in service_fields
if (service.hasFieldName("service_projects")){
QVariantList projects = service.getFieldValue("service_projects").toList();
- for (const QVariant &project:qAsConst(projects)){
+ for (const QVariant &project:std::as_const(projects)){
QVariantMap project_info = project.toMap();
if (project_info["id_project"].toInt() == m_idProject){
// Ok, we are allowed to use file transfer service
@@ -388,7 +531,7 @@ void TestsWidget::comDeleteDataReply(QString path, int id)
{
if (path == WEB_TESTINFO_PATH){
// Remove test from list
- for(TeraData* test_info:qAsConst(m_tests)){
+ for(TeraData* test_info:std::as_const(m_tests)){
if (test_info->getId() == id){
QString test_uuid = test_info->getUuid();
ui->tableTests->removeRow(m_tableTests[test_uuid]->row());
@@ -413,105 +556,6 @@ void TestsWidget::nextMessageWasShown(Message current_message)
}
}
-/*void AssetsWidget::processAssetsInfos(QList infos, QUrlQuery reply_query, QString reply_path)
-{
- for (const QJsonObject &asset_info:qAsConst(infos)){
- QString asset_uuid = asset_info["asset_uuid"].toString();
-
- if (!m_treeAssets.contains(asset_uuid)){
- // Create a new asset, if possible (should happen if we posted a new asset)
- TeraData asset(TERADATA_ASSET, asset_info);
- updateAsset(asset); // TODO: manage participant association, if required by the view
- }
-
- if (m_treeAssets.contains(asset_uuid)){
- QTreeWidgetItem* asset_item = m_treeAssets[asset_uuid];
-
- if (asset_info.contains("asset_file_size")){
-
- asset_item->setText(AssetColumn::ASSET_SIZE, Utils::formatFileSize(asset_info["asset_file_size"].toInt()));
- ui->treeAssets->showColumn(AssetColumn::ASSET_SIZE);
- }
-
- if (asset_info.contains("file_size")){
- asset_item->setText(AssetColumn::ASSET_SIZE, Utils::formatFileSize(asset_info["file_size"].toInt()));
- ui->treeAssets->showColumn(AssetColumn::ASSET_SIZE);
- }
-
- if (asset_info.contains("video_duration")){
- asset_item->setText(AssetColumn::ASSET_DURATION, Utils::formatDuration(asset_info["video_duration"].toString()));
- ui->treeAssets->showColumn(AssetColumn::ASSET_DURATION);
- }
- }
-
- if (m_assets.contains(asset_uuid)){
- // Append received fields to current asset
- TeraData* asset = m_assets[asset_uuid];
- asset->updateFrom(asset_info);
- }
- }
- resizeAssetsColumnsToContent();
-
- setLoading(false);
-}
-
-void AssetsWidget::refreshAccessToken()
-{
- if (!m_comManager)
- return;
-
- QUrlQuery query = m_dataQuery; // Original data query
-
- query.addQueryItem(WEB_QUERY_WITH_ONLY_TOKEN, "1");
- m_comManager->doGet(WEB_ASSETINFO_PATH, query);
-}
-
-void AssetsWidget::on_treeAssets_itemSelectionChanged()
-{
- bool at_least_one_asset_selected = false;
-
- // Make sure we don't have only "labels" items (session, participant, ...) selected
- const QList selected_items = ui->treeAssets->selectedItems();
- for(QTreeWidgetItem* item:selected_items){
- if (!m_treeAssets.key(item).isEmpty() ){
- at_least_one_asset_selected = true;
- break;
- }
- }
- ui->btnDelete->setEnabled(at_least_one_asset_selected);
- ui->btnDownload->setEnabled(at_least_one_asset_selected);
-}
-
-
-void AssetsWidget::on_btnNew_clicked()
-{
- // Upload a new asset to the FileTransfer service
- if (!m_fileTransferServiceInfos || !m_comAssetManager || !m_comManager){
- return; // Should not happen at this point.
- }
-
- if (m_uploadDialog){
- m_uploadDialog->deleteLater();
- }
-
- // Open upload dialog
- m_uploadDialog = new FileUploaderDialog(tr("Tous (*.*)"), dynamic_cast(this));
- if (m_uploadDialog->result() == QDialog::Rejected){
- // No file selected - no need to upload anything!
- m_uploadDialog->deleteLater();
- m_uploadDialog = nullptr;
- return;
- }
- m_uploadDialog->setMinimumWidth(2*this->width()/3);
-
- connect(m_uploadDialog, &FileUploaderDialog::finished, this, &AssetsWidget::fileUploaderFinished);
-
- m_uploadDialog->setModal(true);
- m_uploadDialog->show();
-
-
-}*/
-
void TestsWidget::on_btnDelete_clicked()
{
// Check if the sender is a QToolButton (from the action column)
@@ -551,7 +595,9 @@ void TestsWidget::on_btnDelete_clicked()
void TestsWidget::on_tableTests_itemSelectionChanged()
{
- ui->btnDelete->setEnabled(!ui->tableTests->selectedItems().isEmpty());
+ bool has_selection = !ui->tableTests->selectedItems().isEmpty();
+ ui->btnDelete->setEnabled(has_selection);
+ ui->btnDownload->setEnabled(has_selection);
// Display / hide summary
ui->tableTestSummary->setVisible(ui->tableTests->selectionModel()->selectedRows().count() == 1);
@@ -560,150 +606,37 @@ void TestsWidget::on_tableTests_itemSelectionChanged()
QString test_uuid = m_tableTests.key(ui->tableTests->item(ui->tableTests->currentRow(), TEST_NAME_COLUMN));
showTestSummary(test_uuid);
}
+
}
void TestsWidget::on_btnDownloadAll_clicked()
{
if (m_tests.isEmpty()) return; // Should not happen
- GlobalMessageBox msg(this);
+ QList tests;
- // Query for file to save
- QString full_path;
- QString filename = ""; // Generate default filename
- if (m_tests.first()->hasFieldName("test_participant")){
- QString clean_name = Utils::removeNonAlphanumerics(m_tests.first()->getFieldValue("test_participant").toString());
- filename += clean_name;
- if (!filename.endsWith("_"))
- filename += "_";
+ // Browse table items to have sorted list (the order it will be exported)
+ for (int i=0; itableTests->rowCount(); i++){
+ TeraData* test = m_tests[m_tableTests.key(ui->tableTests->item(i,0))];
+ tests.append(test);
}
- if (m_viewMode == VIEWMODE_SESSION){
- if (m_tests.first()->hasFieldName("test_session_name")){
- QString clean_name = Utils::removeNonAlphanumerics(m_tests.first()->getFieldValue("test_session_name").toString());
- filename += clean_name;
- if (!filename.endsWith("_"))
- filename += "_";
- }
- }
- filename += "tests.csv";
-
- m_fileDialog.selectFile(filename);
- m_fileDialog.setFileMode(QFileDialog::AnyFile);
- m_fileDialog.setWindowTitle(tr("Fichier à enregistrer"));
- m_fileDialog.setAcceptMode(QFileDialog::AcceptSave);
-
- if (m_fileDialog.exec()){
- QStringList selected_files = m_fileDialog.selectedFiles();
- if (selected_files.isEmpty())
- return;
- full_path = selected_files.first();
- }else{
- return;
- }
-
- // Get all variables in the json fields
- QStringList columns;
- QStringList variables;
- for (TeraData* test:qAsConst(m_tests)){
- // Parse json result
- if (test->hasFieldName("test_summary")){
- QJsonDocument test_summary_doc = QJsonDocument::fromJson(test->getFieldValue("test_summary").toString().toUtf8());
- if (!test_summary_doc.isNull()){
- QVariantMap test_summary = test_summary_doc.object().toVariantMap();
- QVariantMap::const_iterator test_result = test_summary.constBegin();
- while (test_result != test_summary.constEnd()) {
- if (!variables.contains(test_result.key()))
- variables << test_result.key();
- ++test_result;
- }
- }
- }
-
- }
-
- columns << "Participant" << "User" << "Device" << "Service" << "Session" << "TestType" << "Status" << "Name" << "Date" << "Time"; // Basic columns
-
- // Format and save to csv
- QFile csv_file(full_path);
-
- if (csv_file.open(QIODevice::WriteOnly| QIODevice::Text)){
- QTextStream csv_writer(&csv_file);
-
- for (const QString &col: qAsConst(columns))
- csv_writer << col << '\t';
-
- for (const QString &var: qAsConst(variables))
- csv_writer << var << '\t';
- csv_writer << Qt::endl;
+ downloadTests(tests);
+}
- for (int i=0; itableTests->rowCount(); i++){
- // Use the data in the table to keep received order of items
- TeraData* test = m_tests[m_tableTests.key(ui->tableTests->item(i,0))];
- // Creator
- if (test->hasFieldName("test_participant")){
- csv_writer << test->getFieldValue("test_participant").toString();
- }
- csv_writer << '\t';
- if (test->hasFieldName("test_user")){
- csv_writer << test->getFieldValue("test_user").toString();
- }
- csv_writer << '\t';
- if (test->hasFieldName("test_device")){
- csv_writer << test->getFieldValue("test_device").toString();
- }
- csv_writer << '\t';
- if (test->hasFieldName("test_service")){
- csv_writer << test->getFieldValue("test_service").toString();
- }
- csv_writer << '\t';
+void TestsWidget::on_btnDownload_clicked()
+{
+ if (m_tests.isEmpty() || ui->tableTests->selectedItems().isEmpty()) return; // Should not happen
- // Test infos
- if (test->hasFieldName("test_session_name")){
- csv_writer << test->getFieldValue("test_session_name").toString();
- }
- csv_writer << '\t';
- if (test->hasFieldName("id_test_type")){
- csv_writer << test->getFieldValue("id_test_type").toString();
- }
- csv_writer << '\t';
- if (test->hasFieldName("test_status")){
- csv_writer << test->getFieldValue("test_status").toString();
- }
- csv_writer << '\t';
- if (test->hasFieldName("test_name")){
- csv_writer << test->getFieldValue("test_name").toString();
- }
- csv_writer << '\t';
- if (test->hasFieldName("test_datetime")){
- csv_writer << test->getFieldValue("test_datetime").toDateTime().toString("yyyy-MM-dd");
- csv_writer << '\t';
- csv_writer << test->getFieldValue("test_datetime").toDateTime().toString("hh:mm:ss");
- }
- csv_writer << '\t';
- if (test->hasFieldName("test_summary")){
- QJsonDocument test_summary_doc = QJsonDocument::fromJson(test->getFieldValue("test_summary").toString().toUtf8());
- if (!test_summary_doc.isNull()){
- QVariantMap test_summary = test_summary_doc.object().toVariantMap();
- for (const QString &var: qAsConst(variables)){
- if (test_summary.contains(var)){
- csv_writer < tests;
+ // Browse table items to have sorted list (the order it will be exported)
+ for (int i=0; itableTests->selectedItems().count(); i++){
+ if (m_tableTests.key(ui->tableTests->selectedItems().at(i), nullptr) != nullptr){
+ TeraData* test = m_tests[m_tableTests.key(ui->tableTests->selectedItems().at(i))];
+ tests.append(test);
}
- csv_file.close();
- }else{
- msg.showError(tr("Erreur d'exportation"), tr("Impossible d'exporter les données dans le fichier.") + "\n\r" + tr("Le fichier est peut-être ouvert dans une autre application?"));
- return;
}
-
- msg.showInfo(tr("Exportation terminée"), tr("L'exportation des données a été complétée avec succès."));
-
-
+ downloadTests(tests);
}
diff --git a/client/src/widgets/TestsWidget.h b/client/src/widgets/TestsWidget.h
index 5ed5d561..12cc64ae 100644
--- a/client/src/widgets/TestsWidget.h
+++ b/client/src/widgets/TestsWidget.h
@@ -81,23 +81,22 @@ class TestsWidget : public QWidget
void setLoading(const bool &loading, const QString &msg = QString(), const bool &hide_ui = false);
void showTestSummary(const QString& test_uuid);
-
void updateTestsCountLabel();
+ void downloadTests(const QList tests);
+
private slots:
void processTestsReply(QList tests, QUrlQuery reply_query);
void processServicesReply(QList services, QUrlQuery reply_query);
void comDeleteDataReply(QString path, int id);
-
void nextMessageWasShown(Message current_message);
-
void on_btnDelete_clicked();
-
void on_tableTests_itemSelectionChanged();
void on_btnDownloadAll_clicked();
+ void on_btnDownload_clicked();
signals:
void testCountChanged(int new_count);
diff --git a/client/src/widgets/TestsWidget.ui b/client/src/widgets/TestsWidget.ui
index 8f444253..f575c5f2 100644
--- a/client/src/widgets/TestsWidget.ui
+++ b/client/src/widgets/TestsWidget.ui
@@ -209,6 +209,38 @@
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+ PointingHandCursor
+
+
+ Exporter la sélection
+
+
+
+ :/icons/download.png:/icons/download.png
+
+
+
+ 24
+ 24
+
+
+
+ Qt::ToolButtonTextBesideIcon
+
+
+
-
@@ -218,7 +250,7 @@
PointingHandCursor
- Exporter
+ Tout exporter
diff --git a/docs/Home.rst b/docs/Home.rst
new file mode 100644
index 00000000..6e034020
--- /dev/null
+++ b/docs/Home.rst
@@ -0,0 +1,3 @@
+.. include:: ../README_fr.md
+ :parser: myst_parser.sphinx_
+ :start-line: 2
\ No newline at end of file
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 00000000..d4bb2cbb
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 00000000..c5efc315
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,41 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = 'OpenTeraPlus'
+copyright = '2023, Simon Brière, Dominic Létourneau'
+author = 'Simon Brière, Dominic Létourneau'
+release = '1.1.3'
+version = release
+
+html_logo = 'logo/LogoOpenTeraPlus.png'
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = ['myst_parser', 'sphinx_rtd_theme', 'sphinxcontrib.openapi', 'sphinx.ext.autosummary']
+
+templates_path = ['_templates']
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'venv']
+
+locale_dirs = ['locale/']
+language = 'fr' # Default language
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_show_sourcelink = False
+html_theme = 'sphinx_rtd_theme'
+html_theme_options = {
+ 'navigation_depth': -1,
+ 'display_version': True
+}
+
+source_suffix = {
+ '.rst': 'restructuredtext',
+ '.md': 'markdown',
+}
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 00000000..9b02804a
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,18 @@
+.. toctree::
+ :maxdepth: 2
+ :hidden:
+ :caption: Introduction
+
+.. toctree::
+ :maxdepth: 5
+ :hidden:
+ :caption: Manuel d'utilisation
+
+ users/Troubleshooting
+
+.. toctree::
+ :maxdepth: 5
+ :hidden:
+ :caption: Développeurs
+
+.. include:: Home.rst
diff --git a/docs/locale/en/LC_MESSAGES/index.po b/docs/locale/en/LC_MESSAGES/index.po
new file mode 100644
index 00000000..ef591f1a
--- /dev/null
+++ b/docs/locale/en/LC_MESSAGES/index.po
@@ -0,0 +1,56 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2023, Simon Brière, Dominic Létourneau
+# This file is distributed under the same license as the OpenTeraPlus
+# package.
+# FIRST AUTHOR , 2023.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenTeraPlus 1.1.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-10-30 09:14-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language: en\n"
+"Language-Team: en \n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.13.1\n"
+
+#: ../../index.rst:1
+msgid "Introduction"
+msgstr ""
+
+#: ../../index.rst:6
+msgid "Utilisateurs"
+msgstr ""
+
+#: ../../index.rst:13
+msgid "Développeurs"
+msgstr ""
+
+#: ../../index.rst:19
+msgid "Indices and tables"
+msgstr ""
+
+#: ../../index.rst:21
+msgid ":ref:`genindex`"
+msgstr ""
+
+#: ../../index.rst:22
+msgid ":ref:`modindex`"
+msgstr ""
+
+#: ../../index.rst:23
+msgid ":ref:`search`"
+msgstr ""
+
+#~ msgid "Contents:"
+#~ msgstr ""
+
+#~ msgid "Welcome to OpenTeraPlus's documentation!"
+#~ msgstr ""
+
diff --git a/docs/locale/en/LC_MESSAGES/users.po b/docs/locale/en/LC_MESSAGES/users.po
new file mode 100644
index 00000000..2786b59d
--- /dev/null
+++ b/docs/locale/en/LC_MESSAGES/users.po
@@ -0,0 +1,502 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2023, Simon Brière, Dominic Létourneau
+# This file is distributed under the same license as the OpenTeraPlus
+# package.
+# FIRST AUTHOR , 2023.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenTeraPlus 1.1.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-10-30 09:14-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language: en\n"
+"Language-Team: en \n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.13.1\n"
+
+#: ../../users/Troubleshooting.md:1
+msgid "Problèmes et solutions"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:3
+msgid "Démarrage du logiciel"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:4
+msgid "Connexion"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:5
+msgid "1. *Utilisateur ou mot de passe invalide*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:6
+msgid "Vérifiez votre code utilisateur et votre mot de passe"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:7
+msgid "Validez auprès de votre administrateur si votre compte est toujours actif"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:9
+msgid "2. *Impossible de rejoindre le serveur*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:10
+msgid ""
+"Vérifiez que votre ordinateur est bien connecté à Internet (en ouvrant un"
+" navigateur et en effectuant une recherche, par exemple)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:11
+msgid ""
+"Assurez-vous que votre ordinateur est bien connecté sur le bon réseau "
+"Internet"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:12
+msgid ""
+"Si nécessaire, assurez-vous que les politiques en place dans votre "
+"établissement permettent bien l’utilisation du logiciel (i.e. aucun port "
+"bloqué, aucun anti-virus qui empêche l'exécution adéquate du logiciel)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:14
+msgid "3. *Message d’erreur : « Déjà connecté au logiciel »*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:15
+msgid "Vérifiez que le logiciel n’est pas déjà ouvert sur votre poste de travail"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:16
+msgid ""
+"Si vous utilisez plusieurs postes, assurez-vous que vous n’êtes pas "
+"connecté sur un autre poste"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:17
+msgid "Assurez-vous que personne d’autre n’utilise votre compte utilisateur"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:18
+msgid ""
+"Si vous ne savez pas où vous êtes connecté, contactez votre "
+"administrateur qui pourra désactiver votre compte, changer le mot de "
+"passe et le réactiver"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:20
+msgid "Séance de télésanté"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:21
+msgid "Téléréadaptation ou autre, basée sur le service de *VideoRehab*."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:23
+msgid "Démarrage de séance"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:25
+msgid "1. *Pas d’image vidéo dans le vestibule de la séance*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:26
+msgid "Vérifiez qu’il n’y a pas de cache-caméra sur votre caméra"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:27
+msgid ""
+"Vérifiez que votre caméra est bien branchée sur votre appareil s’il "
+"s’agit d’une caméra externe"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:28
+msgid ""
+"Assurez-vous qu’aucun autre logiciel présentement ouvert n’utilise votre "
+"caméra (comme Microsoft Teams, Zoom ou autres)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:29
+msgid ""
+"Assurez-vous que la bonne source vidéo est sélectionnée (en bas de la "
+"zone d’image)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:31
+msgid "2. *Pas de son dans le vestibule de séance*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:32
+msgid "La barre de son à gauche ne s’affiche ou ne bouge pas lorsque vous parlez."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:33
+msgid ""
+"Si vous utilisez un microphone externe, assurez-vous qu’il est bien "
+"branché"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:34
+msgid ""
+"S’il y a lieu, assurez-vous que le bouton « mute » n’est pas activé sur "
+"votre microphone"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:35
+msgid ""
+"Assurez-vous que le bon microphone est sélectionné (en bas de la zone "
+"d’image)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:37
+msgid "3. *Mauvaise caméra*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:38
+msgid ""
+"Dans le vestibule, sous l’image de la caméra, sélectionnez la bonne "
+"caméra. N’oubliez pas d’enregistrer les paramètres par défaut si vous "
+"souhaitez toujours utiliser cette caméra !"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:40
+msgid "4. *Participant ne se joint jamais à la séance*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:41
+msgid ""
+"Assurez-vous que le participant était bien en ligne (icône verte) au "
+"démarrage de la séance."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:42
+msgid "Contactez le participant et vérifiez :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:43
+msgid "Qu’il a bien ouvert le lien fourni et qu’il se voit sur son écran"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:44
+msgid ""
+"Qu’il ait bien accepté de partager son microphone et sa caméra lorsque la"
+" question lui sera demandée"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:46
+msgid "Pendant la séance"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:48
+msgid "1. *Le participant n’entend pas ce que vous dites*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:49
+msgid ""
+"Assurez-vous que votre microphone est bien allumé et pas en « mute » "
+"(voir « Pas de son dans le vestibule de séance ») plus haut"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:50
+msgid ""
+"Assurez-vous que vous n’avez pas activé l’icône pour désactiver le "
+"microphone dans le logiciel"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:51
+msgid ""
+"Assurez-vous que la bonne source audio est sélectionnée dans les "
+"paramètres (icône « engrenage » sous votre image)."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:52 ../../users/Troubleshooting.md:67
+#: ../../users/Troubleshooting.md:74
+msgid "Cliquez sur le bouton « Reconnecter » en haut"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:54
+msgid "2. *Vous n’entendez pas le participant*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:55
+msgid ""
+"Assurez-vous que le volume de votre poste est bien allumé et à une valeur"
+" plus grande que 0"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:56
+msgid ""
+"Assurez-vous que votre icône « haut-parleur » dans le logiciel est bien "
+"active"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:57
+msgid ""
+"Si le participant utilise un microphone externe (tel un casque d’écoute),"
+" assurez-vous :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:58
+msgid "Qu’il est bien allumé"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:59
+msgid "Qu’il ne soit pas à « mute »"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:60
+msgid "Bien connecté à l’appareil"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:61
+msgid ""
+"Assurez-vous que le participant a bien la bonne source de microphone en "
+"cliquant sur l’icône « engrenage » sous son image et en changeant sa "
+"source audio principale"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:63
+msgid "3. *Le participant ne vous voit pas*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:64
+msgid "Assurez-vous que vous voyez votre propre image"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:65
+msgid ""
+"Si ce n’est pas le cas, validez les étapes identifiées plus haut sous « "
+"Pas d’image vidéo dans le vestibule de la séance »)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:66
+msgid "Assurez-vous que le bouton « caméra » est bien activé dans le logiciel"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:68 ../../users/Troubleshooting.md:75
+#: ../../users/Troubleshooting.md:91 ../../users/Troubleshooting.md:112
+msgid ""
+"Demandez au participant de rafraichir sa page de son côté (la façon de "
+"faire variera selon l’appareil et le navigateur utilisé) ou de cliquer "
+"sur le bouton « Déconnecter » en haut à droite et de suivre à nouveau le "
+"lien que vous lui avez envoyé"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:70
+msgid "4. *Vous ne voyez pas l’image du participant, mais vous l’entendez*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:71
+msgid "Si le participant vous entend, validez qu’il se voit"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:72
+msgid ""
+"S’il ne se voit pas, assurez-vous que l’icône « caméra » sous son image "
+"est bien activée"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:73
+msgid ""
+"Dans les paramètres du participant (icône « engrenage » sous son image), "
+"assurez-vous que la bonne caméra est sélectionnée"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:77
+msgid "5. *Coupures de son / qualité vidéo dégradée*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:78
+msgid ""
+"Ces problèmes sont dus à une mauvaise qualité de connexion Internet, que "
+"ce soit du côté du professionnel ou du participant. Quelques ajustements "
+"et validations pouvant être faites :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:79
+msgid ""
+"Si vous êtes sur un réseau sans fil et qu’un réseau filaire est "
+"disponible, tentez de brancher votre appareil sur ce réseau"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:80
+msgid ""
+"Assurez-vous que personne d’autre au domicile du participant n’utilise la"
+" connexion Internet en même temps que la séance pour y faire du "
+"téléchargement, du visionnement en ligne (« streaming ») ou jouer à des "
+"jeux vidéo en ligne"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:81
+msgid ""
+"Si le participant se connecte à Internet via une connexion de type « "
+"cellulaire », demandez-lui, si possible de se connecter avec une "
+"connexion de type sans-fil (non-cellulaire) ou filaire"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:82
+msgid ""
+"Si possible, demandez au participant de changer de pièce. Idéalement, "
+"s’il sait où se trouve son point d’accès Internet (routeur et/ou modem), "
+"demandez-lui de s’y rapprocher."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:83
+msgid ""
+"En dernier recours, activez et désactivez les caméras dans le logiciel et"
+" activez-les uniquement si nécessaire"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:84
+msgid "Si le problème persiste :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:85
+msgid ""
+"Si le problème revient constamment avec tous les participants, il faudra "
+"peut-être vérifier la connexion Internet du poste clinicien"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:86
+msgid ""
+"Si le problème revient constamment avec un participant donné, le problème"
+" se trouve probablement de son côté et vérifier la connexion Internet de "
+"celui-ci. Un redémarrage du modem / routeur peut parfois résoudre les "
+"problèmes."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:88
+msgid "6. *Tout autre problème*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:89
+msgid ""
+"La plupart des autres problèmes pouvant survenir peuvent être réglés avec"
+" ces étapes :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:90
+msgid "Cliquez sur le bouton « Reconnecter » en haut à gauche"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:92
+msgid "Terminez la séance et démarrez une nouvelle séance"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:94
+msgid "Problèmes du côté du participant"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:96
+msgid "1. *Message d’erreur : « Navigateur non-supporté »*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:97
+msgid ""
+"Demandez au participant d'utiliser un autre navigateur (tels que Firefox,"
+" Chrome ou Safari)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:98
+msgid "Si le participant est sur un appareil mobile:"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:99
+msgid "Demandez-lui de faire les mises à jour logicielles, s'il y a lieu"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:100
+msgid ""
+"S'il est sur un appareil de type Apple, demandez-lui d'utiliser le "
+"navigateur *Safari* pour ouvrir le lien. Sur ces appareils, aucun autre "
+"navigateur n'est supporté."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:101
+msgid ""
+"S'il n'y a pas de mise à jour disponible et que son appareil date de "
+"plusieurs années, il est possible qu'il ne soit plus supporté. Demandez-"
+"lui d'utilisateur un autre appareil si possible."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:103
+msgid "2. *Pas d’image vidéo en cliquant sur le lien*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:104
+msgid "Assurez-vous qu'il n'a pas de cache-caméra devant sa caméra"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:105
+msgid ""
+"Validez, avec le participant, qu'il a bien répondu \"Oui\" à la question "
+"qui demandait l'accès à sa caméra"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:106
+msgid "S'il a répondu non:"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:107
+msgid "Tentez de rafraichir la page du navigateur"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:108
+msgid ""
+"Si la question ne réapparait pas, la procédure variera selon les "
+"navigateurs. Il faut généralement cliquer sur l'icône \"Caméra\" en haut "
+"près de l'adresse et activer celle-ci."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:109
+msgid "Assurez-vous qu'il utilise un navigateur compatible (voir ci-dessus)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:111
+msgid ""
+"3. *Même si le professionnel démarre la séance, celle-ci ne démarre pas "
+"pour le participant*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:113
+msgid ""
+"En dernier recours, demandez au participant de redémarrer son appareil et"
+" de suivre à nouveau le lien."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:115
+msgid "4. *Le son est faible*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:116
+msgid "Vérifiez le volume de l'appareil du participant"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:117
+msgid ""
+"Même si le volume est au maximum, il se pourrait que le son soit faible. "
+"Vérifiez ces éléments:"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:118
+msgid ""
+"Assurez-vous de minimiser le bruit de fond de votre côté (personnes qui "
+"parlent, musique, bruit constant)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:119
+msgid "Assurez-vous de minimiser le bruit de font du participant"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:120
+msgid "Branchez un haut-parleur externe ou utilisez un casque d'écoute"
+msgstr ""
+
diff --git a/docs/locale/fr/LC_MESSAGES/index.mo b/docs/locale/fr/LC_MESSAGES/index.mo
new file mode 100644
index 00000000..226e2fd7
Binary files /dev/null and b/docs/locale/fr/LC_MESSAGES/index.mo differ
diff --git a/docs/locale/fr/LC_MESSAGES/index.po b/docs/locale/fr/LC_MESSAGES/index.po
new file mode 100644
index 00000000..4c68b318
--- /dev/null
+++ b/docs/locale/fr/LC_MESSAGES/index.po
@@ -0,0 +1,56 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2023, Simon Brière, Dominic Létourneau
+# This file is distributed under the same license as the OpenTeraPlus
+# package.
+# FIRST AUTHOR , 2023.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenTeraPlus 1.1.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-10-30 09:14-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language: fr\n"
+"Language-Team: fr \n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.13.1\n"
+
+#: ../../index.rst:1
+msgid "Introduction"
+msgstr ""
+
+#: ../../index.rst:6
+msgid "Utilisateurs"
+msgstr ""
+
+#: ../../index.rst:13
+msgid "Développeurs"
+msgstr ""
+
+#: ../../index.rst:19
+msgid "Indices and tables"
+msgstr ""
+
+#: ../../index.rst:21
+msgid ":ref:`genindex`"
+msgstr ""
+
+#: ../../index.rst:22
+msgid ":ref:`modindex`"
+msgstr ""
+
+#: ../../index.rst:23
+msgid ":ref:`search`"
+msgstr ""
+
+#~ msgid "Contents:"
+#~ msgstr ""
+
+#~ msgid "Welcome to OpenTeraPlus's documentation!"
+#~ msgstr ""
+
diff --git a/docs/locale/fr/LC_MESSAGES/users.mo b/docs/locale/fr/LC_MESSAGES/users.mo
new file mode 100644
index 00000000..226e2fd7
Binary files /dev/null and b/docs/locale/fr/LC_MESSAGES/users.mo differ
diff --git a/docs/locale/fr/LC_MESSAGES/users.po b/docs/locale/fr/LC_MESSAGES/users.po
new file mode 100644
index 00000000..30340a9b
--- /dev/null
+++ b/docs/locale/fr/LC_MESSAGES/users.po
@@ -0,0 +1,502 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2023, Simon Brière, Dominic Létourneau
+# This file is distributed under the same license as the OpenTeraPlus
+# package.
+# FIRST AUTHOR , 2023.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenTeraPlus 1.1.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-10-30 09:14-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language: fr\n"
+"Language-Team: fr \n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.13.1\n"
+
+#: ../../users/Troubleshooting.md:1
+msgid "Problèmes et solutions"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:3
+msgid "Démarrage du logiciel"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:4
+msgid "Connexion"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:5
+msgid "1. *Utilisateur ou mot de passe invalide*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:6
+msgid "Vérifiez votre code utilisateur et votre mot de passe"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:7
+msgid "Validez auprès de votre administrateur si votre compte est toujours actif"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:9
+msgid "2. *Impossible de rejoindre le serveur*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:10
+msgid ""
+"Vérifiez que votre ordinateur est bien connecté à Internet (en ouvrant un"
+" navigateur et en effectuant une recherche, par exemple)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:11
+msgid ""
+"Assurez-vous que votre ordinateur est bien connecté sur le bon réseau "
+"Internet"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:12
+msgid ""
+"Si nécessaire, assurez-vous que les politiques en place dans votre "
+"établissement permettent bien l’utilisation du logiciel (i.e. aucun port "
+"bloqué, aucun anti-virus qui empêche l'exécution adéquate du logiciel)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:14
+msgid "3. *Message d’erreur : « Déjà connecté au logiciel »*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:15
+msgid "Vérifiez que le logiciel n’est pas déjà ouvert sur votre poste de travail"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:16
+msgid ""
+"Si vous utilisez plusieurs postes, assurez-vous que vous n’êtes pas "
+"connecté sur un autre poste"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:17
+msgid "Assurez-vous que personne d’autre n’utilise votre compte utilisateur"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:18
+msgid ""
+"Si vous ne savez pas où vous êtes connecté, contactez votre "
+"administrateur qui pourra désactiver votre compte, changer le mot de "
+"passe et le réactiver"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:20
+msgid "Séance de télésanté"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:21
+msgid "Téléréadaptation ou autre, basée sur le service de *VideoRehab*."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:23
+msgid "Démarrage de séance"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:25
+msgid "1. *Pas d’image vidéo dans le vestibule de la séance*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:26
+msgid "Vérifiez qu’il n’y a pas de cache-caméra sur votre caméra"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:27
+msgid ""
+"Vérifiez que votre caméra est bien branchée sur votre appareil s’il "
+"s’agit d’une caméra externe"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:28
+msgid ""
+"Assurez-vous qu’aucun autre logiciel présentement ouvert n’utilise votre "
+"caméra (comme Microsoft Teams, Zoom ou autres)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:29
+msgid ""
+"Assurez-vous que la bonne source vidéo est sélectionnée (en bas de la "
+"zone d’image)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:31
+msgid "2. *Pas de son dans le vestibule de séance*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:32
+msgid "La barre de son à gauche ne s’affiche ou ne bouge pas lorsque vous parlez."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:33
+msgid ""
+"Si vous utilisez un microphone externe, assurez-vous qu’il est bien "
+"branché"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:34
+msgid ""
+"S’il y a lieu, assurez-vous que le bouton « mute » n’est pas activé sur "
+"votre microphone"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:35
+msgid ""
+"Assurez-vous que le bon microphone est sélectionné (en bas de la zone "
+"d’image)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:37
+msgid "3. *Mauvaise caméra*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:38
+msgid ""
+"Dans le vestibule, sous l’image de la caméra, sélectionnez la bonne "
+"caméra. N’oubliez pas d’enregistrer les paramètres par défaut si vous "
+"souhaitez toujours utiliser cette caméra !"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:40
+msgid "4. *Participant ne se joint jamais à la séance*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:41
+msgid ""
+"Assurez-vous que le participant était bien en ligne (icône verte) au "
+"démarrage de la séance."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:42
+msgid "Contactez le participant et vérifiez :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:43
+msgid "Qu’il a bien ouvert le lien fourni et qu’il se voit sur son écran"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:44
+msgid ""
+"Qu’il ait bien accepté de partager son microphone et sa caméra lorsque la"
+" question lui sera demandée"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:46
+msgid "Pendant la séance"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:48
+msgid "1. *Le participant n’entend pas ce que vous dites*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:49
+msgid ""
+"Assurez-vous que votre microphone est bien allumé et pas en « mute » "
+"(voir « Pas de son dans le vestibule de séance ») plus haut"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:50
+msgid ""
+"Assurez-vous que vous n’avez pas activé l’icône pour désactiver le "
+"microphone dans le logiciel"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:51
+msgid ""
+"Assurez-vous que la bonne source audio est sélectionnée dans les "
+"paramètres (icône « engrenage » sous votre image)."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:52 ../../users/Troubleshooting.md:67
+#: ../../users/Troubleshooting.md:74
+msgid "Cliquez sur le bouton « Reconnecter » en haut"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:54
+msgid "2. *Vous n’entendez pas le participant*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:55
+msgid ""
+"Assurez-vous que le volume de votre poste est bien allumé et à une valeur"
+" plus grande que 0"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:56
+msgid ""
+"Assurez-vous que votre icône « haut-parleur » dans le logiciel est bien "
+"active"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:57
+msgid ""
+"Si le participant utilise un microphone externe (tel un casque d’écoute),"
+" assurez-vous :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:58
+msgid "Qu’il est bien allumé"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:59
+msgid "Qu’il ne soit pas à « mute »"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:60
+msgid "Bien connecté à l’appareil"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:61
+msgid ""
+"Assurez-vous que le participant a bien la bonne source de microphone en "
+"cliquant sur l’icône « engrenage » sous son image et en changeant sa "
+"source audio principale"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:63
+msgid "3. *Le participant ne vous voit pas*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:64
+msgid "Assurez-vous que vous voyez votre propre image"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:65
+msgid ""
+"Si ce n’est pas le cas, validez les étapes identifiées plus haut sous « "
+"Pas d’image vidéo dans le vestibule de la séance »)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:66
+msgid "Assurez-vous que le bouton « caméra » est bien activé dans le logiciel"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:68 ../../users/Troubleshooting.md:75
+#: ../../users/Troubleshooting.md:91 ../../users/Troubleshooting.md:112
+msgid ""
+"Demandez au participant de rafraichir sa page de son côté (la façon de "
+"faire variera selon l’appareil et le navigateur utilisé) ou de cliquer "
+"sur le bouton « Déconnecter » en haut à droite et de suivre à nouveau le "
+"lien que vous lui avez envoyé"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:70
+msgid "4. *Vous ne voyez pas l’image du participant, mais vous l’entendez*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:71
+msgid "Si le participant vous entend, validez qu’il se voit"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:72
+msgid ""
+"S’il ne se voit pas, assurez-vous que l’icône « caméra » sous son image "
+"est bien activée"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:73
+msgid ""
+"Dans les paramètres du participant (icône « engrenage » sous son image), "
+"assurez-vous que la bonne caméra est sélectionnée"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:77
+msgid "5. *Coupures de son / qualité vidéo dégradée*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:78
+msgid ""
+"Ces problèmes sont dus à une mauvaise qualité de connexion Internet, que "
+"ce soit du côté du professionnel ou du participant. Quelques ajustements "
+"et validations pouvant être faites :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:79
+msgid ""
+"Si vous êtes sur un réseau sans fil et qu’un réseau filaire est "
+"disponible, tentez de brancher votre appareil sur ce réseau"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:80
+msgid ""
+"Assurez-vous que personne d’autre au domicile du participant n’utilise la"
+" connexion Internet en même temps que la séance pour y faire du "
+"téléchargement, du visionnement en ligne (« streaming ») ou jouer à des "
+"jeux vidéo en ligne"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:81
+msgid ""
+"Si le participant se connecte à Internet via une connexion de type « "
+"cellulaire », demandez-lui, si possible de se connecter avec une "
+"connexion de type sans-fil (non-cellulaire) ou filaire"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:82
+msgid ""
+"Si possible, demandez au participant de changer de pièce. Idéalement, "
+"s’il sait où se trouve son point d’accès Internet (routeur et/ou modem), "
+"demandez-lui de s’y rapprocher."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:83
+msgid ""
+"En dernier recours, activez et désactivez les caméras dans le logiciel et"
+" activez-les uniquement si nécessaire"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:84
+msgid "Si le problème persiste :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:85
+msgid ""
+"Si le problème revient constamment avec tous les participants, il faudra "
+"peut-être vérifier la connexion Internet du poste clinicien"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:86
+msgid ""
+"Si le problème revient constamment avec un participant donné, le problème"
+" se trouve probablement de son côté et vérifier la connexion Internet de "
+"celui-ci. Un redémarrage du modem / routeur peut parfois résoudre les "
+"problèmes."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:88
+msgid "6. *Tout autre problème*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:89
+msgid ""
+"La plupart des autres problèmes pouvant survenir peuvent être réglés avec"
+" ces étapes :"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:90
+msgid "Cliquez sur le bouton « Reconnecter » en haut à gauche"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:92
+msgid "Terminez la séance et démarrez une nouvelle séance"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:94
+msgid "Problèmes du côté du participant"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:96
+msgid "1. *Message d’erreur : « Navigateur non-supporté »*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:97
+msgid ""
+"Demandez au participant d'utiliser un autre navigateur (tels que Firefox,"
+" Chrome ou Safari)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:98
+msgid "Si le participant est sur un appareil mobile:"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:99
+msgid "Demandez-lui de faire les mises à jour logicielles, s'il y a lieu"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:100
+msgid ""
+"S'il est sur un appareil de type Apple, demandez-lui d'utiliser le "
+"navigateur *Safari* pour ouvrir le lien. Sur ces appareils, aucun autre "
+"navigateur n'est supporté."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:101
+msgid ""
+"S'il n'y a pas de mise à jour disponible et que son appareil date de "
+"plusieurs années, il est possible qu'il ne soit plus supporté. Demandez-"
+"lui d'utilisateur un autre appareil si possible."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:103
+msgid "2. *Pas d’image vidéo en cliquant sur le lien*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:104
+msgid "Assurez-vous qu'il n'a pas de cache-caméra devant sa caméra"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:105
+msgid ""
+"Validez, avec le participant, qu'il a bien répondu \"Oui\" à la question "
+"qui demandait l'accès à sa caméra"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:106
+msgid "S'il a répondu non:"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:107
+msgid "Tentez de rafraichir la page du navigateur"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:108
+msgid ""
+"Si la question ne réapparait pas, la procédure variera selon les "
+"navigateurs. Il faut généralement cliquer sur l'icône \"Caméra\" en haut "
+"près de l'adresse et activer celle-ci."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:109
+msgid "Assurez-vous qu'il utilise un navigateur compatible (voir ci-dessus)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:111
+msgid ""
+"3. *Même si le professionnel démarre la séance, celle-ci ne démarre pas "
+"pour le participant*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:113
+msgid ""
+"En dernier recours, demandez au participant de redémarrer son appareil et"
+" de suivre à nouveau le lien."
+msgstr ""
+
+#: ../../users/Troubleshooting.md:115
+msgid "4. *Le son est faible*"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:116
+msgid "Vérifiez le volume de l'appareil du participant"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:117
+msgid ""
+"Même si le volume est au maximum, il se pourrait que le son soit faible. "
+"Vérifiez ces éléments:"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:118
+msgid ""
+"Assurez-vous de minimiser le bruit de fond de votre côté (personnes qui "
+"parlent, musique, bruit constant)"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:119
+msgid "Assurez-vous de minimiser le bruit de font du participant"
+msgstr ""
+
+#: ../../users/Troubleshooting.md:120
+msgid "Branchez un haut-parleur externe ou utilisez un casque d'écoute"
+msgstr ""
+
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 00000000..954237b9
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 00000000..c16be0ca
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,5 @@
+sphinx
+sphinx-intl
+myst-parser
+sphinx-rtd-theme
+sphinxcontrib-openapi
diff --git a/docs/users/Troubleshooting.md b/docs/users/Troubleshooting.md
new file mode 100644
index 00000000..1ea687ee
--- /dev/null
+++ b/docs/users/Troubleshooting.md
@@ -0,0 +1,120 @@
+# Problèmes et solutions
+
+## Démarrage du logiciel
+### Connexion
+#### 1. *Utilisateur ou mot de passe invalide*
+- Vérifiez votre code utilisateur et votre mot de passe
+- Validez auprès de votre administrateur si votre compte est toujours actif
+
+#### 2. *Impossible de rejoindre le serveur*
+- Vérifiez que votre ordinateur est bien connecté à Internet (en ouvrant un navigateur et en effectuant une recherche, par exemple)
+- Assurez-vous que votre ordinateur est bien connecté sur le bon réseau Internet
+- Si nécessaire, assurez-vous que les politiques en place dans votre établissement permettent bien l’utilisation du logiciel (i.e. aucun port bloqué, aucun anti-virus qui empêche l'exécution adéquate du logiciel)
+
+#### 3. *Message d’erreur : « Déjà connecté au logiciel »*
+- Vérifiez que le logiciel n’est pas déjà ouvert sur votre poste de travail
+- Si vous utilisez plusieurs postes, assurez-vous que vous n’êtes pas connecté sur un autre poste
+- Assurez-vous que personne d’autre n’utilise votre compte utilisateur
+- Si vous ne savez pas où vous êtes connecté, contactez votre administrateur qui pourra désactiver votre compte, changer le mot de passe et le réactiver
+
+## Séance de télésanté
+> Téléréadaptation ou autre, basée sur le service de *VideoRehab*.
+
+### Démarrage de séance
+
+#### 1. *Pas d’image vidéo dans le vestibule de la séance*
+- Vérifiez qu’il n’y a pas de cache-caméra sur votre caméra
+- Vérifiez que votre caméra est bien branchée sur votre appareil s’il s’agit d’une caméra externe
+- Assurez-vous qu’aucun autre logiciel présentement ouvert n’utilise votre caméra (comme Microsoft Teams, Zoom ou autres)
+- Assurez-vous que la bonne source vidéo est sélectionnée (en bas de la zone d’image)
+
+#### 2. *Pas de son dans le vestibule de séance*
+> La barre de son à gauche ne s’affiche ou ne bouge pas lorsque vous parlez.
+- Si vous utilisez un microphone externe, assurez-vous qu’il est bien branché
+- S’il y a lieu, assurez-vous que le bouton « mute » n’est pas activé sur votre microphone
+- Assurez-vous que le bon microphone est sélectionné (en bas de la zone d’image)
+
+#### 3. *Mauvaise caméra*
+- Dans le vestibule, sous l’image de la caméra, sélectionnez la bonne caméra. N’oubliez pas d’enregistrer les paramètres par défaut si vous souhaitez toujours utiliser cette caméra !
+
+#### 4. *Participant ne se joint jamais à la séance*
+- Assurez-vous que le participant était bien en ligne (icône verte) au démarrage de la séance.
+- Contactez le participant et vérifiez :
+ - Qu’il a bien ouvert le lien fourni et qu’il se voit sur son écran
+ - Qu’il ait bien accepté de partager son microphone et sa caméra lorsque la question lui sera demandée
+
+### Pendant la séance
+
+#### 1. *Le participant n’entend pas ce que vous dites*
+- Assurez-vous que votre microphone est bien allumé et pas en « mute » (voir « Pas de son dans le vestibule de séance ») plus haut
+- Assurez-vous que vous n’avez pas activé l’icône pour désactiver le microphone dans le logiciel
+- Assurez-vous que la bonne source audio est sélectionnée dans les paramètres (icône « engrenage » sous votre image).
+- Cliquez sur le bouton « Reconnecter » en haut
+
+#### 2. *Vous n’entendez pas le participant*
+- Assurez-vous que le volume de votre poste est bien allumé et à une valeur plus grande que 0
+- Assurez-vous que votre icône « haut-parleur » dans le logiciel est bien active
+- Si le participant utilise un microphone externe (tel un casque d’écoute), assurez-vous :
+ - Qu’il est bien allumé
+ - Qu’il ne soit pas à « mute »
+ - Bien connecté à l’appareil
+- Assurez-vous que le participant a bien la bonne source de microphone en cliquant sur l’icône « engrenage » sous son image et en changeant sa source audio principale
+
+#### 3. *Le participant ne vous voit pas*
+- Assurez-vous que vous voyez votre propre image
+ - Si ce n’est pas le cas, validez les étapes identifiées plus haut sous « Pas d’image vidéo dans le vestibule de la séance »)
+ - Assurez-vous que le bouton « caméra » est bien activé dans le logiciel
+- Cliquez sur le bouton « Reconnecter » en haut
+- Demandez au participant de rafraichir sa page de son côté (la façon de faire variera selon l’appareil et le navigateur utilisé) ou de cliquer sur le bouton « Déconnecter » en haut à droite et de suivre à nouveau le lien que vous lui avez envoyé
+
+#### 4. *Vous ne voyez pas l’image du participant, mais vous l’entendez*
+- Si le participant vous entend, validez qu’il se voit
+ - S’il ne se voit pas, assurez-vous que l’icône « caméra » sous son image est bien activée
+ - Dans les paramètres du participant (icône « engrenage » sous son image), assurez-vous que la bonne caméra est sélectionnée
+- Cliquez sur le bouton « Reconnecter » en haut
+- Demandez au participant de rafraichir sa page de son côté (la façon de faire variera selon l’appareil et le navigateur utilisé) ou de cliquer sur le bouton « Déconnecter » en haut à droite et de suivre à nouveau le lien que vous lui avez envoyé
+
+#### 5. *Coupures de son / qualité vidéo dégradée*
+Ces problèmes sont dus à une mauvaise qualité de connexion Internet, que ce soit du côté du professionnel ou du participant. Quelques ajustements et validations pouvant être faites :
+- Si vous êtes sur un réseau sans fil et qu’un réseau filaire est disponible, tentez de brancher votre appareil sur ce réseau
+- Assurez-vous que personne d’autre au domicile du participant n’utilise la connexion Internet en même temps que la séance pour y faire du téléchargement, du visionnement en ligne (« streaming ») ou jouer à des jeux vidéo en ligne
+- Si le participant se connecte à Internet via une connexion de type « cellulaire », demandez-lui, si possible de se connecter avec une connexion de type sans-fil (non-cellulaire) ou filaire
+- Si possible, demandez au participant de changer de pièce. Idéalement, s’il sait où se trouve son point d’accès Internet (routeur et/ou modem), demandez-lui de s’y rapprocher.
+- En dernier recours, activez et désactivez les caméras dans le logiciel et activez-les uniquement si nécessaire
+- Si le problème persiste :
+ - Si le problème revient constamment avec tous les participants, il faudra peut-être vérifier la connexion Internet du poste clinicien
+ - Si le problème revient constamment avec un participant donné, le problème se trouve probablement de son côté et vérifier la connexion Internet de celui-ci. Un redémarrage du modem / routeur peut parfois résoudre les problèmes.
+
+#### 6. *Tout autre problème*
+La plupart des autres problèmes pouvant survenir peuvent être réglés avec ces étapes :
+- Cliquez sur le bouton « Reconnecter » en haut à gauche
+- Demandez au participant de rafraichir sa page de son côté (la façon de faire variera selon l’appareil et le navigateur utilisé) ou de cliquer sur le bouton « Déconnecter » en haut à droite et de suivre à nouveau le lien que vous lui avez envoyé
+- Terminez la séance et démarrez une nouvelle séance
+
+### Problèmes du côté du participant
+
+#### 1. *Message d’erreur : « Navigateur non-supporté »*
+- Demandez au participant d'utiliser un autre navigateur (tels que Firefox, Chrome ou Safari)
+- Si le participant est sur un appareil mobile:
+ - Demandez-lui de faire les mises à jour logicielles, s'il y a lieu
+ - S'il est sur un appareil de type Apple, demandez-lui d'utiliser le navigateur *Safari* pour ouvrir le lien. Sur ces appareils, aucun autre navigateur n'est supporté.
+ - S'il n'y a pas de mise à jour disponible et que son appareil date de plusieurs années, il est possible qu'il ne soit plus supporté. Demandez-lui d'utilisateur un autre appareil si possible.
+
+#### 2. *Pas d’image vidéo en cliquant sur le lien*
+- Assurez-vous qu'il n'a pas de cache-caméra devant sa caméra
+- Validez, avec le participant, qu'il a bien répondu "Oui" à la question qui demandait l'accès à sa caméra
+ - S'il a répondu non:
+ - Tentez de rafraichir la page du navigateur
+ - Si la question ne réapparait pas, la procédure variera selon les navigateurs. Il faut généralement cliquer sur l'icône "Caméra" en haut près de l'adresse et activer celle-ci.
+- Assurez-vous qu'il utilise un navigateur compatible (voir ci-dessus)
+
+#### 3. *Même si le professionnel démarre la séance, celle-ci ne démarre pas pour le participant*
+- Demandez au participant de rafraichir sa page de son côté (la façon de faire variera selon l’appareil et le navigateur utilisé) ou de cliquer sur le bouton « Déconnecter » en haut à droite et de suivre à nouveau le lien que vous lui avez envoyé
+- En dernier recours, demandez au participant de redémarrer son appareil et de suivre à nouveau le lien.
+
+#### 4. *Le son est faible*
+- Vérifiez le volume de l'appareil du participant
+- Même si le volume est au maximum, il se pourrait que le son soit faible. Vérifiez ces éléments:
+ - Assurez-vous de minimiser le bruit de fond de votre côté (personnes qui parlent, musique, bruit constant)
+ - Assurez-vous de minimiser le bruit de font du participant
+- Branchez un haut-parleur externe ou utilisez un casque d'écoute
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index 4a6957ee..7f46ad21 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -8,6 +8,8 @@ if (MSVC)
/wd4910 # Ignore export warnings (C4910) with MSVC
/wd4661 # Ignore no suitable definition for explicit template (C4661)
/wd4251 # Ignore needs to have dll-interface
+ /wd4146 # Ignore unary minus operator applied to unsigned type, result still unsigned
+ /wd4267 # Ignore size_t to uint32_t conversion warnings
)
endif (MSVC)
@@ -22,13 +24,18 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
#Disable tests for now...
option(protobuf_BUILD_TESTS "" OFF)
+set(ABSL_PROPAGATE_CXX_STD OFF)
+set(protobuf_BUILD_EXAMPLES OFF)
+set(protobuf_BUILD_LIBPROTOC OFF)
+set(protobuf_BUILD_TESTS OFF)
+
#Use dynamic MSVC runtime
if (MSVC)
option(protobuf_MSVC_STATIC_RUNTIME "" OFF)
endif(MSVC)
-add_subdirectory(protobuf/cmake)
+add_subdirectory(protobuf)
#Generate messages
add_subdirectory(messages/cpp)
diff --git a/external/protobuf b/external/protobuf
index 3d8943fe..2dca62f7 160000
--- a/external/protobuf
+++ b/external/protobuf
@@ -1 +1 @@
-Subproject commit 3d8943fea997ca18e022bbd6c074cb6aa6610fbe
+Subproject commit 2dca62f7296e5b49d729f7384f975cecb38382a0
diff --git a/external/webcamoid/Driver/CMakeLists.txt b/external/webcamoid/Driver/CMakeLists.txt
index a3d2785b..8364ddfc 100644
--- a/external/webcamoid/Driver/CMakeLists.txt
+++ b/external/webcamoid/Driver/CMakeLists.txt
@@ -1,22 +1,22 @@
MESSAGE ( STATUS "Buiding AkKysDriver...")
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
include_directories(${AVKYS_INCLUDES}
./)
add_executable(installDriver install.cpp)
# qt5_use_modules(installDriver Core Concurrent Gui Qml)
-target_link_libraries(installDriver Qt5::Core Qt5::Concurrent Qt5::Gui Qt5::Qml)
+target_link_libraries(installDriver Qt6::Core Qt6::Concurrent Qt6::Gui Qt6::Qml)
target_link_libraries(installDriver ${AVKYS_LIBS})
add_executable(uninstallDriver uninstall.cpp)
# qt5_use_modules(uninstallDriver Core Concurrent Gui Qml)
-target_link_libraries(uninstallDriver Qt5::Core Qt5::Concurrent Qt5::Gui Qt5::Qml)
+target_link_libraries(uninstallDriver Qt6::Core Qt6::Concurrent Qt6::Gui Qt6::Qml)
target_link_libraries(uninstallDriver ${AVKYS_LIBS})
diff --git a/external/webcamoid/Lib/CMakeLists.txt b/external/webcamoid/Lib/CMakeLists.txt
index 5a920e82..648dfef8 100644
--- a/external/webcamoid/Lib/CMakeLists.txt
+++ b/external/webcamoid/Lib/CMakeLists.txt
@@ -1,9 +1,9 @@
MESSAGE ( STATUS "Buiding AkCommons...")
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
add_definitions(-DQT_DEPRECATED_WARNINGS -DAKCOMMONS_LIBRARY)
@@ -42,15 +42,15 @@ set (libavkys_srcs
)
#This will generate moc_* for Qt
-QT5_WRAP_CPP(libavkys_moc_srcs ${libavkys_headers})
+QT_WRAP_CPP(libavkys_moc_srcs ${libavkys_headers})
add_library(AvKys SHARED ${libavkys_srcs} ${libavkys_headers} ${libavkys_moc_srcs})
# qt5_use_modules(AvKys Core Concurrent Gui Qml)
-target_link_libraries(AvKys Qt5::Core Qt5::Concurrent Qt5::Gui Qt5::Qml)
+target_link_libraries(AvKys Qt6::Core Qt6::Concurrent Qt6::Gui Qt6::Qml)
set(AVKYS_LIBS AvKys CACHE INTERNAL "doc string")
set(AVKYS_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/src CACHE INTERNAL "doc string")
-install(TARGETS AvKys DESTINATION ${CMAKE_INSTALL_BINDIR})
+install(TARGETS AvKys RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/external/webcamoid/Lib/src/ak.cpp b/external/webcamoid/Lib/src/ak.cpp
index 880fdf4e..4090253b 100644
--- a/external/webcamoid/Lib/src/ak.cpp
+++ b/external/webcamoid/Lib/src/ak.cpp
@@ -40,14 +40,15 @@ class AkPrivate
{
this->m_globalEngine = nullptr;
+ // SB: qRegisterMetaTypeStreamOperators is now useless in Qt6: https://www.qt.io/blog/whats-new-in-qmetatype-qvariant
qRegisterMetaType("QRgb");
qRegisterMetaType("QColor");
qRegisterMetaType("AkCaps");
- qRegisterMetaTypeStreamOperators("AkCaps");
+ //qRegisterMetaTypeStreamOperators("AkCaps");
qRegisterMetaType("AkCaps::CapsType");
qRegisterMetaType("CapsType");
qRegisterMetaType("AkAudioCaps");
- qRegisterMetaTypeStreamOperators("AkAudioCaps");
+ //qRegisterMetaTypeStreamOperators("AkAudioCaps");
qRegisterMetaType("AkAudioCaps::SampleFormat");
qRegisterMetaType("SampleFormat");
qRegisterMetaType("AkAudioCaps::SampleType");
@@ -55,14 +56,14 @@ class AkPrivate
qRegisterMetaType("AkAudioCaps::ChannelLayout");
qRegisterMetaType("ChannelLayout");
qRegisterMetaType("AkVideoCaps");
- qRegisterMetaTypeStreamOperators("AkVideoCaps");
+ //qRegisterMetaTypeStreamOperators("AkVideoCaps");
qRegisterMetaType("AkVideoCaps::PixelFormat");
qRegisterMetaType("PixelFormat");
qRegisterMetaType("AkElement::ElementState");
qRegisterMetaType("ElementState");
- qRegisterMetaTypeStreamOperators("AkElement::ElementState");
+ //qRegisterMetaTypeStreamOperators("AkElement::ElementState");
qRegisterMetaType("AkFrac");
- qRegisterMetaTypeStreamOperators("AkFrac");
+ //qRegisterMetaTypeStreamOperators("AkFrac");
qRegisterMetaType("AkPacket");
qRegisterMetaType("AkElementPtr");
diff --git a/external/webcamoid/Lib/src/akaudiopacket.h b/external/webcamoid/Lib/src/akaudiopacket.h
index dc460584..4a9ed1fe 100644
--- a/external/webcamoid/Lib/src/akaudiopacket.h
+++ b/external/webcamoid/Lib/src/akaudiopacket.h
@@ -22,6 +22,7 @@
#include "akpacket.h"
#include "akaudiocaps.h"
+#include
class AkAudioPacketPrivate;
diff --git a/external/webcamoid/Lib/src/akcaps.cpp b/external/webcamoid/Lib/src/akcaps.cpp
index ce68bec1..5ecaa41d 100644
--- a/external/webcamoid/Lib/src/akcaps.cpp
+++ b/external/webcamoid/Lib/src/akcaps.cpp
@@ -17,10 +17,8 @@
* Web-Site: http://webcamoid.github.io/
*/
-#include
+#include
#include
-#include
-
#include "akcaps.h"
class AkCapsPrivate
@@ -140,8 +138,8 @@ AkCaps &AkCaps::fromMap(const QVariantMap &caps)
for (const QString &key: caps.keys())
if (key == "mimeType") {
- this->d->m_isValid = QRegExp("\\s*[a-z]+/\\w+(?:(?:-|\\+|\\.)\\w+)*\\s*")
- .exactMatch(caps[key].toString());
+ this->d->m_isValid = QRegularExpression("\\s*[a-z]+/\\w+(?:(?:-|\\+|\\.)\\w+)*\\s*")
+ .match(caps[key].toString()).hasMatch();
this->d->m_mimeType = caps[key].toString().trimmed();
} else
this->setProperty(key.trimmed().toStdString().c_str(), caps[key]);
@@ -151,9 +149,9 @@ AkCaps &AkCaps::fromMap(const QVariantMap &caps)
AkCaps &AkCaps::fromString(const QString &caps)
{
- this->d->m_isValid = QRegExp("\\s*[a-z]+/\\w+(?:(?:-|\\+|\\.)\\w+)*"
+ this->d->m_isValid = QRegularExpression("\\s*[a-z]+/\\w+(?:(?:-|\\+|\\.)\\w+)*"
"(?:\\s*,\\s*[a-zA-Z_]\\w*\\s*="
- "\\s*[^,=]+)*\\s*").exactMatch(caps);
+ "\\s*[^,=]+)*\\s*").match(caps).hasMatch();
QList properties = this->dynamicPropertyNames();
@@ -163,11 +161,11 @@ AkCaps &AkCaps::fromString(const QString &caps)
QStringList capsChunks;
if (this->d->m_isValid)
- capsChunks = caps.split(QRegExp("\\s*,\\s*"),
+ capsChunks = caps.split(QRegularExpression("\\s*,\\s*"),
Qt::SkipEmptyParts);
for (int i = 1; i < capsChunks.length(); i++) {
- QStringList pair = capsChunks[i].split(QRegExp("\\s*=\\s*"),
+ QStringList pair = capsChunks[i].split(QRegularExpression("\\s*=\\s*"),
Qt::SkipEmptyParts);
this->setProperty(pair[0].trimmed().toStdString().c_str(),
@@ -247,7 +245,7 @@ bool AkCaps::contains(const QString &property) const
void AkCaps::setMimeType(const QString &mimeType)
{
- this->d->m_isValid = QRegExp("\\s*[a-z]+/\\w+(?:(?:-|\\+|\\.)\\w+)*\\s*").exactMatch(mimeType);
+ this->d->m_isValid = QRegularExpression("\\s*[a-z]+/\\w+(?:(?:-|\\+|\\.)\\w+)*\\s*").match(mimeType).hasMatch();
QString _mimeType = this->d->m_isValid? mimeType.trimmed(): QString("");
if (this->d->m_mimeType == _mimeType)
diff --git a/external/webcamoid/Lib/src/akcaps.h b/external/webcamoid/Lib/src/akcaps.h
index 77aa9dc2..8351805a 100644
--- a/external/webcamoid/Lib/src/akcaps.h
+++ b/external/webcamoid/Lib/src/akcaps.h
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include "akcommons.h"
diff --git a/external/webcamoid/Lib/src/akelement.cpp b/external/webcamoid/Lib/src/akelement.cpp
index 0c109bf4..c0dbb848 100644
--- a/external/webcamoid/Lib/src/akelement.cpp
+++ b/external/webcamoid/Lib/src/akelement.cpp
@@ -17,7 +17,7 @@
* Web-Site: http://webcamoid.github.io/
*/
-#include
+#include
#include
#include
#include
@@ -105,8 +105,8 @@ class AkElementPrivate
QMetaMethod method = object->metaObject()->method(i);
QString signature(method.methodSignature());
- if (QRegExp(QString("\\s*%1\\s*\\(.*").arg(methodName))
- .exactMatch(signature))
+ if (QRegularExpression(QString("\\s*%1\\s*\\(.*").arg(methodName))
+ .match(signature).hasMatch())
if (!methodSignatures.contains(signature)) {
methods << method;
methodSignatures << signature;
@@ -133,7 +133,7 @@ class AkElementPrivate
return pluginId;
;
#else
- return pluginId.remove(QRegExp("^lib"));
+ return pluginId.remove(QRegularExpression("^lib"));
#endif
}
@@ -158,7 +158,7 @@ class AkElementPrivate
for (int i = sPath->length() - 1; i >= 0; i--) {
QString searchDir(sPath->at(i));
- searchDir.replace(QRegExp("((\\\\/?)|(/\\\\?))+"),
+ searchDir.replace(QRegularExpression("((\\\\/?)|(/\\\\?))+"),
QDir::separator());
while (searchDir.endsWith(QDir::separator()))
@@ -208,9 +208,12 @@ class AkElementPrivate
if (QFileInfo(path).isFile()) {
QString fileName = QFileInfo(path).fileName();
- if (QRegExp(this->m_pluginFilePattern,
- Qt::CaseSensitive,
- QRegExp::Wildcard).exactMatch(fileName)) {
+ // if (QRegExp(this->m_pluginFilePattern,
+ // Qt::CaseSensitive,
+ // QRegExp::Wildcard).exactMatch(fileName)) {
+ if (QRegularExpression(
+ QRegularExpression::fromWildcard(this->m_pluginFilePattern, Qt::CaseSensitive)
+ ).match(fileName).hasMatch()) {
QPluginLoader pluginLoader(path);
if (pluginLoader.load()) {
@@ -508,7 +511,7 @@ QStringList AkElement::listSubModules(const QStringList &types)
if (this->d->m_pluginId.isEmpty()) {
pluginId = this->metaObject()->className();
- pluginId.replace(QRegExp("Element$"), "");
+ pluginId.replace(QRegularExpression("Element$"), "");
} else {
pluginId = this->d->m_pluginId;
}
@@ -575,7 +578,7 @@ QStringList AkElement::listSubModulesPaths()
if (this->d->m_pluginId.isEmpty()) {
pluginId = this->metaObject()->className();
- pluginId.replace(QRegExp("Element$"), "");
+ pluginId.replace(QRegularExpression("Element$"), "");
} else {
pluginId = this->d->m_pluginId;
}
@@ -624,7 +627,7 @@ QObject *AkElement::loadSubModule(const QString &subModule)
if (this->d->m_pluginId.isEmpty()) {
pluginId = this->metaObject()->className();
- pluginId.replace(QRegExp("Element$"), "");
+ pluginId.replace(QRegularExpression("Element$"), "");
} else {
pluginId = this->d->m_pluginId;
}
@@ -717,7 +720,7 @@ QStringList AkElement::listPluginPaths(const QString &searchPath)
QString searchDir(searchPath);
- searchDir.replace(QRegExp("((\\\\/?)|(/\\\\?))+"),
+ searchDir.replace(QRegularExpression("((\\\\/?)|(/\\\\?))+"),
QDir::separator());
QStringList files;
diff --git a/external/webcamoid/Lib/src/akfrac.cpp b/external/webcamoid/Lib/src/akfrac.cpp
index 7de14728..dba40fbb 100644
--- a/external/webcamoid/Lib/src/akfrac.cpp
+++ b/external/webcamoid/Lib/src/akfrac.cpp
@@ -17,7 +17,7 @@
* Web-Site: http://webcamoid.github.io/
*/
-#include
+#include
#include
#include
@@ -235,8 +235,8 @@ void AkFrac::setNumDen(qint64 num, qint64 den)
void AkFrac::setNumDen(const QString &fracString)
{
- bool match = QRegExp("(\\s*-)?\\s*\\d+\\s*/"
- "\\s*\\d+\\s*").exactMatch(fracString);
+ bool match = QRegularExpression("(\\s*-)?\\s*\\d+\\s*/"
+ "\\s*\\d+\\s*").match(fracString).hasMatch();
if (!match) {
this->setNumDen(0, 0);
@@ -244,7 +244,7 @@ void AkFrac::setNumDen(const QString &fracString)
return;
}
- QStringList fracChunks = fracString.split(QRegExp("\\s*/\\s*"),
+ QStringList fracChunks = fracString.split(QRegularExpression("\\s*/\\s*"),
Qt::SkipEmptyParts);
qint64 num = fracChunks[0].trimmed().toInt();
diff --git a/external/webcamoid/Lib/src/akpacket.h b/external/webcamoid/Lib/src/akpacket.h
index 0a09f28b..7aa9c7e4 100644
--- a/external/webcamoid/Lib/src/akpacket.h
+++ b/external/webcamoid/Lib/src/akpacket.h
@@ -21,6 +21,7 @@
#define AKPACKET_H
#include
+#include
#include "akcaps.h"
#include "akfrac.h"
diff --git a/external/webcamoid/Lib/src/akutils.cpp b/external/webcamoid/Lib/src/akutils.cpp
index 4b47e3fe..c29898e5 100644
--- a/external/webcamoid/Lib/src/akutils.cpp
+++ b/external/webcamoid/Lib/src/akutils.cpp
@@ -18,6 +18,7 @@
*/
#include "akutils.h"
+#include
typedef QMap ImageToPixelFormatMap;
diff --git a/external/webcamoid/Lib/src/akvideopacket.cpp b/external/webcamoid/Lib/src/akvideopacket.cpp
index d64e5ea0..1e02f44d 100644
--- a/external/webcamoid/Lib/src/akvideopacket.cpp
+++ b/external/webcamoid/Lib/src/akvideopacket.cpp
@@ -18,6 +18,7 @@
*/
#include "akvideopacket.h"
+#include
class AkVideoPacketPrivate
{
diff --git a/external/webcamoid/Plugins/ACapsConvert/CMakeLists.txt b/external/webcamoid/Plugins/ACapsConvert/CMakeLists.txt
index b86ee424..65498262 100644
--- a/external/webcamoid/Plugins/ACapsConvert/CMakeLists.txt
+++ b/external/webcamoid/Plugins/ACapsConvert/CMakeLists.txt
@@ -3,10 +3,10 @@ message(STATUS "Building ${PLUGIN_NAME} Plugin.")
add_definitions(-DUNICODE)
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
include_directories(
${AVKYS_PLUGIN_INCLUDES}
@@ -34,15 +34,15 @@ set (plugin_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(plugin_moc_srcs ${plugin_headers})
+QT_WRAP_CPP(plugin_moc_srcs ${plugin_headers})
-QT5_ADD_RESOURCES(plugin_qrc_srcs ${plugin_qrc})
+QT6_ADD_RESOURCES(plugin_qrc_srcs ${plugin_qrc})
add_library(${PLUGIN_NAME} SHARED ${plugin_srcs} ${plugin_headers} ${plugin_moc_srcs} ${plugin_qrc_srcs})
# qt5_use_modules(${PLUGIN_NAME} Core Concurrent Gui Qml)
target_link_libraries(${PLUGIN_NAME} ${AVKYS_PLUGIN_LIBRARIES})
-target_link_libraries(${PLUGIN_NAME} Qt5::Core Qt5::Concurrent Qt5::Gui Qt5::Qml)
-install(TARGETS ${PLUGIN_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH})
+target_link_libraries(${PLUGIN_NAME} Qt6::Core Qt6::Concurrent Qt6::Gui Qt6::Qml)
+install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH})
#submodule(s)
FILE(MAKE_DIRECTORY ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
diff --git a/external/webcamoid/Plugins/ACapsConvert/src/ffmpegsw/CMakeLists.txt b/external/webcamoid/Plugins/ACapsConvert/src/ffmpegsw/CMakeLists.txt
index 45d460e3..d636ab8c 100644
--- a/external/webcamoid/Plugins/ACapsConvert/src/ffmpegsw/CMakeLists.txt
+++ b/external/webcamoid/Plugins/ACapsConvert/src/ffmpegsw/CMakeLists.txt
@@ -13,11 +13,11 @@ add_definitions(-DHAVE_SAMPLEFORMAT64)
SET(LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
-find_package(Qt5Widgets REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
+find_package(Qt6Widgets REQUIRED)
include_directories(
${AVKYS_PLUGIN_INCLUDES}
@@ -44,16 +44,16 @@ set (submodule_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
+QT_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
-QT5_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
+QT6_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
add_library(${PLUGIN_NAME}_${SUBMMODULE_NAME} SHARED ${submodule_srcs} ${submodule_headers} ${submodule_moc_srcs} ${submodule_qrc_srcs})
set_target_properties(${PLUGIN_NAME}_${SUBMMODULE_NAME} PROPERTIES OUTPUT_NAME "ffmpegsw" )
#qt5_use_modules(${PLUGIN_NAME}_${SUBMMODULE_NAME} Core Concurrent Widgets Gui Qml)
-target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Gui Qt5::Qml)
+target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} Qt6::Core Qt6::Concurrent Qt6::Widgets Qt6::Gui Qt6::Qml)
target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} ${AVKYS_PLUGIN_LIBRARIES} ${FFMPEG_LIBS})
-install(TARGETS ${PLUGIN_NAME}_${SUBMMODULE_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
+install(TARGETS ${PLUGIN_NAME}_${SUBMMODULE_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
diff --git a/external/webcamoid/Plugins/CMakeLists.txt b/external/webcamoid/Plugins/CMakeLists.txt
index 43ddf63c..aa483039 100644
--- a/external/webcamoid/Plugins/CMakeLists.txt
+++ b/external/webcamoid/Plugins/CMakeLists.txt
@@ -57,19 +57,50 @@ endif()
if(WIN32)
- #Hard coded path for now
- set(FFMPEG_PATH "C:/Libs/ffmpeg")
+ # Oldest archive found working
+ set(ffmpeg_version "4.4")
+
+ set(ffmpeg_archive_name "ffmpeg-${ffmpeg_version}-full_build-shared.zip")
+ set(ffmpeg_archive_url "https://github.com/GyanD/codexffmpeg/releases/download/${ffmpeg_version}/${ffmpeg_archive_name}")
+
+ set(ffmpeg_archive_url_download_log "")
+ set(ffmpeg_archive_url_download_status "")
+
+ # Download FFMPEG
+ if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${ffmpeg_archive_name})
+ message(STATUS "Downloading : ${ffmpeg_archive_url}")
+ file(DOWNLOAD
+ ${ffmpeg_archive_url}
+ ${CMAKE_CURRENT_BINARY_DIR}/${ffmpeg_archive_name}
+ TIMEOUT 300 #seconds
+ LOG ffmpeg_archive_url_download_log
+ STATUS ffmpeg_archive_url_download_status
+ TLS_VERIFY ON
+ SHOW_PROGRESS)
+ endif()
+
+ MESSAGE ( STATUS "Download status = ${ffmpeg_archive_url_download_status} log = ${ffmpeg_archive_url_download_log}")
+
+
+ # Extract file
+ if (NOT EXISTS {CMAKE_CURRENT_BINARY_DIR}/ffmpeg-${ffmpeg_version}-full_build-shared/README.txt)
+ file(ARCHIVE_EXTRACT INPUT ${CMAKE_CURRENT_BINARY_DIR}/${ffmpeg_archive_name} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+ endif()
+
+
+ # Using downloaded archive
+ set(FFMPEG_PATH ${CMAKE_CURRENT_BINARY_DIR}/ffmpeg-${ffmpeg_version}-full_build-shared)
FILE(GLOB FFMPEG_DLL "${FFMPEG_PATH}/bin/*.dll")
MESSAGE ( STATUS "FFMpeg libs = ${FFMPEG_DLL}")
- #FOR SOME REASON, DLLs ARE IN THE BIN DIRECTORY...
+ # DLLs ARE IN THE BIN DIRECTORY...
INSTALL(FILES ${FFMPEG_DLL} DESTINATION bin)
- #For IN-SOURCE debug
+ # For IN-SOURCE debug
file(COPY ${FFMPEG_DLL} DESTINATION ${EXECUTABLE_OUTPUT_PATH})
- #FOR MSVC
+ # FOR MSVC
set(ffmpeg_lib_names
${FFMPEG_PATH}/lib/avcodec.lib
${FFMPEG_PATH}/lib/avfilter.lib
@@ -81,7 +112,7 @@ if(WIN32)
${FFMPEG_PATH}/lib/swscale.lib
)
- #for linking and compiling
+ # For linking and compiling
set(FFMPEG_INCLUDES "${FFMPEG_PATH}/include " CACHE INTERNAL "doc string")
message ( STATUS "FFMpeg includes = ${FFMPEG_INCLUDES}")
@@ -90,7 +121,7 @@ if(WIN32)
endif()
-#Will output in the right directory
+# Will output in the right directory
FILE(MAKE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin/AvKysPlugins)
SET(LIBRARY_OUTPUT_PATH ${CMAKE_INSTALL_PREFIX}/bin/AvKysPlugins)
SET (AVKYS_LIBRARY_INSTALL_PATH ${CMAKE_INSTALL_BINDIR}/AvKysPlugins)
diff --git a/external/webcamoid/Plugins/DesktopCapture/CMakeLists.txt b/external/webcamoid/Plugins/DesktopCapture/CMakeLists.txt
index 1f7d65f8..33f00565 100644
--- a/external/webcamoid/Plugins/DesktopCapture/CMakeLists.txt
+++ b/external/webcamoid/Plugins/DesktopCapture/CMakeLists.txt
@@ -3,10 +3,10 @@ message(STATUS "Building ${PLUGIN_NAME} Plugin.")
add_definitions(-DUNICODE)
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
include_directories(
${AVKYS_PLUGIN_INCLUDES}
@@ -34,17 +34,15 @@ set (plugin_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(plugin_moc_srcs ${plugin_headers})
+QT_WRAP_CPP(plugin_moc_srcs ${plugin_headers})
-QT5_ADD_RESOURCES(plugin_qrc_srcs ${plugin_qrc})
+QT6_ADD_RESOURCES(plugin_qrc_srcs ${plugin_qrc})
add_library(${PLUGIN_NAME} SHARED ${plugin_srcs} ${plugin_headers} ${plugin_moc_srcs} ${plugin_qrc_srcs})
# qt5_use_modules(${PLUGIN_NAME} Core Concurrent Gui Qml)
-target_link_libraries(${PLUGIN_NAME} Qt5::Core Qt5::Concurrent Qt5::Gui Qt5::Qml)
+target_link_libraries(${PLUGIN_NAME} Qt6::Core Qt6::Concurrent Qt6::Gui Qt6::Qml)
target_link_libraries(${PLUGIN_NAME} ${AVKYS_PLUGIN_LIBRARIES})
-install(TARGETS ${PLUGIN_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH})
-
-
+install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH})
#submodule(s)
FILE(MAKE_DIRECTORY ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
diff --git a/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/CMakeLists.txt b/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/CMakeLists.txt
index b5ec2bb0..9310127a 100644
--- a/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/CMakeLists.txt
+++ b/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/CMakeLists.txt
@@ -5,11 +5,11 @@ message(STATUS "Building ${PLUGIN_NAME} : ${SUBMMODULE_NAME} submodule.")
SET(LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
-find_package(Qt5Widgets REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
+find_package(Qt6Widgets REQUIRED)
include_directories(
${AVKYS_PLUGIN_INCLUDES}
@@ -35,16 +35,16 @@ set (submodule_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
+QT_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
-QT5_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
+QT6_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
add_library(${PLUGIN_NAME}_${SUBMMODULE_NAME} SHARED ${submodule_srcs} ${submodule_headers} ${submodule_moc_srcs} ${submodule_qrc_srcs})
set_target_properties(${PLUGIN_NAME}_${SUBMMODULE_NAME} PROPERTIES OUTPUT_NAME "qtscreen")
# qt5_use_modules(${PLUGIN_NAME}_${SUBMMODULE_NAME} Core Concurrent Widgets Gui Qml)
-target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Gui Qt5::Qml)
+target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} Qt6::Core Qt6::Concurrent Qt6::Widgets Qt6::Gui Qt6::Qml)
target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} ${AVKYS_PLUGIN_LIBRARIES})
-install(TARGETS ${PLUGIN_NAME}_${SUBMMODULE_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
+install(TARGETS ${PLUGIN_NAME}_${SUBMMODULE_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
diff --git a/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.cpp b/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.cpp
index 6dce60be..33e26835 100644
--- a/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.cpp
+++ b/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.cpp
@@ -326,10 +326,10 @@ void QtScreenDev::readFrame()
if (!this->m_threadStatus.isRunning()) {
this->m_curPacket = packet;
- this->m_threadStatus = QtConcurrent::run(&this->m_threadPool,
+ this->m_threadStatus = QtConcurrent::run(&this->m_threadPool,[=]{QtScreenDev::sendPacket(this->m_curPacket);});
+ /*&QtScreenDev::sendPacket,
this,
- &QtScreenDev::sendPacket,
- this->m_curPacket);
+ this->m_curPacket);*/
}
}
@@ -343,7 +343,7 @@ void QtScreenDev::screenCountChanged(QScreen *screen)
void QtScreenDev::srceenResized(int screen)
{
QString media = QString("screen://%1").arg(screen);
- QWidget *widget = QApplication::desktop()->screen(screen);
+ QScreen *widget = QGuiApplication::screens().at(screen);//QApplication::desktop()->screen(screen);
emit this->sizeChanged(media, widget->size());
}
diff --git a/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.h b/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.h
index 147f3403..8d065585 100644
--- a/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.h
+++ b/external/webcamoid/Plugins/DesktopCapture/src/qtscreen/src/qtscreendev.h
@@ -24,7 +24,7 @@
#include
#include
#include
-#include
+#include
#include
#include
diff --git a/external/webcamoid/Plugins/MultiSrc/CMakeLists.txt b/external/webcamoid/Plugins/MultiSrc/CMakeLists.txt
index 92e860bb..37e2c21c 100644
--- a/external/webcamoid/Plugins/MultiSrc/CMakeLists.txt
+++ b/external/webcamoid/Plugins/MultiSrc/CMakeLists.txt
@@ -2,10 +2,10 @@ set(PLUGIN_NAME MultiSrc)
message(STATUS "Building ${PLUGIN_NAME} Plugin.")
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
include_directories(
${AVKYS_PLUGIN_INCLUDES}
@@ -33,15 +33,15 @@ set (plugin_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(plugin_moc_srcs ${plugin_headers})
+QT_WRAP_CPP(plugin_moc_srcs ${plugin_headers})
-QT5_ADD_RESOURCES(plugin_qrc_srcs ${plugin_qrc})
+QT6_ADD_RESOURCES(plugin_qrc_srcs ${plugin_qrc})
add_library(${PLUGIN_NAME} SHARED ${plugin_srcs} ${plugin_headers} ${plugin_moc_srcs} ${plugin_qrc_srcs})
# qt5_use_modules(${PLUGIN_NAME} Core Concurrent Gui Qml)
-target_link_libraries(${PLUGIN_NAME} Qt5::Core Qt5::Concurrent Qt5::Gui Qt5::Qml)
+target_link_libraries(${PLUGIN_NAME} Qt6::Core Qt6::Concurrent Qt6::Gui Qt6::Qml)
target_link_libraries(${PLUGIN_NAME} ${AVKYS_PLUGIN_LIBRARIES})
-install(TARGETS ${PLUGIN_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH})
+install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH})
#submodule(s)
FILE(MAKE_DIRECTORY ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
diff --git a/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/CMakeLists.txt b/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/CMakeLists.txt
index 82c7b4b2..cc01ab32 100644
--- a/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/CMakeLists.txt
+++ b/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/CMakeLists.txt
@@ -13,11 +13,11 @@ add_definitions(-DHAVE_SAMPLEFORMAT64)
SET(LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
-find_package(Qt5Widgets REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
+find_package(Qt6Widgets REQUIRED)
include_directories(
${AVKYS_PLUGIN_INCLUDES}
@@ -54,14 +54,14 @@ set (submodule_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
+QT_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
-QT5_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
+QT6_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
add_library(${SUBMMODULE_NAME} SHARED ${submodule_srcs} ${submodule_headers} ${submodule_moc_srcs} ${submodule_qrc_srcs})
# qt5_use_modules(${SUBMMODULE_NAME} Core Concurrent Widgets Gui Qml)
-target_link_libraries(${SUBMMODULE_NAME} Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Gui Qt5::Qml)
+target_link_libraries(${SUBMMODULE_NAME} Qt6::Core Qt6::Concurrent Qt6::Widgets Qt6::Gui Qt6::Qml)
target_link_libraries(${SUBMMODULE_NAME} ${AVKYS_PLUGIN_LIBRARIES} ${FFMPEG_LIBS})
-install(TARGETS ${SUBMMODULE_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
+install(TARGETS ${SUBMMODULE_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
diff --git a/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/abstractstream.cpp b/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/abstractstream.cpp
index 1389fb5b..2d328f32 100644
--- a/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/abstractstream.cpp
+++ b/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/abstractstream.cpp
@@ -412,9 +412,7 @@ void AbstractStream::setPaused(bool paused)
this->m_dataLoopResult.waitForFinished();
else
this->m_dataLoopResult =
- QtConcurrent::run(&this->m_threadPool,
- this,
- &AbstractStream::dataLoop);
+ QtConcurrent::run(&this->m_threadPool, [=]{AbstractStream::dataLoop();});
this->m_paused = paused;
emit this->pausedChanged(paused);
@@ -440,13 +438,9 @@ bool AbstractStream::init()
this->m_runPacketLoop = true;
this->m_runDataLoop = true;
this->m_packetLoopResult =
- QtConcurrent::run(&this->m_threadPool,
- this,
- &AbstractStream::packetLoop);
+ QtConcurrent::run(&m_threadPool,[=]{AbstractStream::packetLoop();});
this->m_dataLoopResult =
- QtConcurrent::run(&this->m_threadPool,
- this,
- &AbstractStream::dataLoop);
+ QtConcurrent::run(&m_threadPool, [=]{AbstractStream::dataLoop();});
return true;
}
diff --git a/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/audiostream.cpp b/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/audiostream.cpp
index e19233b4..3149b684 100644
--- a/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/audiostream.cpp
+++ b/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/audiostream.cpp
@@ -310,7 +310,8 @@ AkPacket AudioStream::convert(AVFrame *iFrame)
AkAudioCaps caps(format,
iChannels > 1? 2: 1,
iFrame->sample_rate);
- this->m_audioConvert->setProperty("caps", caps.toString());
+ // SB: FIXME - call to setProperty is done from another thread, and thus crashing... For now, we don't care much, since we don't have audio in our stream
+ //this->m_audioConvert->setProperty("caps", caps.toString());
this->m_audioConvert->setState(AkElement::ElementStatePlaying);
}
diff --git a/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/mediasourceffmpeg.cpp b/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/mediasourceffmpeg.cpp
index 6f56195e..7b404ca3 100644
--- a/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/mediasourceffmpeg.cpp
+++ b/external/webcamoid/Plugins/MultiSrc/src/ffmpeg/src/mediasourceffmpeg.cpp
@@ -18,8 +18,8 @@
*/
#include
-#include
#include
+#include
#include "mediasourceffmpeg.h"
#include "videostream.h"
@@ -509,9 +509,8 @@ bool MediaSourceFFmpeg::setState(AkElement::ElementState state)
this->m_globalClock.setClock(0.);
this->m_run = true;
this->m_readPacketsLoopResult =
- QtConcurrent::run(&this->m_threadPool,
- this,
- &MediaSourceFFmpeg::readPackets);
+ QtConcurrent::run(&this->m_threadPool,[=]{MediaSourceFFmpeg::readPackets();});
+ // &MediaSourceFFmpeg::readPackets, this);
this->m_curState = state;
return true;
@@ -631,9 +630,8 @@ void MediaSourceFFmpeg::reconnectStream(){
void MediaSourceFFmpeg::packetConsumed()
{
- QtConcurrent::run(&this->m_threadPool,
- this,
- &MediaSourceFFmpeg::unlockQueue);
+ QtConcurrent::run(&this->m_threadPool,[=]{MediaSourceFFmpeg::unlockQueue();});
+ //&MediaSourceFFmpeg::unlockQueue, this);
}
bool MediaSourceFFmpeg::initContext()
@@ -646,13 +644,13 @@ bool MediaSourceFFmpeg::initContext()
AVInputFormat *inputFormat = nullptr;
AVDictionary *inputOptions = nullptr;
- if (QRegExp("/dev/video\\d*").exactMatch(uri))
+ if (QRegularExpression("/dev/video\\d*").match(uri).hasMatch())
inputFormat = av_find_input_format("v4l2");
- else if (QRegExp(":\\d+\\.\\d+(?:\\+\\d+,\\d+)?").exactMatch(uri)) {
+ else if (QRegularExpression(":\\d+\\.\\d+(?:\\+\\d+,\\d+)?").match(uri).hasMatch()) {
inputFormat = av_find_input_format("x11grab");
- int width = this->roundDown(QApplication::desktop()->width(), 4);
- int height = this->roundDown(QApplication::desktop()->height(), 4);
+ int width = this->roundDown(QGuiApplication::primaryScreen()->size().width(), 4);
+ int height = this->roundDown(QGuiApplication::primaryScreen()->size().height(), 4);
av_dict_set(&inputOptions,
"video_size",
@@ -664,7 +662,7 @@ bool MediaSourceFFmpeg::initContext()
// draw_mouse (int)
}
else if (uri == "pulse" ||
- QRegExp("hw:\\d+").exactMatch(uri))
+ QRegularExpression("hw:\\d+").match(uri).hasMatch())
inputFormat = av_find_input_format("alsa");
else if (uri == "/dev/dsp")
inputFormat = av_find_input_format("oss");
@@ -687,7 +685,7 @@ bool MediaSourceFFmpeg::initContext()
QString uriCopy = uri;
for (const QString &schemer: mmsSchemes)
- uriCopy.replace(QRegExp(QString("^%1").arg(schemer)),
+ uriCopy.replace(QRegularExpression(QString("^%1").arg(schemer)),
scheme);
inputContext = nullptr;
diff --git a/external/webcamoid/Plugins/VirtualCamera/CMakeLists.txt b/external/webcamoid/Plugins/VirtualCamera/CMakeLists.txt
index 16811f0d..f4cc25db 100644
--- a/external/webcamoid/Plugins/VirtualCamera/CMakeLists.txt
+++ b/external/webcamoid/Plugins/VirtualCamera/CMakeLists.txt
@@ -3,10 +3,10 @@ message(STATUS "Building ${PLUGIN_NAME} Plugin.")
add_definitions(-DUNICODE)
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
include_directories(
${AVKYS_PLUGIN_INCLUDES}
@@ -36,15 +36,15 @@ set (plugin_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(plugin_moc_srcs ${plugin_headers})
+QT_WRAP_CPP(plugin_moc_srcs ${plugin_headers})
-QT5_ADD_RESOURCES(plugin_qrc_srcs ${plugin_qrc})
+QT6_ADD_RESOURCES(plugin_qrc_srcs ${plugin_qrc})
add_library(${PLUGIN_NAME} SHARED ${plugin_srcs} ${plugin_headers} ${plugin_moc_srcs} ${plugin_qrc_srcs})
# qt5_use_modules(${PLUGIN_NAME} Core Concurrent Gui Qml)
-target_link_libraries(${PLUGIN_NAME} Qt5::Core Qt5::Concurrent Qt5::Gui Qt5::Qml)
+target_link_libraries(${PLUGIN_NAME} Qt6::Core Qt6::Concurrent Qt6::Gui Qt6::Qml)
target_link_libraries(${PLUGIN_NAME} ${AVKYS_PLUGIN_LIBRARIES})
-install(TARGETS ${PLUGIN_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH})
+install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH})
#submodule(s)
FILE(MAKE_DIRECTORY ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
diff --git a/external/webcamoid/Plugins/VirtualCamera/src/dshow/CMakeLists.txt b/external/webcamoid/Plugins/VirtualCamera/src/dshow/CMakeLists.txt
index 5ba54aa6..5c13a320 100644
--- a/external/webcamoid/Plugins/VirtualCamera/src/dshow/CMakeLists.txt
+++ b/external/webcamoid/Plugins/VirtualCamera/src/dshow/CMakeLists.txt
@@ -6,11 +6,11 @@ SET(LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
#Very important to get .lib files
SET(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
-find_package(Qt5Widgets REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
+find_package(Qt6Widgets REQUIRED)
add_subdirectory(VirtualCameraFilter)
@@ -45,9 +45,9 @@ set (submodule_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
+QT_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
-QT5_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
+QT6_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
set (dshow_additional_libs
@@ -60,6 +60,6 @@ set (dshow_additional_libs
add_library(${SUBMMODULE_NAME} SHARED ${submodule_srcs} ${submodule_headers} ${submodule_moc_srcs} ${submodule_qrc_srcs})
# qt5_use_modules(${SUBMMODULE_NAME} Core Concurrent Widgets Gui Qml)
-target_link_libraries(${SUBMMODULE_NAME} Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Gui Qt5::Qml)
+target_link_libraries(${SUBMMODULE_NAME} Qt6::Core Qt6::Concurrent Qt6::Widgets Qt6::Gui Qt6::Qml)
target_link_libraries(${SUBMMODULE_NAME} ${AVKYS_PLUGIN_LIBRARIES} ${dshow_additional_libs} ipc)
-install(TARGETS ${SUBMMODULE_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
+install(TARGETS ${SUBMMODULE_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
diff --git a/external/webcamoid/Plugins/VirtualCamera/src/dshow/src/cameraoutdshow.cpp b/external/webcamoid/Plugins/VirtualCamera/src/dshow/src/cameraoutdshow.cpp
index 3abccd81..0a3c788c 100644
--- a/external/webcamoid/Plugins/VirtualCamera/src/dshow/src/cameraoutdshow.cpp
+++ b/external/webcamoid/Plugins/VirtualCamera/src/dshow/src/cameraoutdshow.cpp
@@ -211,7 +211,7 @@ void CameraOutDShow::writeFrame(const AkPacket &frame)
DWORD(videoFrame.caps().height()),
reinterpret_cast(videoFrame.buffer().constData())) < 1)
{
- qDebug() << "Error writing frame " << videoFrame.caps();
+ //qDebug() << "Error writing frame " << videoFrame.caps();
}
}
diff --git a/external/webcamoid/Plugins/VirtualCamera/src/ffmpeg/CMakeLists.txt b/external/webcamoid/Plugins/VirtualCamera/src/ffmpeg/CMakeLists.txt
index ecc64cff..7d5c5450 100644
--- a/external/webcamoid/Plugins/VirtualCamera/src/ffmpeg/CMakeLists.txt
+++ b/external/webcamoid/Plugins/VirtualCamera/src/ffmpeg/CMakeLists.txt
@@ -13,11 +13,11 @@ add_definitions(-DHAVE_SAMPLEFORMAT64)
SET(LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}/submodules/${PLUGIN_NAME})
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Concurrent REQUIRED)
-find_package(Qt5Gui REQUIRED)
-find_package(Qt5Qml REQUIRED)
-find_package(Qt5Widgets REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Concurrent REQUIRED)
+find_package(Qt6Gui REQUIRED)
+find_package(Qt6Qml REQUIRED)
+find_package(Qt6Widgets REQUIRED)
include_directories(
${AVKYS_PLUGIN_INCLUDES}
@@ -45,17 +45,17 @@ set (submodule_qrc
#This will generate moc_* for Qt
-QT5_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
+QT_WRAP_CPP(submodule_moc_srcs ${submodule_headers})
-QT5_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
+QT6_ADD_RESOURCES(submodule_qrc_srcs ${summodule_qrc})
add_library(${PLUGIN_NAME}_${SUBMMODULE_NAME} SHARED ${submodule_srcs} ${submodule_headers} ${submodule_moc_srcs} ${submodule_qrc_srcs})
set_target_properties(${PLUGIN_NAME}_${SUBMMODULE_NAME} PROPERTIES OUTPUT_NAME "ffmpeg")
# qt5_use_modules(${PLUGIN_NAME}_${SUBMMODULE_NAME} Core Concurrent Widgets Gui Qml)
-target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Gui Qt5::Qml)
+target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} Qt6::Core Qt6::Concurrent Qt6::Widgets Qt6::Gui Qt6::Qml)
target_link_libraries(${PLUGIN_NAME}_${SUBMMODULE_NAME} ${AVKYS_PLUGIN_LIBRARIES} ${FFMPEG_LIBS})
-install(TARGETS ${PLUGIN_NAME}_${SUBMMODULE_NAME} DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
+install(TARGETS ${PLUGIN_NAME}_${SUBMMODULE_NAME} RUNTIME DESTINATION ${AVKYS_LIBRARY_INSTALL_PATH}/submodules/${PLUGIN_NAME})
diff --git a/package/CMakeLists.txt b/package/CMakeLists.txt
index d35b8e07..cad8e749 100644
--- a/package/CMakeLists.txt
+++ b/package/CMakeLists.txt
@@ -1,17 +1,20 @@
-find_package(Qt5Core REQUIRED)
+find_package(Qt6Core REQUIRED)
message(STATUS "Entering package directory.")
include(InstallRequiredSystemLibraries)
-get_target_property(_qt5_qmake_location Qt5::qmake IMPORTED_LOCATION)
+get_target_property(_qt6_qmake_location Qt6::qmake IMPORTED_LOCATION)
execute_process(
- COMMAND "${_qt5_qmake_location}" -query QT_INSTALL_PREFIX
+ COMMAND "${_qt6_qmake_location}" -query QT_INSTALL_PREFIX
RESULT_VARIABLE return_code
- OUTPUT_VARIABLE qt5_install_prefix
+ OUTPUT_VARIABLE qt6_install_prefix
OUTPUT_STRIP_TRAILING_WHITESPACE
)
-message(STATUS "Testing package ${_qt5_qmake_location} ${qt5_install_prefix}")
+message(STATUS "Testing package ${_qt6_qmake_location} ${qt6_install_prefix}")
+
+# Pre-build script, used to clean up unneeded files for example
+set(CPACK_PRE_BUILD_SCRIPTS ${CMAKE_CURRENT_SOURCE_DIR}/cpack-prebuild.cmake)
if (APPLE)
cmake_policy(SET CMP0087 NEW) # Enable generator expressions in INSTALL(CODE
@@ -24,13 +27,13 @@ if (APPLE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# add_custom_target(mac_deploy_qt
-# COMMAND ${qt5_install_prefix}/bin/macdeployqt "$/../.." -always-overwrite -codesign=""
+# COMMAND ${qt6_install_prefix}/bin/macdeployqt "$/../.." -always-overwrite -codesign=""
# COMMENT "Running macdeployqt ..."
# DEPENDS OpenTeraPlus
# )
set(MACSIGNID "")
- set(MACQTDEPLOY_COMMAND "${qt5_install_prefix}/bin/macdeployqt $/../.. -always-overwrite -verbose=1")
+ set(MACQTDEPLOY_COMMAND "${qt6_install_prefix}/bin/macdeployqt $/../.. -always-overwrite -verbose=1")
# message(STATUS "********** ${MACQTDEPLOY_COMMAND}")
@@ -67,8 +70,9 @@ if (WIN32)
# Create files for installation
add_custom_target(windows_deploy_qt
# Collect and copy required dependencies
- COMMAND ${qt5_install_prefix}/bin/windeployqt "$/OpenTeraPlus.exe" --release --dir "${CMAKE_INSTALL_PREFIX}/qtdeploy"
- COMMENT "Running windeployqt ..."
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/qtdeploy
+ COMMAND ${qt6_install_prefix}/bin/windeployqt6 "$/OpenTeraPlus.exe" --release --dir "${CMAKE_INSTALL_PREFIX}/qtdeploy" --no-quick-import --no-compiler-runtime
+ COMMENT "Running windeployqt6 ..."
)
set(CPACK_PACKAGE_NAME "OpenTeraPlus")
@@ -86,10 +90,10 @@ if (WIN32)
set(CPACK_COMPONENT_OPENTERAPLUS_DEPENDS libprotobuf qt_dist_component openssl)
set(CPACK_COMPONENT_OPENTERAPLUS_REQUIRED ON)
- set(CPACK_COMPONENT_QT_DIST_COMPONENT_DISPLAY_NAME "Librairies Qt")
+ set(CPACK_COMPONENT_QT_DIST_COMPONENT_DISPLAY_NAME "Qt")
set(CPACK_COMPONENT_QT_DIST_COMPONENT_REQUIRED ON)
- set(CPACK_COMPONENT_LIBPROTOBUF_DISPLAY_NAME "Librairies Protobuf")
+ set(CPACK_COMPONENT_LIBPROTOBUF_DISPLAY_NAME "Protobuf")
set(CPACK_COMPONENT_LIBPROTOBUF_REQUIRED ON)
set(CPACK_COMPONENT_OPENSSL_DISPLAY_NAME "OpenSSL")
@@ -99,7 +103,7 @@ if (WIN32)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/config/OpenTeraPlus.json")
# The components that will be packaged
set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} special_configuration)
- set(CPACK_COMPONENT_SPECIAL_CONFIGURATION_DISPLAY_NAME "Fichier de configuration")
+ set(CPACK_COMPONENT_SPECIAL_CONFIGURATION_DISPLAY_NAME "Configuration")
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/config/OpenTeraPlus.json DESTINATION bin/config COMPONENT special_configuration)
endif()
@@ -107,26 +111,31 @@ if (WIN32)
# list(APPEND CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait 'cmd /c $INSTDIR\\\\bin\\\\installDriver.exe'")
# list(APPEND CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "ExecWait 'cmd /c $INSTDIR\\\\bin\\\\uninstallDriver.exe'")
-
# add SSL librariesOpenSSL\Win_x64\bin
- # file(GLOB OPENSSL_LIBRARIES "${qt5_install_prefix}/../../Tools/OpenSSL/Win_x64/bin/*.dll")
+ # file(GLOB OPENSSL_LIBRARIES "${qt6_install_prefix}/../../Tools/OpenSSL/Win_x64/bin/*.dll")
file(GLOB OPENSSL_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/openssl/64bits/*.dll")
- message(STATUS "******************* ${OPENSSL_LIBRARIES} ${qt5_install_prefix} ${CPACK_PACKAGING_INSTALL_PREFIX}")
+ message(STATUS "******************* ${OPENSSL_LIBRARIES} ${qt6_install_prefix} ${CPACK_PACKAGING_INSTALL_PREFIX}")
install(FILES ${OPENSSL_LIBRARIES} DESTINATION bin COMPONENT openssl)
-
# Uses NSIS packaging system on Windows
SET(CPACK_SOURCE_GENERATOR "NSIS")
-
- # SET(CPACK_NSIS_INSTALL_ROOT "C:\\\\INTER")
SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "OpenTeraPlus")
SET(CPACK_NSIS_PACKAGE_NAME "OpenTeraPlus")
SET(CPACK_NSIS_MODIFY_PATH OFF)
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY .)
SET(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
- SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "bin\\\\OpenTeraPlus.exe")
+
+ set(CPACK_NSIS_CREATE_ICONS_EXTRA
+ "CreateShortCut '$DESKTOP\\\\OpenTeraPlus.lnk' '$INSTDIR\\\\bin\\\\OpenTeraPlus.exe'"
+ )
+ set(CPACK_NSIS_DELETE_ICONS_EXTRA
+ "Delete '$DESKTOP\\\\OpenTeraPlus.lnk'"
+ )
+
+ # Removed run after install option, as this caused issue with config file (will run as admin!)
+ # SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "bin\\\\OpenTeraPlus.exe")
SET(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/introlab/openteraplus")
SET(CPACK_NSIS_CONTACT "simon.briere@usherbrooke.ca")
@@ -146,11 +155,16 @@ if (WIN32)
VIAddVersionKey ProductVersion ${CPACK_PACKAGE_VERSION}")
- include(CPack REQUIRED)
+ # Run VC++ redistributable
+ list(APPEND CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\bin\\\\vc_redist.x64.exe\\\" /install /passive /norestart'")
+
+ # The trick is to deploy Qt to a directory and then install the directory in the bin folder
+ install(DIRECTORY ${CMAKE_INSTALL_PREFIX}/qtdeploy/ DESTINATION bin COMPONENT qt_dist_component)
+ # Deploy before packaging
+ add_custom_target(nsis-package DEPENDS windows_deploy_qt package)
- # Run VC++ redistributable
- list(APPEND CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait 'cmd /c $INSTDIR\\\\bin\\\\VC_redist.x64.exe /install /passive /norestart'")
+ include(CPack REQUIRED)
# Set files to install - everything in deploy folder
#install(
@@ -162,11 +176,6 @@ if (WIN32)
# install(CODE " ")
- # The trick is to deploy Qt to a directory and then install the directory in the bin folder
- install(DIRECTORY ${CMAKE_INSTALL_PREFIX}/qtdeploy/ DESTINATION bin COMPONENT qt_dist_component)
-
- # Deploy before packaging
- add_custom_target(nsis-package DEPENDS windows_deploy_qt package)
endif (WIN32)
diff --git a/package/cpack-prebuild.cmake b/package/cpack-prebuild.cmake
new file mode 100644
index 00000000..4193c426
--- /dev/null
+++ b/package/cpack-prebuild.cmake
@@ -0,0 +1,6 @@
+if(WIN32)
+ message("Cleaning unneeded files for package...")
+ file(REMOVE_RECURSE ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/libprotobuf/lib)
+ file(REMOVE_RECURSE ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/openteraplus/lib)
+ file(REMOVE_RECURSE ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/openteraplus/include)
+endif(WIN32)
diff --git a/package/openssl/64bits/libcrypto-1_1-x64.dll b/package/openssl/64bits/libcrypto-1_1-x64.dll
deleted file mode 100644
index d91fe73b..00000000
Binary files a/package/openssl/64bits/libcrypto-1_1-x64.dll and /dev/null differ
diff --git a/package/openssl/64bits/libcrypto-3-x64.dll b/package/openssl/64bits/libcrypto-3-x64.dll
new file mode 100644
index 00000000..370140ba
Binary files /dev/null and b/package/openssl/64bits/libcrypto-3-x64.dll differ
diff --git a/package/openssl/64bits/libssl-1_1-x64.dll b/package/openssl/64bits/libssl-1_1-x64.dll
deleted file mode 100644
index 43baf830..00000000
Binary files a/package/openssl/64bits/libssl-1_1-x64.dll and /dev/null differ
diff --git a/package/openssl/64bits/libssl-3-x64.dll b/package/openssl/64bits/libssl-3-x64.dll
new file mode 100644
index 00000000..708d1ae6
Binary files /dev/null and b/package/openssl/64bits/libssl-3-x64.dll differ
diff --git a/shared/src/CMakeLists.txt b/shared/src/CMakeLists.txt
index 521c2466..70a05c47 100755
--- a/shared/src/CMakeLists.txt
+++ b/shared/src/CMakeLists.txt
@@ -1,5 +1,5 @@
-find_package(Qt5Core REQUIRED)
-find_package(Qt5Multimedia REQUIRED)
+find_package(Qt6Core REQUIRED)
+find_package(Qt6Multimedia REQUIRED)
add_definitions(-DSHAREDLIB_LIBRARY)
if (MSVC)
@@ -8,6 +8,7 @@ if (MSVC)
/wd4910 # Ignore export warnings (C4910) with MSVC
/wd4661 # Ignore no suitable definition for explicit template (C4661)
/wd4251 # Ignore needs to have dll-interface
+ /wd4146 # Ignore unary minus operator applied to unsigned type, result still unsigned
)
endif(MSVC)
@@ -52,23 +53,27 @@ include_directories(
)
#This will generate moc_* for Qt
-qt5_wrap_cpp(sharedlib_moc_srcs ${sharedlib_headers})
+qt6_wrap_cpp(sharedlib_moc_srcs ${sharedlib_headers})
#compile library
-add_library(opentera_shared SHARED ${sharedlib_headers} ${sharedlib_srcs} ${sharedlib_moc_srcs})
-# qt5_use_modules(opentera_shared Core Network)
+if(NOT DEFINED OPENTERA_WEBASSEMBLY)
+ add_library(opentera_shared SHARED ${sharedlib_headers} ${sharedlib_srcs} ${sharedlib_moc_srcs})
+else()
+ add_library(opentera_shared STATIC ${sharedlib_headers} ${sharedlib_srcs} ${sharedlib_moc_srcs})
+endif()
+# qt6_use_modules(opentera_shared Core Network)
set_target_properties(opentera_shared PROPERTIES
INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/bin
INSTALL_RPATH_USE_LINK_PATH TRUE)
-target_link_libraries(opentera_shared Qt5::Core Qt5::Multimedia)
+ target_link_libraries(opentera_shared Qt6::Core)
if (MSVC)
target_compile_definitions(opentera_shared PUBLIC OPENTERAMESSAGES_EXPORT=__declspec\(dllimport\))
endif(MSVC)
# Install target
-install(TARGETS opentera_shared DESTINATION ${CMAKE_INSTALL_BINDIR})
+install(TARGETS opentera_shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
set(OPENTERA_SHARED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/data CACHE INTERNAL "doc string")
set(OPENTERA_SHARED_LIBS "opentera_shared" CACHE INTERNAL "doc string")
diff --git a/shared/src/Logger.cpp b/shared/src/Logger.cpp
index eb18782d..b41e59f7 100755
--- a/shared/src/Logger.cpp
+++ b/shared/src/Logger.cpp
@@ -2,11 +2,11 @@
#include
#include
#include
-
+#include
//Singleton
Logger* Logger::m_instance = nullptr;
-QMutex Logger::m_mutex(QMutex::Recursive);
+QRecursiveMutex Logger::m_mutex;
Logger::ActivationPriority Logger::m_active_priority = Logger::DISABLE_PRIORITY; //DISABLE_PRIORITY; //INFO_PRIORITY; //
diff --git a/shared/src/Logger.h b/shared/src/Logger.h
index 41ca4e07..84806018 100755
--- a/shared/src/Logger.h
+++ b/shared/src/Logger.h
@@ -165,7 +165,7 @@ class SHAREDLIB_EXPORT Logger : public QObject
///The file where to log
QFile m_file;
///Mutex for thread safety
- static QMutex m_mutex;
+ static QRecursiveMutex m_mutex;
///Msg Priority
static ActivationPriority m_active_priority;
diff --git a/shared/src/SimpleCrypt.cpp b/shared/src/SimpleCrypt.cpp
index 278e6dde..a259ae67 100644
--- a/shared/src/SimpleCrypt.cpp
+++ b/shared/src/SimpleCrypt.cpp
@@ -26,11 +26,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "SimpleCrypt.h"
#include
+#include
#include
#include
#include
#include
#include
+#include
SimpleCrypt::SimpleCrypt():
m_key(0),
@@ -38,7 +40,7 @@ SimpleCrypt::SimpleCrypt():
m_protectionMode(ProtectionChecksum),
m_lastError(ErrorNoError)
{
- qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
+ srand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
}
SimpleCrypt::SimpleCrypt(quint64 key):
@@ -47,7 +49,7 @@ SimpleCrypt::SimpleCrypt(quint64 key):
m_protectionMode(ProtectionChecksum),
m_lastError(ErrorNoError)
{
- qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
+ srand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
splitKey();
}
@@ -93,7 +95,7 @@ QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext)
flags |= CryptoFlagCompression;
} else if (m_compressionMode == CompressionAuto) {
QByteArray compressed = qCompress(ba, 9);
- if (compressed.count() < ba.count()) {
+ if (compressed.size() < ba.size()) {
ba = compressed;
flags |= CryptoFlagCompression;
}
@@ -103,7 +105,7 @@ QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext)
if (m_protectionMode == ProtectionChecksum) {
flags |= CryptoFlagChecksum;
QDataStream s(&integrityProtection, QIODevice::WriteOnly);
- s << qChecksum(ba.constData(), ba.length());
+ s << qChecksum(QByteArrayView(ba));
} else if (m_protectionMode == ProtectionHash) {
flags |= CryptoFlagHash;
QCryptographicHash hash(QCryptographicHash::Sha1);
@@ -113,13 +115,13 @@ QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext)
}
//prepend a random char to the string
- char randomChar = char(qrand() & 0xFF);
+ char randomChar = char(rand() & 0xFF);
ba = randomChar + integrityProtection + ba;
int pos(0);
char lastChar(0);
- int cnt = ba.count();
+ auto cnt = ba.size();
while (pos < cnt) {
ba[pos] = ba.at(pos) ^ m_keyParts.at(pos % 8) ^ lastChar;
@@ -188,7 +190,7 @@ QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher)
QByteArray ba = cypher;
- if( cypher.count() < 3 )
+ if( cypher.size() < 3 )
return QByteArray();
char version = ba.at(0);
@@ -203,7 +205,7 @@ QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher)
ba = ba.mid(2);
int pos(0);
- int cnt(ba.count());
+ auto cnt(ba.size());
char lastChar = 0;
while (pos < cnt) {
@@ -227,7 +229,7 @@ QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher)
s >> storedChecksum;
}
ba = ba.mid(2);
- quint16 checksum = qChecksum(ba.constData(), ba.length());
+ quint16 checksum = qChecksum(QByteArrayView(ba));
integrityOk = (checksum == storedChecksum);
} else if (flags.testFlag(CryptoFlagHash)) {
if (ba.length() < 20) {
diff --git a/shared/src/SimpleCrypt.h b/shared/src/SimpleCrypt.h
index 7e9cf44b..20de635d 100644
--- a/shared/src/SimpleCrypt.h
+++ b/shared/src/SimpleCrypt.h
@@ -27,6 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SIMPLECRYPT_H
#define SIMPLECRYPT_H
+
+#include "SharedLib.h"
#include
#include
#include
@@ -54,7 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SimpleCrypt is prepared for the case that the encryption and decryption
algorithm is changed in a later version, by prepending a version identifier to the cypertext.
*/
-class SimpleCrypt
+class SHAREDLIB_EXPORT SimpleCrypt
{
public:
/**
diff --git a/shared/src/Utils.cpp b/shared/src/Utils.cpp
index 812247fd..bfa6447f 100644
--- a/shared/src/Utils.cpp
+++ b/shared/src/Utils.cpp
@@ -1,4 +1,5 @@
#include "Utils.h"
+#include
Utils::Utils(QObject *parent) : QObject(parent)
{
@@ -16,7 +17,7 @@ QString Utils::generatePassword(const int &len)
password.clear();
for(int i=0; ibounded(possibleCharacters.length());
+ auto index = QRandomGenerator::global()->bounded(possibleCharacters.length());
QChar nextChar = possibleCharacters.at(index);
password.append(nextChar);
}
@@ -33,23 +34,24 @@ QList Utils::validatePassword(const QString &pa
errors.append(PASSWORD_LENGTH);
}
- QRegExp validator("[A-Z]");
- if (validator.indexIn(password) == -1){
+ QRegularExpression validator("[A-Z]");
+
+ if (!validator.match(password).hasMatch()){
errors.append(PASSWORD_NOCAPS);
}
validator.setPattern("[a-z]");
- if (validator.indexIn(password) == -1){
+ if (!validator.match(password).hasMatch()){
errors.append(PASSWORD_NONOCAPS);
}
validator.setPattern("[0-9]");
- if (validator.indexIn(password) == -1){
+ if (!validator.match(password).hasMatch()){
errors.append(PASSWORD_NODIGITS);
}
validator.setPattern("[^A-Za-z0-9]");
- if (validator.indexIn(password) == -1){
+ if (!validator.match(password).hasMatch()){
errors.append(PASSWORD_NOCHAR);
}
@@ -79,66 +81,14 @@ QString Utils::getMachineUniqueId()
return machine_id;
}
-QStringList Utils::getAudioDeviceNames()
-{
- QStringList names;
- QList audio_devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
- foreach(QAudioDeviceInfo input, audio_devices){
-#ifdef Q_OS_LINUX
- // On linux, since Qt use ALSA API, we must filter the returned device list...
- if (input.deviceName().startsWith("alsa_input") || input.deviceName() == "default"){
- QString filtered_name = input.deviceName();
- if (input.deviceName() != "default"){
- QStringList name_parts = filtered_name.split(".");
- // Removes first part - usually is "alsa_input"
- if (name_parts.count()>1)
- filtered_name = name_parts[1];
-
- // Split using "_" to remove first and last part, and replace others with spaces
- name_parts = filtered_name.split("_");
- if (name_parts.count()>2){
- filtered_name = "";
- for (int i=1; i1)
- filtered_name += " ";
- filtered_name += name_parts[i];
- }
- }else{
- // No audio name...
- name_parts = filtered_name.split("-");
- if (name_parts.count()>2){
- filtered_name = name_parts[1].replace("_", ":");
- }
- }
-
- }
- names.append(filtered_name);
- }
-#else
- names.append(input.deviceName());
-#endif
- }
- return names;
-}
-
-QStringList Utils::getVideoDeviceNames()
-{
- QStringList names;
- QList video_devices = QCameraInfo::availableCameras();
- for (const QCameraInfo &camera:qAsConst(video_devices)){
- names.append(camera.description());
- }
- return names;
-}
-
void Utils::inStringUnicodeConverter(QString *str)
{
if (str->contains("\\u")) {
do {
- int idx = str->indexOf("\\u");
+ auto idx = str->indexOf("\\u");
QString strHex = str->mid(idx, 6);
strHex = strHex.replace("\\u", QString());
- int nHex = strHex.toInt(0, 16);
+ auto nHex = strHex.toInt(nullptr, 16);
str->replace(idx, 6, QChar(nHex));
} while (str->indexOf("\\u") != -1);
}
@@ -151,7 +101,7 @@ QString Utils::removeAccents(const QString &s) {
QString output = "";
for (int i = 0; i < s.length(); i++) {
QChar c = s[i];
- int dIndex = diacriticLetters_.indexOf(c);
+ auto dIndex = diacriticLetters_.indexOf(c);
if (dIndex < 0) {
output.append(c);
} else {
@@ -217,4 +167,3 @@ QString Utils::formatDuration(const QString &duration)
}
return video_duration.toString("hh:mm:ss");
}
-
diff --git a/shared/src/Utils.h b/shared/src/Utils.h
index 4162296e..4e6be93c 100644
--- a/shared/src/Utils.h
+++ b/shared/src/Utils.h
@@ -1,17 +1,16 @@
#ifndef UTILS_H
#define UTILS_H
+#include "SharedLib.h"
#include
#include
#include
#include
#include
#include
-#include
-#include
#include
-class Utils : public QObject
+class SHAREDLIB_EXPORT Utils : public QObject
{
Q_OBJECT
public:
@@ -30,9 +29,6 @@ class Utils : public QObject
static QString getMachineUniqueId();
- static QStringList getAudioDeviceNames();
- static QStringList getVideoDeviceNames();
-
static void inStringUnicodeConverter(QString* str);
static QString removeAccents(const QString& s);
diff --git a/shared/src/WebAPI.h b/shared/src/WebAPI.h
index 42181339..a6b68037 100755
--- a/shared/src/WebAPI.h
+++ b/shared/src/WebAPI.h
@@ -33,6 +33,7 @@
#define WEB_SERVICESITEINFO_PATH "/api/user/services/sites"
#define WEB_SERVICEACCESSINFO_PATH "/api/user/services/access"
#define WEB_SERVICECONFIGINFO_PATH "/api/user/services/configs"
+#define WEB_SERVICEROLEINFO_PATH "/api/user/services/roles"
#define WEB_STATS_PATH "/api/user/stats"
#define WEB_ASSETINFO_PATH "/api/user/assets"
#define WEB_TESTTYPEINFO_PATH "/api/user/testtypes"
@@ -112,6 +113,7 @@
#define WEB_QUERY_START_DATE "start_date"
#define WEB_QUERY_END_DATE "end_date"
#define WEB_QUERY_LOG_LEVEL "log_level"
+#define WEB_QUERY_GLOBALS "globals"
#define WEB_QUERY_WITH_USERGROUPS "with_usergroups"
#define WEB_QUERY_WITH_SITES "with_sites"
@@ -127,6 +129,7 @@
#define WEB_QUERY_WITH_URLS "with_urls"
#define WEB_QUERY_WITH_ONLY_TOKEN "with_only_token"
#define WEB_QUERY_WITH_SESSIONTYPE "with_session_type"
+#define WEB_QUERY_WITH_TESTTYPES "with_test_types"
#define WEB_QUERY_WITH_DEVICES "with_devices"
#define WEB_QUERY_WITH_NAMES "with_names"
diff --git a/shared/src/data/TeraAsset.h b/shared/src/data/TeraAsset.h
index a328a450..fddf55b0 100644
--- a/shared/src/data/TeraAsset.h
+++ b/shared/src/data/TeraAsset.h
@@ -1,11 +1,12 @@
#ifndef TERAASSET_H
#define TERAASSET_H
+#include "SharedLib.h"
#include
// #include
// #include
-class TeraAsset : public QObject
+class SHAREDLIB_EXPORT TeraAsset : public QObject
{
Q_OBJECT
public:
diff --git a/shared/src/data/TeraData.cpp b/shared/src/data/TeraData.cpp
index 3f18cd03..a194b788 100644
--- a/shared/src/data/TeraData.cpp
+++ b/shared/src/data/TeraData.cpp
@@ -53,7 +53,7 @@ QString TeraData::getUuid() const
{
QVariant raw_uuid = getFieldValue(m_uuidField);
- if (raw_uuid.isValid() && raw_uuid.canConvert(QMetaType::QString)){
+ if (raw_uuid.isValid() && raw_uuid.canConvert()){
return raw_uuid.toString();
}
return "";
@@ -170,7 +170,7 @@ void TeraData::updateFrom(const TeraData &other)
void TeraData::updateFrom(const QJsonObject &object)
{
QVariantHash fields = object.toVariantHash();
- for(const QVariant &field_value:qAsConst(fields)){
+ for(const QVariant &field_value:std::as_const(fields)){
m_fieldsValue[fields.key(field_value)] = field_value;
}
}
@@ -293,6 +293,8 @@ QString TeraData::getDataTypeName(const TeraDataTypes &data_type)
return "service_access";
case TERADATA_SERVICE_CONFIG:
return "service_config";
+ case TERADATA_SERVICE_ROLE:
+ return "service_role";
case TERADATA_STATS:
return "stats";
case TERADATA_USERPREFERENCE:
@@ -370,9 +372,11 @@ QString TeraData::getDataTypeNameText(const TeraDataTypes &data_type)
case TERADATA_SERVICE_SITE:
return tr("Service: site");
case TERADATA_SERVICE_ACCESS:
- return tr("Service: Accès");
+ return tr("Service: accès");
case TERADATA_SERVICE_CONFIG:
- return tr("Service: Configuration");
+ return tr("Service: configuration");
+ case TERADATA_SERVICE_ROLE:
+ return tr("Service: rôle");
case TERADATA_STATS:
return tr("Statistiques");
case TERADATA_ONLINE_DEVICE:
@@ -420,6 +424,7 @@ TeraDataTypes TeraData::getDataTypeFromPath(const QString &path)
if (path==WEB_SERVICESITEINFO_PATH) return TERADATA_SERVICE_SITE;
if (path==WEB_SERVICEACCESSINFO_PATH) return TERADATA_SERVICE_ACCESS;
if (path==WEB_SERVICECONFIGINFO_PATH) return TERADATA_SERVICE_CONFIG;
+ if (path==WEB_SERVICEROLEINFO_PATH) return TERADATA_SERVICE_ROLE;
if (path==WEB_USERUSERGROUPINFO_PATH) return TERADATA_USERUSERGROUP;
if (path==WEB_USERPREFSINFO_PATH) return TERADATA_USERPREFERENCE;
if (path==WEB_STATS_PATH) return TERADATA_STATS;
@@ -455,6 +460,7 @@ QString TeraData::getPathForDataType(const TeraDataTypes &data_type)
if (data_type==TERADATA_DEVICESUBTYPE) return WEB_DEVICESUBTYPE_PATH;
if (data_type==TERADATA_DEVICETYPE) return WEB_DEVICETYPE_PATH;
if (data_type==TERADATA_SERVICE) return WEB_SERVICEINFO_PATH;
+ if (data_type==TERADATA_SERVICE_ACCESS) return WEB_SERVICEACCESSINFO_PATH;
if (data_type==TERADATA_SITEACCESS) return WEB_SITEACCESS_PATH;
if (data_type==TERADATA_SERVICE_CONFIG) return WEB_SERVICECONFIGINFO_PATH;
if (data_type==TERADATA_ASSET) return WEB_ASSETINFO_PATH;
@@ -478,7 +484,7 @@ QString TeraData::getIconFilenameForDataType(const TeraDataTypes &data_type)
case TERADATA_SITE:
case TERADATA_SERVICE_SITE:
case TERADATA_SESSIONTYPESITE:
- return "://icons/site.png";
+ return "://icons/site-icon.png";
case TERADATA_SESSIONTYPE:
return "://icons/session_type.png";
case TERADATA_SESSION:
@@ -496,7 +502,7 @@ QString TeraData::getIconFilenameForDataType(const TeraDataTypes &data_type)
case TERADATA_PROJECT:
case TERADATA_SERVICE_PROJECT:
case TERADATA_SESSIONTYPEPROJECT:
- return "://icons/project.png";
+ return "://icons/project-icon.png";
case TERADATA_DEVICESUBTYPE:
case TERADATA_DEVICETYPE:
return "://icons/kit.png";
@@ -550,6 +556,13 @@ QString TeraData::getIconStateFilename() const
if (isEnabled())
return "://icons/patient_installed.png";
return "://icons/patient.png";
+ case TERADATA_PROJECT:
+ if (isEnabled() || !hasEnabledField()){
+ return "://icons/project.png";
+ }else{
+ return "://icons/project_disabled.png";
+ }
+ break;
default:
return "://icons/error.png";
}
@@ -634,14 +647,14 @@ QJsonObject TeraData::toJson(const QString specific_fieldName)
}
// Ignore "metaObject" properties
QVariant fieldData = getFieldValue(fieldName);
- if (fieldData.canConvert(QMetaType::QString)){
+ if (fieldData.canConvert()){
QDateTime date_tester = QDateTime::fromString(fieldData.toString(), Qt::ISODateWithMs);
if (date_tester.isValid()){
object[fieldName] = fieldData.toDateTime().toString(Qt::ISODateWithMs);
}else{
object[fieldName] = fieldData.toString();
}
- }else if (fieldData.canConvert(QMetaType::QJsonValue)){
+ }else if (fieldData.canConvert()){
object[fieldName] = fieldData.toJsonValue();
}else{
LOG_WARNING("Field " + fieldName + " can't be 'jsonized'", "TeraData::toJson");
@@ -653,8 +666,10 @@ QJsonObject TeraData::toJson(const QString specific_fieldName)
bool TeraData::fromMap(const QVariantMap &map)
{
- foreach(QVariant value, map){
- QString key = map.key(value);
+ QStringList keys = map.keys();
+
+ foreach(QString key, keys){
+ QVariant value = map.value(key);
setFieldValue(key, value);
}
diff --git a/shared/src/data/TeraData.h b/shared/src/data/TeraData.h
index 0a9f6ea1..2144ce4a 100644
--- a/shared/src/data/TeraData.h
+++ b/shared/src/data/TeraData.h
@@ -11,6 +11,7 @@
#include "WebAPI.h"
#include "ParticipantWebAPI.h"
+#include "SharedLib.h"
enum TeraDataTypes {
TERADATA_NONE,
@@ -42,6 +43,7 @@ enum TeraDataTypes {
TERADATA_SERVICE_PROJECT,
TERADATA_SERVICE_SITE,
TERADATA_SERVICE_ACCESS,
+ TERADATA_SERVICE_ROLE,
TERADATA_SERVICE_CONFIG,
TERADATA_STATS,
TERADATA_ONLINE_USER,
@@ -55,7 +57,7 @@ enum TeraDataTypes {
Q_DECLARE_METATYPE(TeraDataTypes)
-class TeraData : public QObject
+class SHAREDLIB_EXPORT TeraData : public QObject
{
Q_OBJECT
diff --git a/shared/src/data/TeraPreferences.h b/shared/src/data/TeraPreferences.h
index b86b6e30..c9dc00d6 100644
--- a/shared/src/data/TeraPreferences.h
+++ b/shared/src/data/TeraPreferences.h
@@ -4,8 +4,9 @@
#include
#include "TeraData.h"
#include
+#include "SharedLib.h"
-class TeraPreferences : public QObject
+class SHAREDLIB_EXPORT TeraPreferences : public QObject
{
Q_OBJECT
diff --git a/shared/src/data/TeraSessionCategory.h b/shared/src/data/TeraSessionCategory.h
index e8c4e6b9..5d963b81 100644
--- a/shared/src/data/TeraSessionCategory.h
+++ b/shared/src/data/TeraSessionCategory.h
@@ -2,8 +2,9 @@
#define TERASESSIONCATEGORY_H
#include
+#include "SharedLib.h"
-class TeraSessionCategory : public QObject
+class SHAREDLIB_EXPORT TeraSessionCategory : public QObject
{
Q_OBJECT
public:
diff --git a/shared/src/data/TeraSessionEvent.h b/shared/src/data/TeraSessionEvent.h
index 32a0cd0c..a44d24e0 100644
--- a/shared/src/data/TeraSessionEvent.h
+++ b/shared/src/data/TeraSessionEvent.h
@@ -2,8 +2,9 @@
#define TERASESSIONEVENT_H
#include
+#include "SharedLib.h"
-class TeraSessionEvent : public QObject
+class SHAREDLIB_EXPORT TeraSessionEvent : public QObject
{
Q_OBJECT
public:
diff --git a/shared/src/data/TeraSessionStatus.h b/shared/src/data/TeraSessionStatus.h
index c1a7430f..930a62ad 100644
--- a/shared/src/data/TeraSessionStatus.h
+++ b/shared/src/data/TeraSessionStatus.h
@@ -2,8 +2,9 @@
#define TERASESSIONSTATUS_H
#include
+#include "SharedLib.h"
-class TeraSessionStatus : public QObject
+class SHAREDLIB_EXPORT TeraSessionStatus : public QObject
{
Q_OBJECT
public:
diff --git a/shared/src/data/TeraSettings.h b/shared/src/data/TeraSettings.h
index 23672ab0..04cb3aa5 100644
--- a/shared/src/data/TeraSettings.h
+++ b/shared/src/data/TeraSettings.h
@@ -2,6 +2,7 @@
#define TERASETTINGS_H
#include
+#include "SharedLib.h"
#define SETTINGS_UI_ADVANCEDVIEW "ui_advancedView"
#define SETTINGS_UI_FILTERINACTIVE "ui_filterInactives"
@@ -13,7 +14,7 @@
#define SETTINGS_LASTLANGUAGE "lastLanguage"
#define SETTINGS_DATA_SAVEPATH "dataSavePath"
-class TeraSettings
+class SHAREDLIB_EXPORT TeraSettings
{
public:
TeraSettings();
diff --git a/shared/src/data/TeraTest.h b/shared/src/data/TeraTest.h
index 12c60c86..470a54cb 100644
--- a/shared/src/data/TeraTest.h
+++ b/shared/src/data/TeraTest.h
@@ -2,8 +2,9 @@
#define TERATEST_H
#include
+#include "SharedLib.h"
-class TeraTest : public QObject
+class SHAREDLIB_EXPORT TeraTest : public QObject
{
Q_OBJECT
public:
diff --git a/shared/src/qrcodegen.hpp b/shared/src/qrcodegen.hpp
index 208a6c68..23bb6c79 100644
--- a/shared/src/qrcodegen.hpp
+++ b/shared/src/qrcodegen.hpp
@@ -23,6 +23,7 @@
#pragma once
+#include "SharedLib.h"
#include
#include
#include
diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt
new file mode 100644
index 00000000..47c9163a
--- /dev/null
+++ b/wasm/CMakeLists.txt
@@ -0,0 +1,143 @@
+project(OpenTeraPlusWebAssembly)
+
+#Look for minimum cmake version
+cmake_minimum_required(VERSION 3.21)
+
+# Software version
+SET(CPACK_PACKAGE_VERSION_MAJOR "1")
+SET(CPACK_PACKAGE_VERSION_MINOR "2")
+SET(CPACK_PACKAGE_VERSION_PATCH "0")
+SET(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
+
+add_definitions(-DOPENTERAPLUS_VERSION="${CPACK_PACKAGE_VERSION}" )
+add_definitions(-DOPENTERAPLUS_VERSION_MAJOR="${CPACK_PACKAGE_VERSION_MAJOR}" )
+add_definitions(-DOPENTERAPLUS_VERSION_MINOR="${CPACK_PACKAGE_VERSION_MINOR}" )
+add_definitions(-DOPENTERAPLUS_VERSION_PATCH="${CPACK_PACKAGE_VERSION_PATCH}" )
+add_definitions(-DOPENTERAPLUS_CLIENT_NAME="OpenTeraPlus")
+
+set(CMAKE_CXX_STANDARD 17)
+
+# Compile in debug or release mode
+if(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE Release)
+ #set(CMAKE_BUILD_TYPE Debug)
+endif(NOT CMAKE_BUILD_TYPE)
+
+# Building protobuf webasm
+# https://github.com/protocolbuffers/protobuf/releases/download/v22.3/protoc-22.3-win64.zip
+
+if (APPLE)
+ set(protoc_archive_name protoc-22.3-osx-x86_64.zip)
+ set(protobuf_PROTOC_EXE ${CMAKE_CURRENT_BINARY_DIR}/protoc/bin/protoc)
+elseif(WIN32)
+ set(protoc_archive_name protoc-22.3-win64.zip)
+ set(protobuf_PROTOC_EXE ${CMAKE_CURRENT_BINARY_DIR}/protoc/bin/protoc.exe)
+else()
+ set(protoc_archive_name protoc-22.3-linux-x86_64.zip)
+ set(protobuf_PROTOC_EXE ${CMAKE_CURRENT_BINARY_DIR}/protoc/bin/protoc)
+endif()
+
+
+set(protc_binaries_url https://github.com/protocolbuffers/protobuf/releases/download/v22.3/${protoc_archive_name})
+
+# Download Archive
+if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${protoc_archive_name})
+ file(DOWNLOAD
+ ${protc_binaries_url}
+ ${CMAKE_CURRENT_BINARY_DIR}/${protoc_archive_name}
+ TIMEOUT 300 #seconds
+ TLS_VERIFY ON
+ SHOW_PROGRESS)
+endif()
+
+# Extract Archive
+# No protoc, will download native
+file(ARCHIVE_EXTRACT INPUT ${CMAKE_CURRENT_BINARY_DIR}/${protoc_archive_name} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/protoc)
+
+set(ABSL_PROPAGATE_CXX_STD ON)
+set(protobuf_BUILD_EXAMPLES OFF)
+set(protobuf_BUILD_PROTOC_BINARIES OFF)
+set(protobuf_BUILD_LIBPROTOC OFF)
+set(protobuf_BUILD_SHARED_LIBS_DEFAULT OFF)
+set(protobuf_BUILD_TESTS OFF)
+set(protobuf_INSTALL OFF)
+
+add_compile_options(-pthread)
+add_subdirectory(../external/protobuf protobuf)
+
+#Generate messages
+#add_subdirectory(messages/cpp)
+set (MESSAGE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../external/messages/proto)
+FILE(GLOB_RECURSE messages RELATIVE "${MESSAGE_PATH}" "${MESSAGE_PATH}/*.proto")
+FILE(GLOB_RECURSE messages_sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${MESSAGE_PATH}/*.proto")
+add_custom_target(proto_files SOURCES ${messages_sources})
+
+#Message files output directory, will create directory
+set (output_directory ${CMAKE_CURRENT_BINARY_DIR})
+file(MAKE_DIRECTORY ${output_directory})
+
+set (generated_headers "")
+set (generated_srcs "")
+
+# Include path
+set(GOOGLE_PROTO_PATH ${PROJECT_SOURCE_DIR}/../external/protobuf/src)
+
+message(STATUS "GOOGLE_PROTO_PATH: ${GOOGLE_PROTO_PATH}")
+
+#Generate code using protoc compiler
+foreach (file ${messages})
+
+ message(STATUS "Processing : ${file}")
+
+ get_filename_component (name_without_extension ${file} NAME_WE)
+
+ message(STATUS "name_without_extension : ${name_without_extension}")
+
+ set(output_header_file ${output_directory}/${name_without_extension}.pb.h)
+ set(output_src_file ${output_directory}/${name_without_extension}.pb.cc)
+
+ #Complete files to be compiled...
+ list(APPEND generated_headers ${output_header_file})
+ list(APPEND generated_srcs ${output_src_file})
+
+ #Should execute protoc on each .proto files
+ #Ex: protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto
+ add_custom_command(OUTPUT ${output_header_file} ${output_src_file}
+ COMMAND ${protobuf_PROTOC_EXE} -I=${MESSAGE_PATH} -I${GOOGLE_PROTO_PATH} --cpp_out=${output_directory} ${file}
+ DEPENDS ${MESSAGE_PATH}/${file} ${protobuf_PROTOC_EXE}
+ WORKING_DIRECTORY ${MESSAGE_PATH}
+ VERBATIM)
+
+endforeach()
+
+message (STATUS "Headers : ${generated_headers}")
+message (STATUS "Sources : ${generated_srcs}")
+
+include_directories(
+ ${PROJECT_SOURCE_DIR}/../external/protobuf/src
+ ${output_directory}
+)
+
+#compile library
+add_library(opentera_messages STATIC ${generated_headers} ${generated_srcs})
+#Link with protobuf
+target_link_libraries(opentera_messages libprotobuf)
+target_compile_definitions(opentera_messages PUBLIC OPENTERA_PROTOCOL_VERSION=1)
+target_compile_options(opentera_messages PUBLIC -pthread)
+get_target_property(all_includes opentera_messages INCLUDE_DIRECTORIES)
+
+message (STATUS "includes : ${all_includes}")
+
+set(OPENTERA_MESSAGES_INCLUDES ${all_includes} CACHE INTERNAL "doc string")
+set(OPENTERA_MESSAGES_LIBS "opentera_messages" CACHE INTERNAL "doc string")
+
+add_definitions(-DOPENTERA_WEBASSEMBLY=1)
+set(OPENTERA_WEBASSEMBLY ON)
+
+# Shared data
+add_subdirectory(../shared shared)
+
+# Client
+add_subdirectory(../client client)
+
+qt6_finalize_project()