##// END OF EJS Templates
Merge pull request 416 from SciQLop-IPSIS-fork CMake_rework...
jeandet -
r1338:8de1d294b752 merge develop
parent child
Show More
@@ -0,0 +1,6
1 [submodule "external/CatalogueAPI"]
2 path = external/CatalogueAPI
3 url = https://hephaistos.lpp.polytechnique.fr/rhodecode/HG_REPOSITORIES/LPP/INSTRUMENTATION/USERS/JEANDET/CatalogueAPI
4 [submodule "external/libcatalogs"]
5 path = external/libcatalogs
6 url = https://hephaistos.lpp.polytechnique.fr/rhodecode/HG_REPOSITORIES/LPP/SciQLOP_Repos/libcatalogs
@@ -0,0 +1,18
1 [Desktop Entry]
2 Version=1.0
3 Name=QLop
4 Name[en_US]=SciQLOP
5
6 Type=Application
7 GenericName=SciQLOP
8 Comment=SCIentific Qt application for Learning from Observations of Plasmas
9
10 Exec=sciqlopapp
11 Icon=/usr/share/SciQLOP/icons/sciqlopLOGO.svg
12 Terminal=false
13
14 Categories=Qt;Education;Science;
15
16 #MimeType=text/x-python;
17
18
@@ -0,0 +1,5
1 macro(declare_test testname testexe sources libraries)
2 add_executable(${testexe} ${sources})
3 target_link_libraries(${testexe} ${libraries})
4 add_test(NAME ${testname} COMMAND ${testexe})
5 endmacro(declare_test)
@@ -0,0 +1,26
1 #ifndef SCIQLOP_DATASERIESTYPE_H
2 #define SCIQLOP_DATASERIESTYPE_H
3
4 #include <QString>
5
6 enum class DataSeriesType { SCALAR, SPECTROGRAM, VECTOR, UNKNOWN };
7
8 struct DataSeriesTypeUtils {
9 static DataSeriesType fromString(const QString &type)
10 {
11 if (type == QStringLiteral("scalar")) {
12 return DataSeriesType::SCALAR;
13 }
14 else if (type == QStringLiteral("spectrogram")) {
15 return DataSeriesType::SPECTROGRAM;
16 }
17 else if (type == QStringLiteral("vector")) {
18 return DataSeriesType::VECTOR;
19 }
20 else {
21 return DataSeriesType::UNKNOWN;
22 }
23 }
24 };
25
26 #endif // SCIQLOP_DATASERIESTYPE_H
@@ -0,0 +1,33
1 include(sciqlop_tests)
2
3 add_definitions(-DCORE_TESTS_RESOURCES_DIR="${CMAKE_CURRENT_LIST_DIR}/../tests-resources")
4
5
6 declare_test(TestStringUtils TestStringUtils Common/TestStringUtils.cpp "sciqlopcore;Qt5::Test")
7
8 declare_test(TestDataSeriesUtils TestDataSeriesUtils Data/TestDataSeriesUtils.cpp "sciqlopcore;Qt5::Test")
9 declare_test(TestOptionalAxis TestOptionalAxis Data/TestOptionalAxis.cpp "sciqlopcore;Qt5::Test")
10 declare_test(TestSpectrogramSeries TestSpectrogramSeries
11 "Data/TestSpectrogramSeries.cpp;Data/DataSeriesBuilders.h;Data/DataSeriesBuilders.cpp;Data/DataSeriesTestsUtils.h;Data/DataSeriesTestsUtils.cpp"
12 "sciqlopcore;Qt5::Test")
13 declare_test(TestOneDimArrayData TestOneDimArrayData Data/TestOneDimArrayData.cpp "sciqlopcore;Qt5::Test")
14 declare_test(TestScalarSeries TestScalarSeries
15 "Data/TestScalarSeries.cpp;Data/DataSeriesBuilders.h;Data/DataSeriesBuilders.cpp;Data/DataSeriesTestsUtils.h;Data/DataSeriesTestsUtils.cpp"
16 "sciqlopcore;Qt5::Test")
17 declare_test(TestTwoDimArrayData TestTwoDimArrayData Data/TestTwoDimArrayData.cpp "sciqlopcore;Qt5::Test")
18 declare_test(TestVectorSeries TestVectorSeries
19 "Data/TestVectorSeries.cpp;Data/DataSeriesBuilders.h;Data/DataSeriesBuilders.cpp;Data/DataSeriesTestsUtils.h;Data/DataSeriesTestsUtils.cpp"
20 "sciqlopcore;Qt5::Test")
21
22 declare_test(TestDataSourceController TestDataSourceController
23 "DataSource/TestDataSourceController.cpp;DataSource/DataSourceItemBuilder.cpp"
24 "sciqlopcore;Qt5::Test")
25 declare_test(TestDataSourceItem TestDataSourceItem
26 "DataSource/TestDataSourceItem.cpp;DataSource/DataSourceItemBuilder.cpp"
27 "sciqlopcore;Qt5::Test")
28
29 declare_test(TestVariable TestVariable Variable/TestVariable.cpp "sciqlopcore;Qt5::Test")
30 declare_test(TestVariableCacheController TestVariableCacheController Variable/TestVariableCacheController.cpp "sciqlopcore;Qt5::Test")
31 declare_test(TestVariableController TestVariableController Variable/TestVariableController.cpp "sciqlopcore;Qt5::Test")
32 declare_test(TestVariableSync TestVariableSync Variable/TestVariableSync.cpp "sciqlopcore;Qt5::Test")
33
@@ -0,0 +1,13
1 find_package(Doxygen)
2 if(DOXYGEN_FOUND)
3 set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.dox.in)
4 set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
5 configure_file(${doxyfile_in} ${doxyfile} @ONLY)
6
7 add_custom_target(doc
8 COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
9 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
10 COMMENT "Generating API documentation with Doxygen"
11 VERBATIM)
12
13 endif()
@@ -0,0 +1,1
1 Subproject commit 232c863d6217298caf06deafb1dd821063f9efdc
@@ -0,0 +1,1
1 Subproject commit f2fa281306099e7136a288dd70fd97d0e33afa15
@@ -0,0 +1,19
1 #ifndef SCIQLOP_FILTERINGACTION_H
2 #define SCIQLOP_FILTERINGACTION_H
3
4 #include <Common/spimpl.h>
5 #include <QWidgetAction>
6
7 /// A LineEdit inside an action which is able to filter other actions
8 class FilteringAction : public QWidgetAction {
9 public:
10 FilteringAction(QWidget *parent);
11
12 void addActionToFilter(QAction *action);
13
14 private:
15 class FilteringActionPrivate;
16 spimpl::unique_impl_ptr<FilteringActionPrivate> impl;
17 };
18
19 #endif // SCIQLOP_FILTERINGACTION_H
@@ -0,0 +1,27
1 #include "Actions/FilteringAction.h"
2
3 #include <QLineEdit>
4
5 struct FilteringAction::FilteringActionPrivate {
6 QLineEdit *m_FilterLineEdit;
7 QVector<QAction *> m_FilteredActions;
8 };
9
10 FilteringAction::FilteringAction(QWidget *parent)
11 : QWidgetAction(parent), impl{spimpl::make_unique_impl<FilteringActionPrivate>()}
12 {
13 impl->m_FilterLineEdit = new QLineEdit(parent);
14 setDefaultWidget(impl->m_FilterLineEdit);
15
16 connect(impl->m_FilterLineEdit, &QLineEdit::textEdited, [this](auto text) {
17 for (auto action : impl->m_FilteredActions) {
18 auto match = action->text().contains(text, Qt::CaseInsensitive);
19 action->setVisible(match);
20 }
21 });
22 }
23
24 void FilteringAction::addActionToFilter(QAction *action)
25 {
26 impl->m_FilteredActions << action;
27 }
@@ -0,0 +1,2
1 add_subdirectory(mockplugin)
2 add_subdirectory(amda)
@@ -0,0 +1,9
1 sonar.host.url=https://sonarcloud.io
2 sonar.organization=jeandet-github
3 sonar.projectKey=sciqlop
4 sonar.projectName=SciQLOP
5 sonar.projectVersion=1.0
6 sonar.sources=.
7 sonar.language=cpp
8 sonar.exclusions=**/QxOrm/**/*,**/CatalogueAPI/**/*,**/qrc_*.cpp,**/moc_*.cpp,**/mocs_*.cpp
9 sonar.cfamily.build-wrapper-output=build
@@ -0,0 +1,4
1 [wrap-git]
2 directory=libcatalogs
3 url=https://hephaistos.lpp.polytechnique.fr/rhodecode/HG_REPOSITORIES/LPP/SciQLOP_Repos/libcatalogs.git
4 revision=master
@@ -1,18 +1,62
1 
1 cmake_minimum_required(VERSION 3.6)
2 project(SciQLOP CXX)
2
3
3 ## Main CMakeLists for SCIQLOP
4 include(GNUInstallDirs)
4 CMAKE_MINIMUM_REQUIRED (VERSION 3.6.1)
5 cmake_policy(VERSION 3.6)
6
5
7 PROJECT(SCIQLOP)
6 SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake")
8
7
8 OPTION (CPPCHECK "Analyzes the source code with cppcheck" OFF)
9 OPTION (CLANG_TIDY "Analyzes the source code with Clang Tidy" OFF)
10 OPTION (IWYU "Analyzes the source code with Include What You Use" OFF)
9
11
10 #
12 set(CMAKE_CXX_STANDARD 14)
11 # build the CatalogueAPI dependencu
12 #
13 INCLUDE("extern/CatalogueAPI.cmake")
14
13
15 #
14 set(CMAKE_AUTOMOC ON)
16 # build the project
15 #https://gitlab.kitware.com/cmake/cmake/issues/15227
17 #
16 #set(CMAKE_AUTOUIC ON)
18 INCLUDE("cmake/sciqlop.cmake")
17 if(POLICY CMP0071)
18 cmake_policy(SET CMP0071 OLD)
19 endif()
20 set(CMAKE_AUTORCC ON)
21 set(CMAKE_INCLUDE_CURRENT_DIR ON)
22
23 if(NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH)
24 set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
25 endif()
26 if(NOT DEFINED CMAKE_MACOSX_RPATH)
27 set(CMAKE_MACOSX_RPATH TRUE)
28 endif()
29
30 if(NOT CMAKE_BUILD_TYPE)
31 set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
32 endif()
33
34 find_package(Qt5 COMPONENTS Core Widgets Network PrintSupport Svg Test REQUIRED)
35
36 IF(CPPCHECK)
37 set(CMAKE_CXX_CPPCHECK "cppcheck;--enable=warning,style")
38 ENDIF(CPPCHECK)
39
40 IF(CLANG_TIDY)
41 set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-style=file;-checks=*")
42 ENDIF(CLANG_TIDY)
43
44 IF(IWYU)
45 set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use")
46 ENDIF(IWYU)
47
48 enable_testing()
49
50
51 find_package(catalogs CONFIG QUIET)
52 if (NOT CatalogueAPI_FOUND)
53 execute_process(COMMAND git submodule init external/libcatalogs WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
54 execute_process(COMMAND git submodule update external/libcatalogs WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
55 add_subdirectory(external/libcatalogs)
56 endif()
57
58 add_subdirectory(core)
59 add_subdirectory(gui)
60 add_subdirectory(app)
61 add_subdirectory(plugins)
62 add_subdirectory(docs)
@@ -1,157 +1,34
1 include_directories(include)
1
2
2 ## sciqlop - CMakeLists.txt
3 FILE (GLOB_RECURSE app_SRCS
3 SET(EXECUTABLE_NAME "sciqlop")
4 include/*.h
4 SCIQLOP_SET_TO_PARENT_SCOPE(EXECUTABLE_NAME)
5 src/*.cpp
5 SET(SOURCES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/)
6 resources/*.qrc
6 SET(INCLUDES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
7 )
7 SET(UI_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/ui)
8 SET(RES_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/resources)
9
8
10 # Include gui directory
9 QT5_WRAP_UI(UiGenerated_SRCS
11 include_directories("${INCLUDES_DIR}")
10 ui/MainWindow.ui
12
13 #
14 # Find Qt modules
15 #
16 SCIQLOP_FIND_QT(Core Widgets)
17
18
19 #
20 # Find dependent libraries
21 # ========================
22 find_package(sciqlop-gui)
23
24 SET(LIBRARIES ${SCIQLOP-GUI_LIBRARIES})
25 SET(EXTERN_SHARED_LIBRARIES)
26
27 INCLUDE_DIRECTORIES(${SCIQLOP-GUI_INCLUDE_DIR})
28
29 # Add sqpcore to the list of libraries to use
30 list(APPEND LIBRARIES ${SQPCORE_LIBRARY_NAME})
31
32 # Include core directory
33 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../core/include")
34
35 # Add dependent shared libraries
36 list(APPEND SHARED_LIBRARIES ${SQPCORE_SHARED_LIBRARIES})
37
38 # Retrieve the location of the dynamic library to copy it to the output path
39 #get_property(sqpcoreLocation TARGET ${SQPCORE_LIBRARY_NAME} PROPERTY LOCATION)
40 list(APPEND SHARED_LIBRARIES_FROM_TARGETS ${sqpcoreLocation})
41
42 # Ui files
43 FILE (GLOB_RECURSE PROJECT_FORMS ${UI_FOLDER}/*.ui)
44
45 #
46 # Compile the application
47 #
48 FILE (GLOB_RECURSE APPLICATION_SOURCES
49 ${INCLUDES_DIR}/*.h
50 ${SOURCES_DIR}/*.c
51 ${SOURCES_DIR}/*.cpp
52 ${SOURCES_DIR}/*.h
53 ${PROJECT_FORMS})
54
55 FILE (GLOB_RECURSE APPLICATION_RESOURCES ${RES_FOLDER}/*.qrc)
56
57 QT5_ADD_RESOURCES(RCC_HDRS ${APPLICATION_RESOURCES} )
58
59 QT5_WRAP_UI(UIS_HDRS
60 ${PROJECT_FORMS}
61 )
11 )
62
12
63
13 add_executable(sciqlopapp ${app_SRCS} ${UiGenerated_SRCS})
64 ADD_EXECUTABLE(${EXECUTABLE_NAME} ${APPLICATION_SOURCES} ${RCC_HDRS} ${UIS_HDRS})
14 if(NOT BUILD_SHARED_LIBS)
65 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY CXX_STANDARD 14)
15 add_definitions(-DQT_STATICPLUGIN)
66 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
16 target_link_libraries(sciqlopapp mockplugin)
67 target_link_libraries(${EXECUTABLE_NAME}
17 target_link_libraries(sciqlopapp amdaplugin)
68 ${LIBRARIES})
18 endif()
69
19
70 INSTALL(TARGETS ${EXECUTABLE_NAME}
20 target_link_libraries(sciqlopapp
71 RUNTIME DESTINATION ${INSTALL_BINARY_DIR}
21 Qt5::Core
72 LIBRARY DESTINATION ${INSTALL_BINARY_DIR}
22 Qt5::Widgets
73 ARCHIVE DESTINATION ${INSTALL_BINARY_DIR}
23 Qt5::Network
24 Qt5::PrintSupport
25 Qt5::Svg
26 sciqlopgui
27 sciqlopcore
74 )
28 )
75 # Link with Qt5 modules
76 qt5_use_modules(${EXECUTABLE_NAME} Core Widgets)
77
78
79 add_dependencies(${EXECUTABLE_NAME} ${SQPGUI_LIBRARY_NAME} ${SQPCORE_LIBRARY_NAME})
80
81
82
83 # Add the files to the list of files to be analyzed
84 LIST(APPEND CHECKSTYLE_INPUT_FILES ${APPLICATION_SOURCES})
85 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_INPUT_FILES)
86 # Vera++ exclusion files
87 LIST(APPEND CHECKSTYLE_EXCLUSION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vera-exclusions/exclusions.txt)
88 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_EXCLUSION_FILES)
89
90 #
91 # Compile the tests
92 #
93 IF(BUILD_TESTS)
94
95 INCLUDE_DIRECTORIES(${SOURCES_DIR})
96 FILE (GLOB_RECURSE TESTS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test*.cpp)
97 FILE (GLOB_RECURSE TESTS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Test*.h)
98 SET( TEST_LIBRARIES ${LIBRARIES})
99
100 FOREACH( testFile ${TESTS_SOURCES} )
101 GET_FILENAME_COMPONENT( testDirectory ${testFile} DIRECTORY )
102 GET_FILENAME_COMPONENT( testName ${testFile} NAME_WE )
103
104 # Add to the list of sources files all the sources in the same
105 # directory that aren't another test
106 FILE (GLOB currentTestSources
107 ${testDirectory}/*.c
108 ${testDirectory}/*.cpp
109 ${testDirectory}/*.h)
110 LIST (REMOVE_ITEM currentTestSources ${TESTS_SOURCES})
111 LIST (REMOVE_ITEM currentTestSources ${TESTS_HEADERS})
112
113 ADD_EXECUTABLE(${testName} ${testFile} ${currentTestSources})
114 TARGET_LINK_LIBRARIES( ${testName} ${TEST_LIBRARIES})
115 qt5_use_modules(${testName} Test)
116
117 ADD_TEST( NAME ${testName} COMMAND ${testName} )
118
119 SCIQLOP_COPY_TO_TARGET(RUNTIME ${testName})
120 ENDFOREACH( testFile )
121
122 LIST(APPEND testFilesToFormat ${TESTS_SOURCES})
123 LIST(APPEND testFilesToFormat ${TESTS_HEADERS})
124 LIST(APPEND FORMATTING_INPUT_FILES ${testFilesToFormat})
125
126 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
127 ENDIF(BUILD_TESTS)
128
29
129 #
30 install(TARGETS sciqlopapp DESTINATION ${CMAKE_INSTALL_BINDIR})
130 # Set the files that must be formatted by clang-format.
31 install(FILES resources/SciQLOP.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications/)
131 #
32 install(FILES resources/sciqlopLOGO.svg DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/SciQLOP/icons/)
132 LIST (APPEND FORMATTING_INPUT_FILES ${APPLICATION_SOURCES})
133 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
134
33
135 #
136 # Set the directories that doxygen must browse to generate the
137 # documentation.
138 #
139 # Source directories:
140 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/docs")
141 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
142 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_INPUT_DIRS)
143 # Source directories to exclude from the documentation generation
144 #LIST (APPEND DOXYGEN_EXCLUDE_PATTERNS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir/*")
145 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_EXCLUDE_PATTERNS)
146
34
147 #
148 # Set the directories with the sources to analyze and propagate the
149 # modification to the parent scope
150 #
151 # Source directories to analyze:
152 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
153 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
154 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_INPUT_DIRS)
155 # Source directories to exclude from the analysis
156 #LIST (APPEND ANALYSIS_EXCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir")
157 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_EXCLUDE_DIRS)
@@ -25,7 +25,7
25 #include <SqpApplication.h>
25 #include <SqpApplication.h>
26 #include <qglobal.h>
26 #include <qglobal.h>
27
27
28 #include <Plugin/PluginManager.h>
28 #include <PluginManager/PluginManager.h>
29 #include <QDir>
29 #include <QDir>
30 #include <QtPlugin>
30 #include <QtPlugin>
31
31
@@ -53,6 +53,8 int main(int argc, char *argv[])
53 SqpApplication::setOrganizationDomain("lpp.fr");
53 SqpApplication::setOrganizationDomain("lpp.fr");
54 SqpApplication::setApplicationName("SciQLop");
54 SqpApplication::setApplicationName("SciQLop");
55
55
56 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
57
56 SqpApplication a{argc, argv};
58 SqpApplication a{argc, argv};
57
59
58 MainWindow w;
60 MainWindow w;
@@ -133,7 +133,7 MainWindow::MainWindow(QWidget *parent)
133
133
134 auto openInspector = [this](bool checked, bool right, auto action) {
134 auto openInspector = [this](bool checked, bool right, auto action) {
135
135
136 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
136 action->setIcon(QIcon{(checked ^ right) ? ":/icones/next.png" : ":/icones/previous.png"});
137
137
138 auto &lastInspectorSize
138 auto &lastInspectorSize
139 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
139 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
@@ -386,8 +386,8 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget *parentWidget)
386 if (hasChanges) {
386 if (hasChanges) {
387 // There are some unsaved changes
387 // There are some unsaved changes
388 switch (QMessageBox::question(
388 switch (QMessageBox::question(
389 parentWidget, "Save changes",
389 parentWidget, tr("Save changes"),
390 tr("The catalogue controller unsaved changes.\nDo you want to save them ?"),
390 tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"),
391 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
391 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
392 QMessageBox::SaveAll)) {
392 QMessageBox::SaveAll)) {
393 case QMessageBox::SaveAll:
393 case QMessageBox::SaveAll:
@@ -1,173 +1,31
1 ## core - CMakeLists.txt
1 FILE (GLOB_RECURSE core_SRCS
2 STRING(TOLOWER ${CMAKE_PROJECT_NAME} LIBRARY_PREFFIX)
2 include/*.h
3 SET(SQPCORE_LIBRARY_NAME "${LIBRARY_PREFFIX}_core${DEBUG_SUFFIX}")
3 src/*.cpp
4 SET(SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/")
4 )
5 SET(INCLUDES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/")
6 SET(TESTS_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests-resources")
7
5
8 # Include core directory
6 add_definitions(-DCORE_STATIC)
9 include_directories("${INCLUDES_DIR}")
10
7
11 # Set a variable to display a warning in the version files.
8 add_library(sciqlopcore ${core_SRCS})
12 SET(SCIQLOP_CMAKE_GENERATION_WARNING "DON'T CHANGE THIS FILE. AUTOGENERATED BY CMAKE.")
9 SET_TARGET_PROPERTIES(sciqlopcore PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
13 # Generate the version file from the cmake version variables. The version
14 # variables are defined in the cmake/sciqlop_version.cmake file.
15 CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/resources/Version.h.in"
16 "${INCLUDES_DIR}/Version.h")
17 CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/resources/Version.cpp.in"
18 "${SOURCES_DIR}/Version.cpp")
19
10
20 # Find dependent modules
11 target_include_directories(sciqlopcore PUBLIC
21 find_package(sciqlop-plugin)
12 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
22 INCLUDE_DIRECTORIES(${SCIQLOP-PLUGIN_INCLUDE_DIR})
13 $<INSTALL_INTERFACE:include/SciQLOP>
23
24 #
25 # Find Qt modules
26 #
27 SCIQLOP_FIND_QT(Core Network)
28
29 #
30 # Compile the library library
31 #
32
33 ADD_DEFINITIONS(-DCORE_LIB)
34
35 FILE (GLOB_RECURSE MODULE_SOURCES
36 ${INCLUDES_DIR}/*.h
37 ${SOURCES_DIR}/*.c
38 ${SOURCES_DIR}/*.cpp
39 ${SOURCES_DIR}/*.h)
40
41 ADD_LIBRARY(${SQPCORE_LIBRARY_NAME} ${MODULE_SOURCES})
42 set_property(TARGET ${SQPCORE_LIBRARY_NAME} PROPERTY CXX_STANDARD 14)
43 set_property(TARGET ${SQPCORE_LIBRARY_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
44 TARGET_LINK_LIBRARIES(${SQPCORE_LIBRARY_NAME})
45 qt5_use_modules(${SQPCORE_LIBRARY_NAME} Core Network)
46
47 # Find CATALOGUE_API
48 include_directories("${CATALOGUEAPI_INCLUDE}")
49 TARGET_LINK_LIBRARIES(${SQPCORE_LIBRARY_NAME} ${CATALOGUEAPI_LIBRARIES})
50 INSTALL(TARGETS ${SQPCORE_LIBRARY_NAME}
51 RUNTIME DESTINATION ${INSTALL_BINARY_DIR}
52 LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR}
53 ARCHIVE DESTINATION ${INSTALL_LIBRARY_DIR}
54 )
14 )
55
15
56 add_dependencies(${SQPCORE_LIBRARY_NAME} CatalogueAPI)
16 target_link_libraries(sciqlopcore PUBLIC
57
17 Qt5::Core
58 # From cmake documentation: http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
18 Qt5::Network
59 # Entries in the COMPILE_DEFINITIONS are prefixed with -D or /D and added to the compile line in an unspecified order.
19 catalogs
60 # The DEFINE_SYMBOL target property is also added as a compile definition as a special convenience case for SHARED and MODULE library targets
61 IF(BUILD_SHARED_LIBS)
62 SET_TARGET_PROPERTIES(${SQPCORE_LIBRARY_NAME} PROPERTIES COMPILE_DEFINITIONS "SCIQLOP_EXPORT")
63 ELSE()
64 TARGET_COMPILE_DEFINITIONS(${SQPCORE_LIBRARY_NAME} PUBLIC "SCIQLOP_STATIC_LIBRARIES")
65 ENDIF()
66
67 # Set the variable to parent scope so that the other projects can copy the
68 # dependent shared libraries
69 SCIQLOP_SET_TO_PARENT_SCOPE(SQPCORE_LIBRARY_NAME)
70
71 ## Copy extern shared libraries to the lib folder
72 LIST (APPEND ${EXTERN_SHARED_LIBRARIES} ${CATALOGUEAPI_LIBRARIES})
73
74
75 SET (COPY_LIBS_DESTINATION LIBRARY)
76 if(APPLE)
77 SET (COPY_LIBS_DESTINATION RUNTIME)
78 endif()
79
80 add_custom_command(TARGET ${SQPCORE_LIBRARY_NAME} POST_BUILD
81 COMMAND ${CMAKE_COMMAND} -E copy ${CATALOGUEAPI_LIBRARIES} ${EXECUTABLE_OUTPUT_PATH}
82 )
20 )
83
21
84 # Add the files to the list of files to be analyzed
22 install(TARGETS sciqlopcore EXPORT SciQLOPCoreConfig
85 LIST(APPEND CHECKSTYLE_INPUT_FILES ${MODULE_SOURCES})
23 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
86 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_INPUT_FILES)
24 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
87 # Vera++ exclusion files
25 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
88 LIST(APPEND CHECKSTYLE_EXCLUSION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vera-exclusions/exclusions.txt)
89 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_EXCLUSION_FILES)
90
91 #
92 # Compile the tests
93 #
94 IF(BUILD_TESTS)
95 INCLUDE_DIRECTORIES(${SOURCES_DIR})
96 FILE (GLOB_RECURSE TESTS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test*.cpp)
97 FILE (GLOB_RECURSE TESTS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Test*.h)
98 SET( TEST_LIBRARIES ${SQPCORE_LIBRARY_NAME})
99 list(APPEND TEST_LIBRARIES ${CATALOGUEAPI_LIBRARIES})
100
101 SET(TARGETS_COV)
102 FOREACH( testFile ${TESTS_SOURCES} )
103 GET_FILENAME_COMPONENT( testDirectory ${testFile} DIRECTORY )
104 GET_FILENAME_COMPONENT( testName ${testFile} NAME_WE )
105
106 # Add to the list of sources files all the sources in the same
107 # directory that aren't another test
108 FILE (GLOB currentTestSources
109 ${testDirectory}/*.c
110 ${testDirectory}/*.cpp
111 ${testDirectory}/*.h)
112 LIST (REMOVE_ITEM currentTestSources ${TESTS_SOURCES})
113 # LIST (REMOVE_ITEM currentTestSources ${TESTS_HEADERS})
114
115 ADD_EXECUTABLE(${testName} ${testFile} ${currentTestSources})
116 set_property(TARGET ${testName} PROPERTY CXX_STANDARD 14)
117 set_property(TARGET ${testName} PROPERTY CXX_STANDARD_REQUIRED ON)
118 TARGET_LINK_LIBRARIES( ${testName} ${TEST_LIBRARIES})
119 qt5_use_modules(${testName} Test)
120
121 ADD_TEST( NAME ${testName} COMMAND ${testName} )
122
123 set(Coverage_NAME ${testName})
124 if(UNIX)
125 SETUP_TARGET_FOR_COVERAGE(TARGET ${testName}_coverage OUTPUT ${testFile}-path NAME ${testFile} EXECUTABLE ${testName})
126 LIST( APPEND TARGETS_COV ${testName}_coverage)
127 endif(UNIX)
128
129 ENDFOREACH( testFile )
130
131 add_custom_target(coverage)
132
133 FOREACH( target_cov ${TARGETS_COV} )
134 add_custom_command(TARGET coverage PRE_BUILD COMMAND make ${target_cov})
135 ENDFOREACH( target_cov )
136
137 LIST(APPEND testFilesToFormat ${TESTS_SOURCES})
138 LIST(APPEND testFilesToFormat ${TESTS_HEADERS})
139 LIST(APPEND FORMATTING_INPUT_FILES ${testFilesToFormat})
140 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
141
142 ADD_DEFINITIONS(-DCORE_TESTS_RESOURCES_DIR="${TESTS_RESOURCES_DIR}")
143 ENDIF(BUILD_TESTS)
144
145 #
146 # Set the files that must be formatted by clang-format.
147 #
148 LIST (APPEND FORMATTING_INPUT_FILES ${MODULE_SOURCES})
149 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
150
26
151 #
27 install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SciQLOP)
152 # Set the directories that doxygen must browse to generate the
28 install(EXPORT SciQLOPCoreConfig DESTINATION share/SciQLOPCore/cmake)
153 # documentation.
29 export(TARGETS sciqlopcore FILE SciQLOPCoreConfig.cmake)
154 #
155 # Source directories:
156 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/docs")
157 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
158 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_INPUT_DIRS)
159 # Source directories to exclude from the documentation generation
160 #LIST (APPEND DOXYGEN_EXCLUDE_PATTERNS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir/*")
161 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_EXCLUDE_PATTERNS)
162
30
163 #
31 add_subdirectory(tests)
164 # Set the directories with the sources to analyze and propagate the
165 # modification to the parent scope
166 #
167 # Source directories to analyze:
168 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
169 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
170 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_INPUT_DIRS)
171 # Source directories to exclude from the analysis
172 #LIST (APPEND ANALYSIS_EXCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir")
173 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_EXCLUDE_DIRS)
@@ -41,8 +41,7 public:
41 /// retrieveEvents with empty repository retrieve them from the default repository
41 /// retrieveEvents with empty repository retrieve them from the default repository
42 std::list<std::shared_ptr<DBEvent> > retrieveEvents(const QString &repository) const;
42 std::list<std::shared_ptr<DBEvent> > retrieveEvents(const QString &repository) const;
43 std::list<std::shared_ptr<DBEvent> > retrieveAllEvents() const;
43 std::list<std::shared_ptr<DBEvent> > retrieveAllEvents() const;
44 std::list<std::shared_ptr<DBEvent> >
44
45 retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const;
46 void addEvent(std::shared_ptr<DBEvent> event);
45 void addEvent(std::shared_ptr<DBEvent> event);
47 void updateEvent(std::shared_ptr<DBEvent> event);
46 void updateEvent(std::shared_ptr<DBEvent> event);
48 void updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct);
47 void updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct);
@@ -50,17 +49,21 public:
50 // void trashEvent(std::shared_ptr<DBEvent> event);
49 // void trashEvent(std::shared_ptr<DBEvent> event);
51 // void restore(std::shared_ptr<DBEvent> event);
50 // void restore(std::shared_ptr<DBEvent> event);
52 void saveEvent(std::shared_ptr<DBEvent> event);
51 void saveEvent(std::shared_ptr<DBEvent> event);
53 void discardEvent(std::shared_ptr<DBEvent> event);
52 void discardEvent(std::shared_ptr<DBEvent> event, bool &removed);
54 bool eventHasChanges(std::shared_ptr<DBEvent> event) const;
53 bool eventHasChanges(std::shared_ptr<DBEvent> event) const;
55
54
56 // Catalogue
55 // Catalogue
57 // bool createCatalogue(const QString &name, QVector<QUuid> eventList);
56 std::list<std::shared_ptr<DBEvent> >
57 retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const;
58
58 /// retrieveEvents with empty repository retrieve them from the default repository
59 /// retrieveEvents with empty repository retrieve them from the default repository
59 std::list<std::shared_ptr<DBCatalogue> > retrieveCatalogues(const QString &repository
60 std::list<std::shared_ptr<DBCatalogue> > retrieveCatalogues(const QString &repository
60 = QString()) const;
61 = QString()) const;
62 void addCatalogue(std::shared_ptr<DBCatalogue> catalogue);
61 void updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63 void updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
62 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
64 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue);
65 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue);
66 void discardCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool &removed);
64
67
65 void saveAll();
68 void saveAll();
66 bool hasChanges() const;
69 bool hasChanges() const;
@@ -71,6 +74,13 public:
71 /// Returns the list of variables contained in a MIME data
74 /// Returns the list of variables contained in a MIME data
72 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
75 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
73
76
77 /// Returns the MIME data associated to a list of variables
78 QByteArray
79 mimeDataForCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues) const;
80
81 /// Returns the list of variables contained in a MIME data
82 QVector<std::shared_ptr<DBCatalogue> > cataloguesForMimeData(const QByteArray &mimeData) const;
83
74 public slots:
84 public slots:
75 /// Manage init/end of the controller
85 /// Manage init/end of the controller
76 void initialize();
86 void initialize();
@@ -5,6 +5,10
5
5
6 #include <QDateTime>
6 #include <QDateTime>
7
7
8 /// Format for datetimes
9 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
10 const auto DATETIME_FORMAT_ONE_LINE = QStringLiteral("dd/MM/yyyy hh:mm:ss:zzz");
11
8 /**
12 /**
9 * Utility class with methods for dates
13 * Utility class with methods for dates
10 */
14 */
@@ -16,6 +16,7 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
17 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SELECTION_ZONE;
17 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SELECTION_ZONE;
18 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_EVENT_LIST;
18 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_EVENT_LIST;
19 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SOURCE_CATALOGUE_LIST;
19
20
20
21
21 #endif // SCIQLOP_MIMETYPESDEF_H
22 #endif // SCIQLOP_MIMETYPESDEF_H
@@ -75,6 +75,10 public slots:
75 void initialize();
75 void initialize();
76 void finalize();
76 void finalize();
77
77
78 /// Request the creation of a variable from the ID_DATA_KEY of a product
79 void requestVariableFromProductIdKey(const QString &datasourceIdKey);
80
81 /// Request the creation of a variable from metadata of a product
78 void requestVariable(const QVariantHash &productData);
82 void requestVariable(const QVariantHash &productData);
79
83
80 signals:
84 signals:
@@ -145,6 +145,14 public:
145 */
145 */
146 DataSourceItem *findItem(const QVariantHash &data, bool recursive);
146 DataSourceItem *findItem(const QVariantHash &data, bool recursive);
147
147
148 /**
149 * @brief Searches the first child matching the specified \p ID_DATA_KEY in its metadata.
150 * @param id The id to search.
151 * @param recursive So the search recursively.
152 * @return the item matching the data or nullptr if it was not found.
153 */
154 DataSourceItem *findItem(const QString &datasourceIdKey, bool recursive);
155
148 bool operator==(const DataSourceItem &other);
156 bool operator==(const DataSourceItem &other);
149 bool operator!=(const DataSourceItem &other);
157 bool operator!=(const DataSourceItem &other);
150
158
1 NO CONTENT: file renamed from plugin/include/Plugin/IPlugin.h to core/include/Plugin/IPlugin.h
NO CONTENT: file renamed from plugin/include/Plugin/IPlugin.h to core/include/Plugin/IPlugin.h
@@ -14,7 +14,7 Q_DECLARE_LOGGING_CATEGORY(LOG_PluginManager)
14 /**
14 /**
15 * @brief The PluginManager class aims to handle the plugins loaded dynamically into SciQLop.
15 * @brief The PluginManager class aims to handle the plugins loaded dynamically into SciQLop.
16 */
16 */
17 class SCIQLOP_CORE_EXPORT PluginManager {
17 class PluginManager {
18 public:
18 public:
19 explicit PluginManager();
19 explicit PluginManager();
20
20
@@ -4,6 +4,7
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/DataSeriesIterator.h>
6 #include <Data/DataSeriesIterator.h>
7 #include <Data/DataSeriesType.h>
7 #include <Data/SqpRange.h>
8 #include <Data/SqpRange.h>
8
9
9 #include <QLoggingCategory>
10 #include <QLoggingCategory>
@@ -54,6 +55,9 public:
54 /// @return the data of the variable, nullptr if there is no data
55 /// @return the data of the variable, nullptr if there is no data
55 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
56 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
56
57
58 /// @return the type of data that the variable holds
59 DataSeriesType type() const noexcept;
60
57 QVariantHash metadata() const noexcept;
61 QVariantHash metadata() const noexcept;
58
62
59 bool contains(const SqpRange &range) const noexcept;
63 bool contains(const SqpRange &range) const noexcept;
@@ -76,6 +80,8 public:
76
80
77 signals:
81 signals:
78 void updated();
82 void updated();
83 /// Signal emitted when when the data series of the variable is loaded for the first time
84 void dataInitialized();
79
85
80 private:
86 private:
81 class VariablePrivate;
87 class VariablePrivate;
@@ -48,26 +48,6 public:
48 */
48 */
49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
50
50
51 /**
52 * Deletes from the controller the variable passed in parameter.
53 *
54 * Delete a variable includes:
55 * - the deletion of the various references to the variable in SciQlop
56 * - the deletion of the model variable
57 * - the deletion of the provider associated with the variable
58 * - removing the cache associated with the variable
59 *
60 * @param variable the variable to delete from the controller.
61 */
62 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
63
64 /**
65 * Deletes from the controller the variables passed in parameter.
66 * @param variables the variables to delete from the controller.
67 * @sa deleteVariable()
68 */
69 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
70
71 /// Returns the MIME data associated to a list of variables
51 /// Returns the MIME data associated to a list of variables
72 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
52 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
73
53
@@ -89,7 +69,29 signals:
89 /// validated, canceled, or failed)
69 /// validated, canceled, or failed)
90 void acquisitionFinished();
70 void acquisitionFinished();
91
71
72 void variableAdded(const std::shared_ptr<Variable> &variable);
73
92 public slots:
74 public slots:
75 /**
76 * Deletes from the controller the variable passed in parameter.
77 *
78 * Delete a variable includes:
79 * - the deletion of the various references to the variable in SciQlop
80 * - the deletion of the model variable
81 * - the deletion of the provider associated with the variable
82 * - removing the cache associated with the variable
83 *
84 * @param variable the variable to delete from the controller.
85 */
86 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
87
88 /**
89 * Deletes from the controller the variables passed in parameter.
90 * @param variables the variables to delete from the controller.
91 * @sa deleteVariable()
92 */
93 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
94
93 /// Request the data loading of the variable whithin range
95 /// Request the data loading of the variable whithin range
94 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
96 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
95 bool synchronise);
97 bool synchronise);
@@ -1,6 +1,6
1
1
2 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
2 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
3 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
3 libcatalogs_dep = dependency('libcatalogs', required : true, fallback:['libcatalogs','libcatalogs_dep'])
4
4
5
5
6 core_moc_headers = [
6 core_moc_headers = [
@@ -41,7 +41,7 core_sources = [
41 'src/DataSource/DataSourceItemAction.cpp',
41 'src/DataSource/DataSourceItemAction.cpp',
42 'src/DataSource/DataSourceItemMergeHelper.cpp',
42 'src/DataSource/DataSourceItemMergeHelper.cpp',
43 'src/Network/NetworkController.cpp',
43 'src/Network/NetworkController.cpp',
44 'src/Plugin/PluginManager.cpp',
44 'src/PluginManager/PluginManager.cpp',
45 'src/Settings/SqpSettingsDefs.cpp',
45 'src/Settings/SqpSettingsDefs.cpp',
46 'src/Time/TimeController.cpp',
46 'src/Time/TimeController.cpp',
47 'src/Variable/Variable.cpp',
47 'src/Variable/Variable.cpp',
@@ -53,21 +53,21 core_sources = [
53 'src/Visualization/VisualizationController.cpp'
53 'src/Visualization/VisualizationController.cpp'
54 ]
54 ]
55
55
56 core_inc = include_directories(['include', '../plugin/include'])
56 core_inc = include_directories(['include', 'include/Plugin'])
57
57
58 sciqlop_core_lib = library('sciqlopcore',
58 sciqlop_core_lib = library('sciqlopcore',
59 core_sources,
59 core_sources,
60 core_moc_files,
60 core_moc_files,
61 cpp_args : '-DCORE_LIB',
61 cpp_args : '-DCORE_LIB',
62 include_directories : core_inc,
62 include_directories : core_inc,
63 dependencies : [qt5core, qt5network, catalogueapi_dep],
63 dependencies : [qt5core, qt5network, libcatalogs_dep],
64 install : true
64 install : true
65 )
65 )
66
66
67
67
68 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
68 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
69 include_directories : core_inc,
69 include_directories : core_inc,
70 dependencies : [qt5core, qt5network, catalogueapi_dep])
70 dependencies : [qt5core, qt5network, libcatalogs_dep])
71
71
72
72
73
73
@@ -27,6 +27,10 static QString REPOSITORY_WORK_SUFFIX = QString{"_work"};
27 static QString REPOSITORY_TRASH_SUFFIX = QString{"_trash"};
27 static QString REPOSITORY_TRASH_SUFFIX = QString{"_trash"};
28 }
28 }
29
29
30 /**
31 * Possible types of an repository
32 */
33 enum class DBType { SYNC, WORK, TRASH };
30 class CatalogueController::CatalogueControllerPrivate {
34 class CatalogueController::CatalogueControllerPrivate {
31
35
32 public:
36 public:
@@ -37,9 +41,10 public:
37 QStringList m_RepositoryList;
41 QStringList m_RepositoryList;
38 CatalogueController *m_Q;
42 CatalogueController *m_Q;
39
43
40 QSet<QString> m_EventKeysWithChanges;
44 QSet<QString> m_KeysWithChanges;
41
45
42 QString eventUniqueKey(const std::shared_ptr<DBEvent> &event) const;
46 QString eventUniqueKey(const std::shared_ptr<DBEvent> &event) const;
47 QString catalogueUniqueKey(const std::shared_ptr<DBCatalogue> &catalogue) const;
43
48
44 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
49 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
45 QString toWorkRepository(QString repository);
50 QString toWorkRepository(QString repository);
@@ -48,6 +53,9 public:
48
53
49 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
54 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
50 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
55 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
56
57 std::shared_ptr<IRequestPredicate> createFinder(const QUuid &uniqId, const QString &repository,
58 DBType type);
51 };
59 };
52
60
53 CatalogueController::CatalogueController(QObject *parent)
61 CatalogueController::CatalogueController(QObject *parent)
@@ -142,7 +150,7 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
142 event->setRepository(impl->toWorkRepository(event->getRepository()));
150 event->setRepository(impl->toWorkRepository(event->getRepository()));
143
151
144 auto uniqueId = impl->eventUniqueKey(event);
152 auto uniqueId = impl->eventUniqueKey(event);
145 impl->m_EventKeysWithChanges.insert(uniqueId);
153 impl->m_KeysWithChanges.insert(uniqueId);
146
154
147 impl->m_CatalogueDao.updateEvent(*event);
155 impl->m_CatalogueDao.updateEvent(*event);
148 }
156 }
@@ -183,48 +191,49 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
183
191
184 impl->m_CatalogueDao.updateEvent(eventTemp);
192 impl->m_CatalogueDao.updateEvent(eventTemp);
185 }
193 }
194
195 auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK);
196
197 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
198 *event = workEvent;
199
200
201 auto uniqueId = impl->eventUniqueKey(event);
202 impl->m_KeysWithChanges.insert(uniqueId);
186 }
203 }
187
204
188 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
205 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
189 {
206 {
190 impl->saveEvent(event, true);
207 impl->saveEvent(event, true);
191 impl->m_EventKeysWithChanges.remove(impl->eventUniqueKey(event));
208 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
192 }
209 }
193
210
194 void CatalogueController::discardEvent(std::shared_ptr<DBEvent> event)
211 void CatalogueController::discardEvent(std::shared_ptr<DBEvent> event, bool &removed)
195 {
212 {
196 auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(
213 auto syncPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::SYNC);
197 QString{"uniqId"}, event->getUniqId(), ComparaisonOperation::EQUALEQUAL);
214 auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK);
198
199 auto syncRepositoryPredicate = std::make_shared<ComparaisonPredicate>(
200 QString{"repository"}, impl->toSyncRepository(event->getRepository()),
201 ComparaisonOperation::EQUALEQUAL);
202
203 auto syncPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
204 syncPred->AddRequestPredicate(uniqIdPredicate);
205 syncPred->AddRequestPredicate(syncRepositoryPredicate);
206
207
208 auto workRepositoryPredicate = std::make_shared<ComparaisonPredicate>(
209 QString{"repository"}, impl->toWorkRepository(event->getRepository()),
210 ComparaisonOperation::EQUALEQUAL);
211
212 auto workPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
213 workPred->AddRequestPredicate(uniqIdPredicate);
214 workPred->AddRequestPredicate(workRepositoryPredicate);
215
216
215
217 auto syncEvent = impl->m_CatalogueDao.getEvent(syncPred);
216 auto syncEvent = impl->m_CatalogueDao.getEvent(syncPred);
218 impl->m_CatalogueDao.copyEvent(syncEvent, impl->toWorkRepository(event->getRepository()), true);
217 if (!syncEvent.getUniqId().isNull()) {
219
218 removed = false;
220 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
219 impl->m_CatalogueDao.copyEvent(syncEvent, impl->toWorkRepository(event->getRepository()),
221 *event = workEvent;
220 true);
222 impl->m_EventKeysWithChanges.remove(impl->eventUniqueKey(event));
221
222 auto workEvent = impl->m_CatalogueDao.getEvent(workPred);
223 *event = workEvent;
224 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
225 }
226 else {
227 removed = true;
228 // Since the element wasn't in sync repository. Discard it means remove it
229 event->setRepository(impl->toWorkRepository(event->getRepository()));
230 impl->m_CatalogueDao.removeEvent(*event);
231 }
223 }
232 }
224
233
225 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
234 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
226 {
235 {
227 return impl->m_EventKeysWithChanges.contains(impl->eventUniqueKey(event));
236 return impl->m_KeysWithChanges.contains(impl->eventUniqueKey(event));
228 }
237 }
229
238
230 std::list<std::shared_ptr<DBCatalogue> >
239 std::list<std::shared_ptr<DBCatalogue> >
@@ -240,10 +249,30 CatalogueController::retrieveCatalogues(const QString &repository) const
240 return cataloguesShared;
249 return cataloguesShared;
241 }
250 }
242
251
252 void CatalogueController::addCatalogue(std::shared_ptr<DBCatalogue> catalogue)
253 {
254 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
255
256 auto catalogueTemp = *catalogue;
257 impl->m_CatalogueDao.addCatalogue(catalogueTemp);
258
259 auto workPred
260 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK);
261
262 auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred);
263 *catalogue = workCatalogue;
264
265 auto uniqueId = impl->catalogueUniqueKey(catalogue);
266 impl->m_KeysWithChanges.insert(uniqueId);
267 }
268
243 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
269 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
244 {
270 {
245 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
271 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
246
272
273 auto uniqueId = impl->catalogueUniqueKey(catalogue);
274 impl->m_KeysWithChanges.insert(uniqueId);
275
247 impl->m_CatalogueDao.updateCatalogue(*catalogue);
276 impl->m_CatalogueDao.updateCatalogue(*catalogue);
248 }
277 }
249
278
@@ -254,11 +283,46 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue
254 impl->m_CatalogueDao.removeCatalogue(*catalogue);
283 impl->m_CatalogueDao.removeCatalogue(*catalogue);
255 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
284 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
256 impl->m_CatalogueDao.removeCatalogue(*catalogue);
285 impl->m_CatalogueDao.removeCatalogue(*catalogue);
286 impl->savAllDB();
257 }
287 }
258
288
259 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
289 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
260 {
290 {
261 impl->saveCatalogue(catalogue, true);
291 impl->saveCatalogue(catalogue, true);
292 impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue));
293
294 // remove key of events of the catalogue
295 if (catalogue->getType() == CatalogueType::STATIC) {
296 auto events = this->retrieveEventsFromCatalogue(catalogue);
297 for (auto event : events) {
298 impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event));
299 }
300 }
301 }
302
303 void CatalogueController::discardCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool &removed)
304 {
305 auto syncPred
306 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::SYNC);
307 auto workPred
308 = impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK);
309
310 auto syncCatalogue = impl->m_CatalogueDao.getCatalogue(syncPred);
311 if (!syncCatalogue.getUniqId().isNull()) {
312 removed = false;
313 impl->m_CatalogueDao.copyCatalogue(
314 syncCatalogue, impl->toWorkRepository(catalogue->getRepository()), true);
315
316 auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred);
317 *catalogue = workCatalogue;
318 impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue));
319 }
320 else {
321 removed = true;
322 // Since the element wasn't in sync repository. Discard it means remove it
323 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
324 impl->m_CatalogueDao.removeCatalogue(*catalogue);
325 }
262 }
326 }
263
327
264 void CatalogueController::saveAll()
328 void CatalogueController::saveAll()
@@ -278,12 +342,12 void CatalogueController::saveAll()
278 }
342 }
279
343
280 impl->savAllDB();
344 impl->savAllDB();
281 impl->m_EventKeysWithChanges.clear();
345 impl->m_KeysWithChanges.clear();
282 }
346 }
283
347
284 bool CatalogueController::hasChanges() const
348 bool CatalogueController::hasChanges() const
285 {
349 {
286 return !impl->m_EventKeysWithChanges.isEmpty(); // TODO: catalogues
350 return !impl->m_KeysWithChanges.isEmpty();
287 }
351 }
288
352
289 QByteArray
353 QByteArray
@@ -326,6 +390,46 CatalogueController::eventsForMimeData(const QByteArray &mimeData) const
326 return events;
390 return events;
327 }
391 }
328
392
393 QByteArray CatalogueController::mimeDataForCatalogues(
394 const QVector<std::shared_ptr<DBCatalogue> > &catalogues) const
395 {
396 auto encodedData = QByteArray{};
397
398 QMap<QString, QVariantList> idsPerRepository;
399 for (auto catalogue : catalogues) {
400 idsPerRepository[catalogue->getRepository()] << catalogue->getUniqId();
401 }
402
403 QDataStream stream{&encodedData, QIODevice::WriteOnly};
404 stream << idsPerRepository;
405
406 return encodedData;
407 }
408
409 QVector<std::shared_ptr<DBCatalogue> >
410 CatalogueController::cataloguesForMimeData(const QByteArray &mimeData) const
411 {
412 auto catalogues = QVector<std::shared_ptr<DBCatalogue> >{};
413 QDataStream stream{mimeData};
414
415 QMap<QString, QVariantList> idsPerRepository;
416 stream >> idsPerRepository;
417
418 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
419 auto repository = it.key();
420 auto allRepositoryCatalogues = retrieveCatalogues(repository);
421 for (auto uuid : it.value()) {
422 for (auto repositoryCatalogues : allRepositoryCatalogues) {
423 if (uuid.toUuid() == repositoryCatalogues->getUniqId()) {
424 catalogues << repositoryCatalogues;
425 }
426 }
427 }
428 }
429
430 return catalogues;
431 }
432
329 void CatalogueController::initialize()
433 void CatalogueController::initialize()
330 {
434 {
331 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
435 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
@@ -339,9 +443,23 void CatalogueController::initialize()
339 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
443 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
340 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
444 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
341 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
445 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
446
342 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
447 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
343 << defaultRepository;
448 << defaultRepository;
344 this->addDB(defaultRepository);
449
450 QDir dbDir(defaultRepository);
451 impl->m_RepositoryList << REPOSITORY_DEFAULT;
452 if (dbDir.exists()) {
453 auto dirName = dbDir.dirName();
454
455 if (impl->m_CatalogueDao.addDB(defaultRepository, dirName)) {
456 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
457 }
458 }
459 else {
460 qCInfo(LOG_CatalogueController()) << tr("Initialisation of Default repository detected")
461 << defaultRepository;
462 }
345 }
463 }
346 else {
464 else {
347 qCWarning(LOG_CatalogueController())
465 qCWarning(LOG_CatalogueController())
@@ -358,6 +476,12 QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey(
358 return event->getUniqId().toString().append(event->getRepository());
476 return event->getUniqId().toString().append(event->getRepository());
359 }
477 }
360
478
479 QString CatalogueController::CatalogueControllerPrivate::catalogueUniqueKey(
480 const std::shared_ptr<DBCatalogue> &catalogue) const
481 {
482 return catalogue->getUniqId().toString().append(catalogue->getRepository());
483 }
484
361 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
485 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
362 const QString &dbTo)
486 const QString &dbTo)
363 {
487 {
@@ -418,3 +542,33 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
418 savAllDB();
542 savAllDB();
419 }
543 }
420 }
544 }
545
546 std::shared_ptr<IRequestPredicate> CatalogueController::CatalogueControllerPrivate::createFinder(
547 const QUuid &uniqId, const QString &repository, DBType type)
548 {
549 // update catalogue parameter
550 auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(QString{"uniqId"}, uniqId,
551 ComparaisonOperation::EQUALEQUAL);
552
553 auto repositoryType = repository;
554 switch (type) {
555 case DBType::SYNC:
556 repositoryType = toSyncRepository(repositoryType);
557 break;
558 case DBType::WORK:
559 repositoryType = toWorkRepository(repositoryType);
560 break;
561 case DBType::TRASH:
562 default:
563 break;
564 }
565
566 auto repositoryPredicate = std::make_shared<ComparaisonPredicate>(
567 QString{"repository"}, repositoryType, ComparaisonOperation::EQUALEQUAL);
568
569 auto finderPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND);
570 finderPred->AddRequestPredicate(uniqIdPredicate);
571 finderPred->AddRequestPredicate(repositoryPredicate);
572
573 return finderPred;
574 }
@@ -7,3 +7,4 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
8 const QString MIME_TYPE_SELECTION_ZONE = QStringLiteral("sciqlop/selection-zone");
8 const QString MIME_TYPE_SELECTION_ZONE = QStringLiteral("sciqlop/selection-zone");
9 const QString MIME_TYPE_EVENT_LIST = QStringLiteral("sciqlop/event-list");
9 const QString MIME_TYPE_EVENT_LIST = QStringLiteral("sciqlop/event-list");
10 const QString MIME_TYPE_SOURCE_CATALOGUE_LIST = QStringLiteral("sciqlop/source-catalogue-list");
@@ -37,6 +37,20 public:
37
37
38 return sourceItem;
38 return sourceItem;
39 }
39 }
40
41 // Search for the first datasource item matching the specified ID_DATA_KEY
42 DataSourceItem *findDataSourceItem(const QString &datasourceIdKey)
43 {
44 DataSourceItem *sourceItem = nullptr;
45 for (const auto &item : m_DataSourceItems) {
46 sourceItem = item.second->findItem(datasourceIdKey, true);
47 if (sourceItem) {
48 break;
49 }
50 }
51
52 return sourceItem;
53 }
40 };
54 };
41
55
42 DataSourceController::DataSourceController(QObject *parent)
56 DataSourceController::DataSourceController(QObject *parent)
@@ -149,6 +163,20 void DataSourceController::finalize()
149 impl->m_WorkingMutex.unlock();
163 impl->m_WorkingMutex.unlock();
150 }
164 }
151
165
166 void DataSourceController::requestVariableFromProductIdKey(const QString &datasourceIdKey)
167 {
168 auto sourceItem = impl->findDataSourceItem(datasourceIdKey);
169
170 if (sourceItem) {
171 auto sourceName = sourceItem->rootItem().name();
172 auto sourceId = impl->m_DataSources.key(sourceName);
173 loadProductItem(sourceId, *sourceItem);
174 }
175 else {
176 qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found");
177 }
178 }
179
152 void DataSourceController::requestVariable(const QVariantHash &productData)
180 void DataSourceController::requestVariable(const QVariantHash &productData)
153 {
181 {
154 auto sourceItem = impl->findDataSourceItem(productData);
182 auto sourceItem = impl->findDataSourceItem(productData);
@@ -165,6 +165,24 DataSourceItem *DataSourceItem::findItem(const QVariantHash &data, bool recursiv
165 return nullptr;
165 return nullptr;
166 }
166 }
167
167
168 DataSourceItem *DataSourceItem::findItem(const QString &datasourceIdKey, bool recursive)
169 {
170 for (const auto &child : impl->m_Children) {
171 auto childId = child->impl->m_Data.value(ID_DATA_KEY);
172 if (childId == datasourceIdKey) {
173 return child.get();
174 }
175
176 if (recursive) {
177 if (auto foundItem = child->findItem(datasourceIdKey, true)) {
178 return foundItem;
179 }
180 }
181 }
182
183 return nullptr;
184 }
185
168 bool DataSourceItem::operator==(const DataSourceItem &other)
186 bool DataSourceItem::operator==(const DataSourceItem &other)
169 {
187 {
170 // Compares items' attributes
188 // Compares items' attributes
@@ -1,4 +1,4
1 #include <Plugin/PluginManager.h>
1 #include <PluginManager/PluginManager.h>
2
2
3 #include <Plugin/IPlugin.h>
3 #include <Plugin/IPlugin.h>
4
4
@@ -9,6 +9,29
9
9
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11
11
12 namespace {
13
14 /**
15 * Searches in metadata for a value that can be converted to DataSeriesType
16 * @param metadata the metadata where to search
17 * @return the value converted to a DataSeriesType if it was found, UNKNOWN type otherwise
18 * @sa DataSeriesType
19 */
20 DataSeriesType findDataSeriesType(const QVariantHash &metadata)
21 {
22 auto dataSeriesType = DataSeriesType::UNKNOWN;
23
24 // Go through the metadata and stop at the first value that could be converted to DataSeriesType
25 for (auto it = metadata.cbegin(), end = metadata.cend();
26 it != end && dataSeriesType == DataSeriesType::UNKNOWN; ++it) {
27 dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString());
28 }
29
30 return dataSeriesType;
31 }
32
33 } // namespace
34
12 struct Variable::VariablePrivate {
35 struct Variable::VariablePrivate {
13 explicit VariablePrivate(const QString &name, const QVariantHash &metadata)
36 explicit VariablePrivate(const QString &name, const QVariantHash &metadata)
14 : m_Name{name},
37 : m_Name{name},
@@ -17,7 +40,8 struct Variable::VariablePrivate {
17 m_Metadata{metadata},
40 m_Metadata{metadata},
18 m_DataSeries{nullptr},
41 m_DataSeries{nullptr},
19 m_RealRange{INVALID_RANGE},
42 m_RealRange{INVALID_RANGE},
20 m_NbPoints{0}
43 m_NbPoints{0},
44 m_Type{findDataSeriesType(m_Metadata)}
21 {
45 {
22 }
46 }
23
47
@@ -28,7 +52,8 struct Variable::VariablePrivate {
28 m_Metadata{other.m_Metadata},
52 m_Metadata{other.m_Metadata},
29 m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr},
53 m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr},
30 m_RealRange{other.m_RealRange},
54 m_RealRange{other.m_RealRange},
31 m_NbPoints{other.m_NbPoints}
55 m_NbPoints{other.m_NbPoints},
56 m_Type{findDataSeriesType(m_Metadata)}
32 {
57 {
33 }
58 }
34
59
@@ -75,6 +100,7 struct Variable::VariablePrivate {
75 std::shared_ptr<IDataSeries> m_DataSeries;
100 std::shared_ptr<IDataSeries> m_DataSeries;
76 SqpRange m_RealRange;
101 SqpRange m_RealRange;
77 int m_NbPoints;
102 int m_NbPoints;
103 DataSeriesType m_Type;
78
104
79 QReadWriteLock m_Lock;
105 QReadWriteLock m_Lock;
80 };
106 };
@@ -161,16 +187,23 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
161 return;
187 return;
162 }
188 }
163
189
190 auto dataInit = false;
191
164 // Add or merge the data
192 // Add or merge the data
165 impl->lockWrite();
193 impl->lockWrite();
166 if (!impl->m_DataSeries) {
194 if (!impl->m_DataSeries) {
167 impl->m_DataSeries = dataSeries->clone();
195 impl->m_DataSeries = dataSeries->clone();
196 dataInit = true;
168 }
197 }
169 else {
198 else {
170 impl->m_DataSeries->merge(dataSeries.get());
199 impl->m_DataSeries->merge(dataSeries.get());
171 }
200 }
172 impl->purgeDataSeries();
201 impl->purgeDataSeries();
173 impl->unlock();
202 impl->unlock();
203
204 if (dataInit) {
205 emit dataInitialized();
206 }
174 }
207 }
175
208
176
209
@@ -183,6 +216,15 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
183 return dataSeries;
216 return dataSeries;
184 }
217 }
185
218
219 DataSeriesType Variable::type() const noexcept
220 {
221 impl->lockRead();
222 auto type = impl->m_Type;
223 impl->unlock();
224
225 return type;
226 }
227
186 QVariantHash Variable::metadata() const noexcept
228 QVariantHash Variable::metadata() const noexcept
187 {
229 {
188 impl->lockRead();
230 impl->lockRead();
@@ -136,6 +136,9 struct VariableController::VariableControllerPrivate {
136 void cancelVariableRequest(QUuid varRequestId);
136 void cancelVariableRequest(QUuid varRequestId);
137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
138
138
139 template <typename VariableIterator>
140 void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId);
141
139 QMutex m_WorkingMutex;
142 QMutex m_WorkingMutex;
140 /// Variable model. The VariableController has the ownership
143 /// Variable model. The VariableController has the ownership
141 VariableModel *m_VariableModel;
144 VariableModel *m_VariableModel;
@@ -258,8 +261,22 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noex
258 // make some treatments before the deletion
261 // make some treatments before the deletion
259 emit variableAboutToBeDeleted(variable);
262 emit variableAboutToBeDeleted(variable);
260
263
264 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
265 Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend());
266
267 auto variableId = variableIt->second;
268
269 // Removes variable's handler
270 impl->m_VarIdToVarRequestHandler.erase(variableId);
271
272 // Desynchronizes variable (if the variable is in a sync group)
273 auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId);
274 if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) {
275 impl->desynchronize(variableIt, syncGroupIt->second);
276 }
277
261 // Deletes identifier
278 // Deletes identifier
262 impl->m_VariableToIdentifierMap.erase(variable);
279 impl->m_VariableToIdentifierMap.erase(variableIt);
263
280
264 // Deletes provider
281 // Deletes provider
265 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
282 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
@@ -356,6 +373,8 VariableController::createVariable(const QString &name, const QVariantHash &meta
356 // impl->processRequest(newVariable, range, varRequestId);
373 // impl->processRequest(newVariable, range, varRequestId);
357 // impl->updateVariableRequest(varRequestId);
374 // impl->updateVariableRequest(varRequestId);
358
375
376 emit variableAdded(newVariable);
377
359 return newVariable;
378 return newVariable;
360 }
379 }
361
380
@@ -545,23 +564,7 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
545 return;
564 return;
546 }
565 }
547
566
548 // Gets synchronization group
567 impl->desynchronize(variableIt, synchronizationGroupId);
549 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
550 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
551 qCCritical(LOG_VariableController())
552 << tr("Can't desynchronize variable %1: unknown synchronization group")
553 .arg(variable->name());
554 return;
555 }
556
557 auto variableId = variableIt->second;
558
559 // Removes variable from synchronization group
560 auto synchronizationGroup = groupIt->second;
561 synchronizationGroup->removeVariableId(variableId);
562
563 // Removes link between variable and synchronization group
564 impl->m_VariableIdGroupIdMap.erase(variableId);
565 }
568 }
566
569
567 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
570 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
@@ -933,6 +936,7 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid
933 varHandler->m_PendingVarRequest = VariableRequest{};
936 varHandler->m_PendingVarRequest = VariableRequest{};
934 auto var = findVariable(itVarHandler->first);
937 auto var = findVariable(itVarHandler->first);
935 executeVarRequest(var, varHandler->m_RunningVarRequest);
938 executeVarRequest(var, varHandler->m_RunningVarRequest);
939 updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId);
936 break;
940 break;
937 }
941 }
938 default:
942 default:
@@ -1032,7 +1036,14 void VariableController::VariableControllerPrivate::executeVarRequest(std::share
1032 {
1036 {
1033 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1037 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1034
1038
1035 auto varId = m_VariableToIdentifierMap.at(var);
1039 auto varIdIt = m_VariableToIdentifierMap.find(var);
1040 if (varIdIt == m_VariableToIdentifierMap.cend()) {
1041 qCWarning(LOG_VariableController()) << tr(
1042 "Can't execute request of a variable that is not registered (may has been deleted)");
1043 return;
1044 }
1045
1046 auto varId = varIdIt->second;
1036
1047
1037 auto varCacheRange = var->cacheRange();
1048 auto varCacheRange = var->cacheRange();
1038 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1049 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
@@ -1067,3 +1078,27 void VariableController::VariableControllerPrivate::executeVarRequest(std::share
1067 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1078 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1068 }
1079 }
1069 }
1080 }
1081
1082 template <typename VariableIterator>
1083 void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt,
1084 const QUuid &syncGroupId)
1085 {
1086 const auto &variable = variableIt->first;
1087 const auto &variableId = variableIt->second;
1088
1089 // Gets synchronization group
1090 auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId);
1091 if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) {
1092 qCCritical(LOG_VariableController())
1093 << tr("Can't desynchronize variable %1: unknown synchronization group")
1094 .arg(variable->name());
1095 return;
1096 }
1097
1098 // Removes variable from synchronization group
1099 auto synchronizationGroup = groupIt->second;
1100 synchronizationGroup->removeVariableId(variableId);
1101
1102 // Removes link between variable and synchronization group
1103 m_VariableIdGroupIdMap.erase(variableId);
1104 }
@@ -52,9 +52,6 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
52 {UNIT_COLUMN, {QObject::tr("Unit")}}, {MISSION_COLUMN, {QObject::tr("Mission")}},
52 {UNIT_COLUMN, {QObject::tr("Unit")}}, {MISSION_COLUMN, {QObject::tr("Mission")}},
53 {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
53 {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
54
54
55 /// Format for datetimes
56 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
57
58 QString uniqueName(const QString &defaultName,
55 QString uniqueName(const QString &defaultName,
59 const std::vector<std::shared_ptr<Variable> > &variables)
56 const std::vector<std::shared_ptr<Variable> > &variables)
60 {
57 {
@@ -1,179 +1,51
1
1 FILE (GLOB_RECURSE gui_SRCS
2 ## gui - CMakeLists.txt
2 include/*.h
3 STRING(TOLOWER ${CMAKE_PROJECT_NAME} LIBRARY_PREFFIX)
3 src/*.cpp
4 SET(SQPGUI_LIBRARY_NAME "${LIBRARY_PREFFIX}_gui${DEBUG_SUFFIX}")
4 resources/*.qrc
5 SET(SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
5 )
6 SET(INCLUDES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
6
7 SET(UI_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/ui")
7 QT5_WRAP_UI(
8 SET(RES_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/resources")
8 UiGenerated_SRCS
9
9 ui/DataSource/DataSourceWidget.ui
10 # Include gui directory
10 ui/Settings/SqpSettingsDialog.ui
11 include_directories("${INCLUDES_DIR}")
11 ui/Settings/SqpSettingsGeneralWidget.ui
12 include_directories("${CMAKE_CURRENT_BINARY_DIR}")
12 ui/SidePane/SqpSidePane.ui
13
13 ui/TimeWidget/TimeWidget.ui
14 # Set a variable to display a warning in the version files.
14 ui/Variable/RenameVariableDialog.ui
15 SET(SCIQLOP_CMAKE_GENERATION_WARNING "DON'T CHANGE THIS FILE. AUTOGENERATED BY CMAKE.")
15 ui/Variable/VariableInspectorWidget.ui
16
16 ui/Variable/VariableMenuHeaderWidget.ui
17 #
17 ui/Visualization/ColorScaleEditor.ui
18 # Find Qt modules
18 ui/Visualization/VisualizationGraphWidget.ui
19 #
19 ui/Visualization/VisualizationTabWidget.ui
20 SCIQLOP_FIND_QT(Core Widgets PrintSupport)
20 ui/Visualization/VisualizationWidget.ui
21
21 ui/Visualization/VisualizationZoneWidget.ui
22 #
22 ui/Visualization/VisualizationMultiZoneSelectionDialog.ui
23 # Find dependent libraries
23 ui/Catalogue/CatalogueEventsWidget.ui
24 # ========================
24 ui/Catalogue/CatalogueExplorer.ui
25 find_package(sciqlop-core)
25 ui/Catalogue/CatalogueInspectorWidget.ui
26
26 ui/Catalogue/CatalogueSideBarWidget.ui
27 SET(LIBRARIES ${SCIQLOP-CORE_LIBRARIES})
28
29 INCLUDE_DIRECTORIES(${SCIQLOP-CORE_INCLUDE_DIR})
30
31 # Add sqpcore to the list of libraries to use
32 list(APPEND LIBRARIES ${SQPCORE_LIBRARY_NAME})
33
34 # Add dependent shared libraries
35 list(APPEND SHARED_LIBRARIES ${SQPCORE_SHARED_LIBRARIES})
36
37
38 # Ui files
39 FILE (GLOB_RECURSE PROJECT_FORMS ${UI_FOLDER}/*.ui)
40
41 # Resources files
42 FILE (GLOB_RECURSE PROJECT_RESOURCES ${RES_FOLDER}/*.qrc)
43
44 #
45 # Compile the library library
46 #
47 FILE (GLOB_RECURSE MODULE_SOURCES
48 ${INCLUDES_DIR}/*.h
49 ${SOURCES_DIR}/*.c
50 ${SOURCES_DIR}/*.cpp
51 ${SOURCES_DIR}/*.h
52 ${PROJECT_FORMS})
53
54 QT5_ADD_RESOURCES(RCC_HDRS
55 ${PROJECT_RESOURCES}
56 )
57
58 QT5_WRAP_UI(UIS_HDRS
59 ${PROJECT_FORMS}
60 )
27 )
61
28
29 add_library(sciqlopgui ${gui_SRCS} ${UiGenerated_SRCS})
30 SET_TARGET_PROPERTIES(sciqlopgui PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
62
31
63 ADD_LIBRARY(${SQPGUI_LIBRARY_NAME} ${MODULE_SOURCES} ${UIS_HDRS} ${RCC_HDRS})
32 target_include_directories(sciqlopgui PUBLIC
64 set_property(TARGET ${SQPGUI_LIBRARY_NAME} PROPERTY CXX_STANDARD 14)
33 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
65 set_property(TARGET ${SQPGUI_LIBRARY_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
34 $<INSTALL_INTERFACE:include/SciQLOP>
66
35 )
67 TARGET_LINK_LIBRARIES(${SQPGUI_LIBRARY_NAME} ${LIBRARIES})
68 qt5_use_modules(${SQPGUI_LIBRARY_NAME} Core Widgets PrintSupport)
69
36
70
37 target_link_libraries(sciqlopgui PUBLIC
71 INSTALL(TARGETS ${SQPGUI_LIBRARY_NAME}
38 Qt5::Widgets
72 RUNTIME DESTINATION ${INSTALL_BINARY_DIR}
39 Qt5::PrintSupport
73 LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR}
40 Qt5::Svg
74 ARCHIVE DESTINATION ${INSTALL_LIBRARY_DIR}
41 sciqlopcore
75 )
76 add_dependencies(${SQPGUI_LIBRARY_NAME} ${SQPCORE_LIBRARY_NAME})
77
78 # Find CATALOGUE_API
79 include_directories("${CATALOGUEAPI_INCLUDE}")
80 TARGET_LINK_LIBRARIES(${SQPGUI_LIBRARY_NAME} ${CATALOGUEAPI_LIBRARIES})
81 INSTALL(TARGETS ${SQPGUI_LIBRARY_NAME}
82 RUNTIME DESTINATION ${INSTALL_BINARY_DIR}
83 LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR}
84 ARCHIVE DESTINATION ${INSTALL_LIBRARY_DIR}
85 )
42 )
86
43
87 add_dependencies(${SQPGUI_LIBRARY_NAME} CatalogueAPI)
44 install(TARGETS sciqlopgui EXPORT SciQLOPGuiConfig
88
45 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
89 # From cmake documentation: http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
46 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
90 # Entries in the COMPILE_DEFINITIONS are prefixed with -D or /D and added to the compile line in an unspecified order.
47 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
91 # The DEFINE_SYMBOL target property is also added as a compile definition as a special convenience case for SHARED and MODULE library targets
92 IF(BUILD_SHARED_LIBS)
93 SET_TARGET_PROPERTIES(${SQPGUI_LIBRARY_NAME} PROPERTIES COMPILE_DEFINITIONS "SCIQLOP_EXPORT")
94 ELSE()
95 TARGET_COMPILE_DEFINITIONS(${SQPGUI_LIBRARY_NAME} PUBLIC "SCIQLOP_STATIC_LIBRARIES")
96 ENDIF()
97
98 # Set the variable to parent scope so that the other projects can copy the
99 # dependent shared libraries
100 SCIQLOP_SET_TO_PARENT_SCOPE(SQPGUI_LIBRARY_NAME)
101
102 # Copy extern shared libraries to the lib folder
103 SCIQLOP_COPY_TO_TARGET(LIBRARY ${SQPGUI_LIBRARY_NAME})
104
105 # Add the files to the list of files to be analyzed
106 LIST(APPEND CHECKSTYLE_INPUT_FILES ${MODULE_SOURCES})
107 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_INPUT_FILES)
108 # Vera++ exclusion files
109 LIST(APPEND CHECKSTYLE_EXCLUSION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vera-exclusions/exclusions.txt)
110 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_EXCLUSION_FILES)
111
112 #
113 # Compile the tests
114 #
115 IF(BUILD_TESTS)
116 INCLUDE_DIRECTORIES(${SOURCES_DIR})
117 FILE (GLOB_RECURSE TESTS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test*.cpp)
118 FILE (GLOB_RECURSE TESTS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Test*.h)
119 SET( TEST_LIBRARIES ${SQPGUI_LIBRARY_NAME})
120
121 FOREACH( testFile ${TESTS_SOURCES} )
122 GET_FILENAME_COMPONENT( testDirectory ${testFile} DIRECTORY )
123 GET_FILENAME_COMPONENT( testName ${testFile} NAME_WE )
124
125 # Add to the list of sources files all the sources in the same
126 # directory that aren't another test
127 FILE (GLOB currentTestSources
128 ${testDirectory}/*.c
129 ${testDirectory}/*.cpp
130 ${testDirectory}/*.h)
131 LIST (REMOVE_ITEM currentTestSources ${TESTS_SOURCES})
132 # LIST (REMOVE_ITEM currentTestSources ${TESTS_HEADERS})
133
134 ADD_EXECUTABLE(${testName} ${testFile} ${currentTestSources})
135 set_property(TARGET ${testName} PROPERTY CXX_STANDARD 14)
136 set_property(TARGET ${testName} PROPERTY CXX_STANDARD_REQUIRED ON)
137 TARGET_LINK_LIBRARIES( ${testName} ${TEST_LIBRARIES} )
138 qt5_use_modules(${testName} Test)
139
140 ADD_TEST( NAME ${testName} COMMAND ${testName} )
141
142 SCIQLOP_COPY_TO_TARGET(RUNTIME ${testName} ${EXTERN_SHARED_LIBRARIES})
143 ENDFOREACH( testFile )
144
145 LIST(APPEND testFilesToFormat ${TESTS_SOURCES})
146 LIST(APPEND testFilesToFormat ${TESTS_HEADERS})
147 LIST(APPEND FORMATTING_INPUT_FILES ${testFilesToFormat})
148 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
149 ENDIF(BUILD_TESTS)
150
151 #
152 # Set the files that must be formatted by clang-format.
153 #
154 LIST (APPEND FORMATTING_INPUT_FILES ${MODULE_SOURCES})
155 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
156
157 #
158 # Set the directories that doxygen must browse to generate the
159 # documentation.
160 #
161 # Source directories:
162 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/docs")
163 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
164 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_INPUT_DIRS)
165 # Source directories to exclude from the documentation generation
166 #LIST (APPEND DOXYGEN_EXCLUDE_PATTERNS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir/*")
167 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_EXCLUDE_PATTERNS)
168
48
169 #
49 install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SciQLOP)
170 # Set the directories with the sources to analyze and propagate the
50 install(EXPORT SciQLOPGuiConfig DESTINATION share/SciQLOPGui/cmake)
171 # modification to the parent scope
51 export(TARGETS sciqlopgui FILE SciQLOPGuiConfig.cmake)
172 #
173 # Source directories to analyze:
174 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
175 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
176 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_INPUT_DIRS)
177 # Source directories to exclude from the analysis
178 #LIST (APPEND ANALYSIS_EXCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir")
179 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_EXCLUDE_DIRS)
@@ -19,6 +19,14 public:
19
19
20 QVector<std::shared_ptr<SelectionZoneAction> > selectionZoneActions() const;
20 QVector<std::shared_ptr<SelectionZoneAction> > selectionZoneActions() const;
21
21
22 void removeAction(const std::shared_ptr<SelectionZoneAction> &action);
23
24 /// Sets a flag to say that the specified menu can be filtered, usually via a FilteringAction
25 void addFilterForMenu(const QStringList &menuPath);
26
27 /// Returns true if the menu can be filtered
28 bool isMenuFiltered(const QStringList &menuPath) const;
29
22 private:
30 private:
23 class ActionsGuiControllerPrivate;
31 class ActionsGuiControllerPrivate;
24 spimpl::unique_impl_ptr<ActionsGuiControllerPrivate> impl;
32 spimpl::unique_impl_ptr<ActionsGuiControllerPrivate> impl;
@@ -60,6 +60,13 public:
60 /// The path in the sub menus, if any
60 /// The path in the sub menus, if any
61 QStringList subMenuList() const noexcept;
61 QStringList subMenuList() const noexcept;
62
62
63 /// Sets if filtering the action is allowed via a FilteringAction
64 void setAllowedFiltering(bool value);
65
66 /// Returns true if filtering the action is allowed via a FilteringAction. By default it is
67 /// allowed.
68 bool isFilteringAllowed() const;
69
63 public slots:
70 public slots:
64 /// Executes the action
71 /// Executes the action
65 void execute(const QVector<VisualizationSelectionZoneItem *> &item);
72 void execute(const QVector<VisualizationSelectionZoneItem *> &item);
@@ -10,6 +10,7 public:
10 CatalogueActionManager(CatalogueExplorer *catalogueExplorer);
10 CatalogueActionManager(CatalogueExplorer *catalogueExplorer);
11
11
12 void installSelectionZoneActions();
12 void installSelectionZoneActions();
13 void refreshCreateInCatalogueAction();
13
14
14 private:
15 private:
15 class CatalogueActionManagerPrivate;
16 class CatalogueActionManagerPrivate;
@@ -6,6 +6,7
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7 #include <unordered_set>
7 #include <unordered_set>
8
8
9 class DBCatalogue;
9 class DBEvent;
10 class DBEvent;
10 class DBEventProduct;
11 class DBEventProduct;
11
12
@@ -22,6 +23,7 public:
22
23
23 enum class Column { Name, TStart, TEnd, Tags, Product, Validation, NbColumn };
24 enum class Column { Name, TStart, TEnd, Tags, Product, Validation, NbColumn };
24
25
26 void setSourceCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
25 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
27 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
26 void addEvent(const std::shared_ptr<DBEvent> &event);
28 void addEvent(const std::shared_ptr<DBEvent> &event);
27 void removeEvent(const std::shared_ptr<DBEvent> &event);
29 void removeEvent(const std::shared_ptr<DBEvent> &event);
@@ -9,6 +9,7 class DBCatalogue;
9 class DBEvent;
9 class DBEvent;
10 class DBEventProduct;
10 class DBEventProduct;
11 class VisualizationWidget;
11 class VisualizationWidget;
12 class VisualizationSelectionZoneItem;
12
13
13 namespace Ui {
14 namespace Ui {
14 class CatalogueEventsWidget;
15 class CatalogueEventsWidget;
@@ -21,10 +22,15 class CatalogueEventsWidget : public QWidget {
21
22
22 signals:
23 signals:
23 void eventsSelected(const QVector<std::shared_ptr<DBEvent> > &event);
24 void eventsSelected(const QVector<std::shared_ptr<DBEvent> > &event);
25 void eventsRemoved(const QVector<std::shared_ptr<DBEvent> > &event);
24 void eventProductsSelected(
26 void eventProductsSelected(
25 const QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > >
27 const QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > >
26 &eventproducts);
28 &eventproducts);
27 void selectionCleared();
29 void selectionCleared();
30 void selectionZoneAdded(const std::shared_ptr<DBEvent> &event, const QString &productId,
31 VisualizationSelectionZoneItem *selectionZone);
32
33 void eventCataloguesModified(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
28
34
29 public:
35 public:
30 explicit CatalogueEventsWidget(QWidget *parent = 0);
36 explicit CatalogueEventsWidget(QWidget *parent = 0);
@@ -34,17 +40,25 public:
34
40
35 void addEvent(const std::shared_ptr<DBEvent> &event);
41 void addEvent(const std::shared_ptr<DBEvent> &event);
36 void setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
42 void setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
43 void setEventsChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
37
44
38 QVector<std::shared_ptr<DBCatalogue> > displayedCatalogues() const;
45 QVector<std::shared_ptr<DBCatalogue> > displayedCatalogues() const;
39 bool isAllEventsDisplayed() const;
46 bool isAllEventsDisplayed() const;
40 bool isEventDisplayed(const std::shared_ptr<DBEvent> &event) const;
47 bool isEventDisplayed(const std::shared_ptr<DBEvent> &event) const;
41
48
49 void refreshEvent(const std::shared_ptr<DBEvent> &event);
50
42 public slots:
51 public slots:
43 void populateWithCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
52 void populateWithCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
44 void populateWithAllEvents();
53 void populateWithAllEvents();
45 void clear();
54 void clear();
46 void refresh();
55 void refresh();
47
56
57 // QWidget interface
58 protected:
59 void keyPressEvent(QKeyEvent *event);
60
61
48 private:
62 private:
49 Ui::CatalogueEventsWidget *ui;
63 Ui::CatalogueEventsWidget *ui;
50
64
@@ -12,6 +12,10 class CatalogueEventsWidget;
12 class CatalogueSideBarWidget;
12 class CatalogueSideBarWidget;
13
13
14 class VisualizationWidget;
14 class VisualizationWidget;
15 class VisualizationSelectionZoneItem;
16
17 class DBEvent;
18
15
19
16 class CatalogueExplorer : public QDialog {
20 class CatalogueExplorer : public QDialog {
17 Q_OBJECT
21 Q_OBJECT
@@ -25,6 +29,10 public:
25 CatalogueEventsWidget &eventsWidget() const;
29 CatalogueEventsWidget &eventsWidget() const;
26 CatalogueSideBarWidget &sideBarWidget() const;
30 CatalogueSideBarWidget &sideBarWidget() const;
27
31
32 void clearSelectionZones();
33 void addSelectionZoneItem(const std::shared_ptr<DBEvent> &event, const QString &productId,
34 VisualizationSelectionZoneItem *selectionZone);
35
28 private:
36 private:
29 Ui::CatalogueExplorer *ui;
37 Ui::CatalogueExplorer *ui;
30
38
@@ -36,6 +36,8 public:
36 const std::shared_ptr<DBEventProduct> &eventProduct);
36 const std::shared_ptr<DBEventProduct> &eventProduct);
37 void setCatalogue(const std::shared_ptr<DBCatalogue> &catalogue);
37 void setCatalogue(const std::shared_ptr<DBCatalogue> &catalogue);
38
38
39 void refresh();
40
39 public slots:
41 public slots:
40 void showPage(Page page);
42 void showPage(Page page);
41
43
@@ -6,6 +6,7
6 #include <QTreeWidgetItem>
6 #include <QTreeWidgetItem>
7 #include <QWidget>
7 #include <QWidget>
8
8
9 class CatalogueAbstractTreeItem;
9 class DBCatalogue;
10 class DBCatalogue;
10
11
11 namespace Ui {
12 namespace Ui {
@@ -23,16 +24,26 signals:
23 void allEventsSelected();
24 void allEventsSelected();
24 void trashSelected();
25 void trashSelected();
25 void selectionCleared();
26 void selectionCleared();
27 void catalogueSaved(const std::shared_ptr<DBCatalogue> &catalogue);
28 void catalogueListChanged();
26
29
27 public:
30 public:
28 explicit CatalogueSideBarWidget(QWidget *parent = 0);
31 explicit CatalogueSideBarWidget(QWidget *parent = 0);
29 virtual ~CatalogueSideBarWidget();
32 virtual ~CatalogueSideBarWidget();
30
33
31 void addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue, const QString &repository);
34 CatalogueAbstractTreeItem *addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
35 const QString &repository);
32 void setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue, bool hasChanges);
36 void setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue, bool hasChanges);
33
37
34 QVector<std::shared_ptr<DBCatalogue> > getCatalogues(const QString &repository) const;
38 QVector<std::shared_ptr<DBCatalogue> > getCatalogues(const QString &repository) const;
35
39
40 // QWidget interface
41 protected:
42 void keyPressEvent(QKeyEvent *event);
43
44 private slots:
45 void emitSelection();
46
36 private:
47 private:
37 Ui::CatalogueSideBarWidget *ui;
48 Ui::CatalogueSideBarWidget *ui;
38
49
@@ -15,6 +15,7 public:
15 virtual ~CatalogueAbstractTreeItem();
15 virtual ~CatalogueAbstractTreeItem();
16
16
17 void addChild(CatalogueAbstractTreeItem *child);
17 void addChild(CatalogueAbstractTreeItem *child);
18 void removeChild(CatalogueAbstractTreeItem *child);
18 QVector<CatalogueAbstractTreeItem *> children() const;
19 QVector<CatalogueAbstractTreeItem *> children() const;
19 CatalogueAbstractTreeItem *parent() const;
20 CatalogueAbstractTreeItem *parent() const;
20
21
@@ -19,6 +19,7 public:
19
19
20 /// Returns the catalogue represented by the item
20 /// Returns the catalogue represented by the item
21 std::shared_ptr<DBCatalogue> catalogue() const;
21 std::shared_ptr<DBCatalogue> catalogue() const;
22 void replaceCatalogue(const std::shared_ptr<DBCatalogue> &catalogue);
22
23
23 private:
24 private:
24 class CatalogueTreeItemPrivate;
25 class CatalogueTreeItemPrivate;
@@ -16,7 +16,7 class CatalogueTreeModel : public QAbstractItemModel {
16
16
17 signals:
17 signals:
18 void itemRenamed(const QModelIndex &index);
18 void itemRenamed(const QModelIndex &index);
19 void itemDropped(const QModelIndex &parentIndex);
19 void itemDropped(const QModelIndex &parentIndex, const QMimeData *data, Qt::DropAction action);
20
20
21 public:
21 public:
22 CatalogueTreeModel(QObject *parent = nullptr);
22 CatalogueTreeModel(QObject *parent = nullptr);
@@ -27,6 +27,9 public:
27 QVector<CatalogueAbstractTreeItem *> topLevelItems() const;
27 QVector<CatalogueAbstractTreeItem *> topLevelItems() const;
28
28
29 void addChildItem(CatalogueAbstractTreeItem *child, const QModelIndex &parentIndex);
29 void addChildItem(CatalogueAbstractTreeItem *child, const QModelIndex &parentIndex);
30 void removeChildItem(CatalogueAbstractTreeItem *child, const QModelIndex &parentIndex);
31 /// Refresh the data for the specified index
32 void refresh(const QModelIndex &index);
30
33
31 CatalogueAbstractTreeItem *item(const QModelIndex &index) const;
34 CatalogueAbstractTreeItem *item(const QModelIndex &index) const;
32 QModelIndex indexOf(CatalogueAbstractTreeItem *item, int column = 0) const;
35 QModelIndex indexOf(CatalogueAbstractTreeItem *item, int column = 0) const;
@@ -12,6 +12,7 class IDataSeries;
12 class QCPAxis;
12 class QCPAxis;
13 class QCustomPlot;
13 class QCustomPlot;
14 class SqpColorScale;
14 class SqpColorScale;
15 class Variable;
15
16
16 /// Formats a data value according to the axis on which it is present
17 /// Formats a data value according to the axis on which it is present
17 QString formatValue(double value, const QCPAxis &axis);
18 QString formatValue(double value, const QCPAxis &axis);
@@ -27,11 +28,17 struct IAxisHelper {
27 /// @param plot the plot for which to set axe properties
28 /// @param plot the plot for which to set axe properties
28 /// @param colorScale the color scale for which to set properties
29 /// @param colorScale the color scale for which to set properties
29 virtual void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) = 0;
30 virtual void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) = 0;
31
32 /// Set the units of the plot's axes and the color scale associated to plot passed as
33 /// parameters
34 /// @param plot the plot for which to set axe units
35 /// @param colorScale the color scale for which to set unit
36 virtual void setUnits(QCustomPlot &plot, SqpColorScale &colorScale) = 0;
30 };
37 };
31
38
32 struct IAxisHelperFactory {
39 struct IAxisHelperFactory {
33 /// Creates IAxisHelper according to a data series
40 /// Creates IPlottablesHelper according to the type of data series a variable holds
34 static std::unique_ptr<IAxisHelper> create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
41 static std::unique_ptr<IAxisHelper> create(const Variable &variable) noexcept;
35 };
42 };
36
43
37 #endif // SCIQLOP_AXISRENDERINGUTILS_H
44 #endif // SCIQLOP_AXISRENDERINGUTILS_H
@@ -1,6 +1,8
1 #ifndef SCIQLOP_PLOTTABLESRENDERINGUTILS_H
1 #ifndef SCIQLOP_PLOTTABLESRENDERINGUTILS_H
2 #define SCIQLOP_PLOTTABLESRENDERINGUTILS_H
2 #define SCIQLOP_PLOTTABLESRENDERINGUTILS_H
3
3
4 #include <Data/DataSeriesType.h>
5
4 #include <Visualization/VisualizationDefs.h>
6 #include <Visualization/VisualizationDefs.h>
5
7
6 #include <memory>
8 #include <memory>
@@ -9,9 +11,9
9
11
10 Q_DECLARE_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils)
11
13
12 class IDataSeries;
13 class QCPColorScale;
14 class QCPColorScale;
14 class QCustomPlot;
15 class QCustomPlot;
16 class Variable;
15
17
16 /**
18 /**
17 * Helper used to handle plottables rendering
19 * Helper used to handle plottables rendering
@@ -25,9 +27,8 struct IPlottablesHelper {
25 };
27 };
26
28
27 struct IPlottablesHelperFactory {
29 struct IPlottablesHelperFactory {
28 /// Creates IPlottablesHelper according to a data series
30 /// Creates IPlottablesHelper according to the type of data series a variable holds
29 static std::unique_ptr<IPlottablesHelper>
31 static std::unique_ptr<IPlottablesHelper> create(const Variable &variable) noexcept;
30 create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
31 };
32 };
32
33
33 #endif // SCIQLOP_PLOTTABLESRENDERINGUTILS_H
34 #endif // SCIQLOP_PLOTTABLESRENDERINGUTILS_H
@@ -32,7 +32,7 struct VisualizationGraphHelper {
32 */
32 */
33 static PlottablesMap create(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
33 static PlottablesMap create(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
34
34
35 static void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
35 static void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
36 const SqpRange &dateTime);
36 const SqpRange &dateTime);
37
37
38 static void setYAxisRange(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
38 static void setYAxisRange(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
@@ -9,6 +9,7 class IDataSeries;
9 class QCustomPlot;
9 class QCustomPlot;
10 class QMouseEvent;
10 class QMouseEvent;
11 class Unit;
11 class Unit;
12 class Variable;
12 class VisualizationGraphWidget;
13 class VisualizationGraphWidget;
13
14
14 class VisualizationGraphRenderingDelegate {
15 class VisualizationGraphRenderingDelegate {
@@ -23,13 +24,14 public:
23 /// Updates rendering when data of plot changed
24 /// Updates rendering when data of plot changed
24 void onPlotUpdated() noexcept;
25 void onPlotUpdated() noexcept;
25
26
26 /// Sets properties of the plot's axes from the data series passed as parameter
27 /// Sets units of the plot's axes according to the properties of the variable passed as
27 void setAxesProperties(std::shared_ptr<IDataSeries> dataSeries) noexcept;
28 /// parameter
29 void setAxesUnits(const Variable &variable) noexcept;
28
30
29 /// Sets rendering properties of the plottables passed as parameter, from the data series that
31 /// Sets graph properties of the plottables passed as parameter, from the variable that
30 /// generated these
32 /// generated these
31 void setPlottablesProperties(std::shared_ptr<IDataSeries> dataSeries,
33 void setGraphProperties(const Variable &variable, PlottablesMap &plottables) noexcept;
32 PlottablesMap &plottables) noexcept;
34
33
35
34 /// Shows or hides graph overlay (name, close button, etc.)
36 /// Shows or hides graph overlay (name, close button, etc.)
35 void showGraphOverlay(bool show) noexcept;
37 void showGraphOverlay(bool show) noexcept;
@@ -25,6 +25,20 namespace Ui {
25 class VisualizationGraphWidget;
25 class VisualizationGraphWidget;
26 } // namespace Ui
26 } // namespace Ui
27
27
28 /// Defines options that can be associated with the graph
29 enum GraphFlag {
30 DisableAll = 0x0, ///< Disables acquisition and synchronization
31 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
32 /// the acquisition of data
33 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
34 /// the call to the synchronization of the graphs contained in the
35 /// same zone of this graph
36 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
37 };
38
39 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
40 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
41
28 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
42 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
29 Q_OBJECT
43 Q_OBJECT
30
44
@@ -41,8 +55,8 public:
41 /// Returns the main VisualizationWidget which contains the graph or nullptr
55 /// Returns the main VisualizationWidget which contains the graph or nullptr
42 VisualizationWidget *parentVisualizationWidget() const;
56 VisualizationWidget *parentVisualizationWidget() const;
43
57
44 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
58 /// Sets graph options
45 void enableAcquisition(bool enable);
59 void setFlags(GraphFlags flags);
46
60
47 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
61 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
48
62
@@ -55,13 +69,16 public:
55 /// Sets the y-axis range based on the data of a variable
69 /// Sets the y-axis range based on the data of a variable
56 void setYRange(std::shared_ptr<Variable> variable);
70 void setYRange(std::shared_ptr<Variable> variable);
57 SqpRange graphRange() const noexcept;
71 SqpRange graphRange() const noexcept;
58 void setGraphRange(const SqpRange &range);
72 void setGraphRange(const SqpRange &range, bool calibration = false);
73 void setAutoRangeOnVariableInitialization(bool value);
59
74
60 // Zones
75 // Zones
61 /// Returns the ranges of all the selection zones on the graph
76 /// Returns the ranges of all the selection zones on the graph
62 QVector<SqpRange> selectionZoneRanges() const;
77 QVector<SqpRange> selectionZoneRanges() const;
63 /// Adds new selection zones in the graph
78 /// Adds new selection zones in the graph
64 void addSelectionZones(const QVector<SqpRange> &ranges);
79 void addSelectionZones(const QVector<SqpRange> &ranges);
80 /// Adds a new selection zone in the graph
81 VisualizationSelectionZoneItem *addSelectionZone(const QString &name, const SqpRange &range);
65 /// Removes the specified selection zone
82 /// Removes the specified selection zone
66 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
83 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
67
84
@@ -8,6 +8,11
8 class VisualizationGraphWidget;
8 class VisualizationGraphWidget;
9
9
10 class VisualizationSelectionZoneItem : public QCPItemRect {
10 class VisualizationSelectionZoneItem : public QCPItemRect {
11 Q_OBJECT
12
13 signals:
14 /// Signal emitted when the zone range is edited manually
15 void rangeEdited(const SqpRange &range);
11
16
12 public:
17 public:
13 VisualizationSelectionZoneItem(QCustomPlot *plot);
18 VisualizationSelectionZoneItem(QCustomPlot *plot);
@@ -68,6 +68,9 public:
68 /// Returns the first graph in the zone or nullptr if there is no graph inside
68 /// Returns the first graph in the zone or nullptr if there is no graph inside
69 VisualizationGraphWidget *firstGraph() const;
69 VisualizationGraphWidget *firstGraph() const;
70
70
71 /// Closes all graphes inside the zone
72 void closeAllGraphs();
73
71 // IVisualizationWidget interface
74 // IVisualizationWidget interface
72 void accept(IVisualizationWidgetVisitor *visitor) override;
75 void accept(IVisualizationWidgetVisitor *visitor) override;
73 bool canDrop(const Variable &variable) const override;
76 bool canDrop(const Variable &variable) const override;
@@ -1,5 +1,3
1 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
2 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
3
1
4 gui_moc_headers = [
2 gui_moc_headers = [
5 'include/DataSource/DataSourceWidget.h',
3 'include/DataSource/DataSourceWidget.h',
@@ -20,6 +18,7 gui_moc_headers = [
20 'include/Visualization/VisualizationDragDropContainer.h',
18 'include/Visualization/VisualizationDragDropContainer.h',
21 'include/Visualization/VisualizationDragWidget.h',
19 'include/Visualization/VisualizationDragWidget.h',
22 'include/Visualization/ColorScaleEditor.h',
20 'include/Visualization/ColorScaleEditor.h',
21 'include/Visualization/VisualizationSelectionZoneItem.h',
23 'include/Actions/SelectionZoneAction.h',
22 'include/Actions/SelectionZoneAction.h',
24 'include/Visualization/VisualizationMultiZoneSelectionDialog.h',
23 'include/Visualization/VisualizationMultiZoneSelectionDialog.h',
25 'include/Catalogue/CatalogueExplorer.h',
24 'include/Catalogue/CatalogueExplorer.h',
@@ -27,8 +26,8 gui_moc_headers = [
27 'include/Catalogue/CatalogueSideBarWidget.h',
26 'include/Catalogue/CatalogueSideBarWidget.h',
28 'include/Catalogue/CatalogueInspectorWidget.h',
27 'include/Catalogue/CatalogueInspectorWidget.h',
29 'include/Catalogue/CatalogueEventsModel.h',
28 'include/Catalogue/CatalogueEventsModel.h',
30 'include/Catalogue/CreateEventDialog.h',
29 'include/Catalogue/CatalogueTreeModel.h',
31 'include/Catalogue/CatalogueTreeModel.h'
30 'include/Actions/FilteringAction.h'
32 ]
31 ]
33
32
34 gui_ui_files = [
33 gui_ui_files = [
@@ -49,8 +48,7 gui_ui_files = [
49 'ui/Catalogue/CatalogueExplorer.ui',
48 'ui/Catalogue/CatalogueExplorer.ui',
50 'ui/Catalogue/CatalogueEventsWidget.ui',
49 'ui/Catalogue/CatalogueEventsWidget.ui',
51 'ui/Catalogue/CatalogueSideBarWidget.ui',
50 'ui/Catalogue/CatalogueSideBarWidget.ui',
52 'ui/Catalogue/CatalogueInspectorWidget.ui',
51 'ui/Catalogue/CatalogueInspectorWidget.ui'
53 'ui/Catalogue/CreateEventDialog.ui'
54 ]
52 ]
55
53
56 gui_qresources = ['resources/sqpguiresources.qrc']
54 gui_qresources = ['resources/sqpguiresources.qrc']
@@ -113,6 +111,7 gui_sources = [
113 'src/Visualization/VisualizationSelectionZoneManager.cpp',
111 'src/Visualization/VisualizationSelectionZoneManager.cpp',
114 'src/Actions/SelectionZoneAction.cpp',
112 'src/Actions/SelectionZoneAction.cpp',
115 'src/Actions/ActionsGuiController.cpp',
113 'src/Actions/ActionsGuiController.cpp',
114 'src/Actions/FilteringAction.cpp',
116 'src/Visualization/VisualizationActionManager.cpp',
115 'src/Visualization/VisualizationActionManager.cpp',
117 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
116 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
118 'src/Catalogue/CatalogueExplorer.cpp',
117 'src/Catalogue/CatalogueExplorer.cpp',
@@ -125,7 +124,6 gui_sources = [
125 'src/Catalogue/CatalogueEventsModel.cpp',
124 'src/Catalogue/CatalogueEventsModel.cpp',
126 'src/Catalogue/CatalogueExplorerHelper.cpp',
125 'src/Catalogue/CatalogueExplorerHelper.cpp',
127 'src/Catalogue/CatalogueActionManager.cpp',
126 'src/Catalogue/CatalogueActionManager.cpp',
128 'src/Catalogue/CreateEventDialog.cpp',
129 'src/Catalogue/CatalogueTreeModel.cpp'
127 'src/Catalogue/CatalogueTreeModel.cpp'
130 ]
128 ]
131
129
@@ -136,12 +134,12 sciqlop_gui_lib = library('sciqlopgui',
136 gui_moc_files,
134 gui_moc_files,
137 rcc_files,
135 rcc_files,
138 include_directories : [gui_inc],
136 include_directories : [gui_inc],
139 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep],
137 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
140 install : true
138 install : true
141 )
139 )
142
140
143 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
141 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
144 include_directories : gui_inc,
142 include_directories : gui_inc,
145 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep])
143 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
146
144
147
145
1 NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden
NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden
@@ -3,6 +3,7
3 struct ActionsGuiController::ActionsGuiControllerPrivate {
3 struct ActionsGuiController::ActionsGuiControllerPrivate {
4
4
5 QVector<std::shared_ptr<SelectionZoneAction> > m_SelectionZoneActions;
5 QVector<std::shared_ptr<SelectionZoneAction> > m_SelectionZoneActions;
6 QSet<QStringList> m_FilteredMenu;
6 };
7 };
7
8
8 ActionsGuiController::ActionsGuiController()
9 ActionsGuiController::ActionsGuiController()
@@ -34,3 +35,18 QVector<std::shared_ptr<SelectionZoneAction> > ActionsGuiController::selectionZo
34 {
35 {
35 return impl->m_SelectionZoneActions;
36 return impl->m_SelectionZoneActions;
36 }
37 }
38
39 void ActionsGuiController::removeAction(const std::shared_ptr<SelectionZoneAction> &action)
40 {
41 impl->m_SelectionZoneActions.removeAll(action);
42 }
43
44 void ActionsGuiController::addFilterForMenu(const QStringList &menuPath)
45 {
46 impl->m_FilteredMenu.insert(menuPath);
47 }
48
49 bool ActionsGuiController::isMenuFiltered(const QStringList &menuPath) const
50 {
51 return impl->m_FilteredMenu.contains(menuPath);
52 }
@@ -15,6 +15,7 struct SelectionZoneAction::SelectionZoneActionPrivate {
15 QKeySequence m_DisplayedShortcut;
15 QKeySequence m_DisplayedShortcut;
16 SelectionZoneAction::ExecuteFunction m_Fun;
16 SelectionZoneAction::ExecuteFunction m_Fun;
17 SelectionZoneAction::EnableFunction m_EnableFun = [](auto zones) { return true; };
17 SelectionZoneAction::EnableFunction m_EnableFun = [](auto zones) { return true; };
18 bool m_FilteringAllowed = true;
18 };
19 };
19
20
20 SelectionZoneAction::SelectionZoneAction(const QString &name, ExecuteFunction fun)
21 SelectionZoneAction::SelectionZoneAction(const QString &name, ExecuteFunction fun)
@@ -55,6 +56,16 QStringList SelectionZoneAction::subMenuList() const noexcept
55 return impl->m_SubMenuList;
56 return impl->m_SubMenuList;
56 }
57 }
57
58
59 void SelectionZoneAction::setAllowedFiltering(bool value)
60 {
61 impl->m_FilteringAllowed = value;
62 }
63
64 bool SelectionZoneAction::isFilteringAllowed() const
65 {
66 return impl->m_FilteringAllowed;
67 }
68
58 void SelectionZoneAction::execute(const QVector<VisualizationSelectionZoneItem *> &item)
69 void SelectionZoneAction::execute(const QVector<VisualizationSelectionZoneItem *> &item)
59 {
70 {
60 impl->m_Fun(item);
71 impl->m_Fun(item);
@@ -11,7 +11,6
11 #include <Catalogue/CatalogueEventsWidget.h>
11 #include <Catalogue/CatalogueEventsWidget.h>
12 #include <Catalogue/CatalogueExplorer.h>
12 #include <Catalogue/CatalogueExplorer.h>
13 #include <Catalogue/CatalogueSideBarWidget.h>
13 #include <Catalogue/CatalogueSideBarWidget.h>
14 #include <Catalogue/CreateEventDialog.h>
15
14
16 #include <CatalogueDao.h>
15 #include <CatalogueDao.h>
17 #include <DBCatalogue.h>
16 #include <DBCatalogue.h>
@@ -25,9 +24,16
25 #include <QLineEdit>
24 #include <QLineEdit>
26 #include <memory>
25 #include <memory>
27
26
27 const auto CATALOGUE_MENU_NAME = QObject::tr("Catalogues");
28 const auto CATALOGUE_CREATE_EVENT_MENU_NAME = QObject::tr("New Event...");
29
30 const auto DEFAULT_EVENT_NAME = QObject::tr("Event");
31 const auto DEFAULT_CATALOGUE_NAME = QObject::tr("Catalogue");
32
28 struct CatalogueActionManager::CatalogueActionManagerPrivate {
33 struct CatalogueActionManager::CatalogueActionManagerPrivate {
29
34
30 CatalogueExplorer *m_CatalogueExplorer = nullptr;
35 CatalogueExplorer *m_CatalogueExplorer = nullptr;
36 QVector<std::shared_ptr<SelectionZoneAction> > m_CreateInCatalogueActions;
31
37
32 CatalogueActionManagerPrivate(CatalogueExplorer *catalogueExplorer)
38 CatalogueActionManagerPrivate(CatalogueExplorer *catalogueExplorer)
33 : m_CatalogueExplorer(catalogueExplorer)
39 : m_CatalogueExplorer(catalogueExplorer)
@@ -48,12 +54,14 struct CatalogueActionManager::CatalogueActionManagerPrivate {
48 auto eventProduct = std::make_shared<DBEventProduct>();
54 auto eventProduct = std::make_shared<DBEventProduct>();
49 eventProduct->setEvent(*event);
55 eventProduct->setEvent(*event);
50
56
57 auto productId
58 = var->metadata().value(DataSourceItem::ID_DATA_KEY, "UnknownID").toString();
59
51 auto zoneRange = zone->range();
60 auto zoneRange = zone->range();
52 eventProduct->setTStart(zoneRange.m_TStart);
61 eventProduct->setTStart(zoneRange.m_TStart);
53 eventProduct->setTEnd(zoneRange.m_TEnd);
62 eventProduct->setTEnd(zoneRange.m_TEnd);
54
63
55 eventProduct->setProductId(
64 eventProduct->setProductId(productId);
56 var->metadata().value(DataSourceItem::ID_DATA_KEY, "UnknownID").toString());
57
65
58 productList.push_back(*eventProduct);
66 productList.push_back(*eventProduct);
59 }
67 }
@@ -65,8 +73,8 struct CatalogueActionManager::CatalogueActionManagerPrivate {
65
73
66
74
67 if (catalogue) {
75 if (catalogue) {
68 // TODO
76 catalogue->addEvent(event->getUniqId());
69 // catalogue->addEvent(event);
77 sqpApp->catalogueController().updateCatalogue(catalogue);
70 m_CatalogueExplorer->sideBarWidget().setCatalogueChanges(catalogue, true);
78 m_CatalogueExplorer->sideBarWidget().setCatalogueChanges(catalogue, true);
71 if (m_CatalogueExplorer->eventsWidget().displayedCatalogues().contains(catalogue)) {
79 if (m_CatalogueExplorer->eventsWidget().displayedCatalogues().contains(catalogue)) {
72 m_CatalogueExplorer->eventsWidget().addEvent(event);
80 m_CatalogueExplorer->eventsWidget().addEvent(event);
@@ -78,6 +86,32 struct CatalogueActionManager::CatalogueActionManagerPrivate {
78 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
86 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
79 }
87 }
80 }
88 }
89
90 SelectionZoneAction::EnableFunction createEventEnableFuntion() const
91 {
92 return [](auto zones) {
93
94 // Checks that all variables in the zones doesn't refer to the same product
95 QSet<QString> usedDatasource;
96 for (auto zone : zones) {
97 auto graph = zone->parentGraphWidget();
98 auto variables = graph->variables();
99
100 for (auto var : variables) {
101 auto datasourceId
102 = var->metadata().value(DataSourceItem::ID_DATA_KEY).toString();
103 if (!usedDatasource.contains(datasourceId)) {
104 usedDatasource.insert(datasourceId);
105 }
106 else {
107 return false;
108 }
109 }
110 }
111
112 return true;
113 };
114 }
81 };
115 };
82
116
83 CatalogueActionManager::CatalogueActionManager(CatalogueExplorer *catalogueExplorer)
117 CatalogueActionManager::CatalogueActionManager(CatalogueExplorer *catalogueExplorer)
@@ -89,48 +123,52 void CatalogueActionManager::installSelectionZoneActions()
89 {
123 {
90 auto &actionController = sqpApp->actionsGuiController();
124 auto &actionController = sqpApp->actionsGuiController();
91
125
92 auto createEventEnableFuntion = [](auto zones) {
93 QSet<VisualizationGraphWidget *> usedGraphs;
94 for (auto zone : zones) {
95 auto graph = zone->parentGraphWidget();
96 if (!usedGraphs.contains(graph)) {
97 usedGraphs.insert(graph);
98 }
99 else {
100 return false;
101 }
102 }
103
104 return true;
105 };
106
107 auto createEventAction = actionController.addSectionZoneAction(
126 auto createEventAction = actionController.addSectionZoneAction(
108 {QObject::tr("Catalogues")}, QObject::tr("New Event..."), [this](auto zones) {
127 {CATALOGUE_MENU_NAME, CATALOGUE_CREATE_EVENT_MENU_NAME}, QObject::tr("Without Catalogue"),
109 CreateEventDialog dialog(
128 [this](auto zones) { impl->createEventFromZones(DEFAULT_EVENT_NAME, zones); });
110 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
129 createEventAction->setEnableFunction(impl->createEventEnableFuntion());
111 dialog.hideCatalogueChoice();
130 createEventAction->setAllowedFiltering(false);
112 if (dialog.exec() == QDialog::Accepted) {
131
113 impl->createEventFromZones(dialog.eventName(), zones);
132 auto createEventInNewCatalogueAction = actionController.addSectionZoneAction(
114 }
133 {CATALOGUE_MENU_NAME, CATALOGUE_CREATE_EVENT_MENU_NAME}, QObject::tr("In New Catalogue"),
134 [this](auto zones) {
135
136 auto newCatalogue = std::make_shared<DBCatalogue>();
137 newCatalogue->setName(DEFAULT_CATALOGUE_NAME);
138 sqpApp->catalogueController().addCatalogue(newCatalogue);
139 impl->m_CatalogueExplorer->sideBarWidget().addCatalogue(newCatalogue,
140 REPOSITORY_DEFAULT);
141
142 impl->createEventFromZones(DEFAULT_EVENT_NAME, zones, newCatalogue);
115 });
143 });
116 createEventAction->setEnableFunction(createEventEnableFuntion);
144 createEventInNewCatalogueAction->setEnableFunction(impl->createEventEnableFuntion());
117
145 createEventInNewCatalogueAction->setAllowedFiltering(false);
118 auto createEventInCatalogueAction = actionController.addSectionZoneAction(
119 {QObject::tr("Catalogues")}, QObject::tr("New Event in Catalogue..."), [this](auto zones) {
120 CreateEventDialog dialog(
121 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
122 if (dialog.exec() == QDialog::Accepted) {
123 auto selectedCatalogue = dialog.selectedCatalogue();
124 if (!selectedCatalogue) {
125 selectedCatalogue = std::make_shared<DBCatalogue>();
126 selectedCatalogue->setName(dialog.catalogueName());
127 // sqpApp->catalogueController().addCatalogue(selectedCatalogue); TODO
128 impl->m_CatalogueExplorer->sideBarWidget().addCatalogue(selectedCatalogue,
129 REPOSITORY_DEFAULT);
130 }
131
146
132 impl->createEventFromZones(dialog.eventName(), zones, selectedCatalogue);
147 refreshCreateInCatalogueAction();
133 }
148
134 });
149 actionController.addFilterForMenu({CATALOGUE_MENU_NAME, CATALOGUE_CREATE_EVENT_MENU_NAME});
135 createEventInCatalogueAction->setEnableFunction(createEventEnableFuntion);
150 }
151
152 void CatalogueActionManager::refreshCreateInCatalogueAction()
153 {
154 auto &actionController = sqpApp->actionsGuiController();
155
156 for (auto action : impl->m_CreateInCatalogueActions) {
157 actionController.removeAction(action);
158 }
159 impl->m_CreateInCatalogueActions.clear();
160
161 auto allCatalogues
162 = impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT);
163
164 for (auto catalogue : allCatalogues) {
165 auto catalogueName = catalogue->getName();
166 auto createEventInCatalogueAction = actionController.addSectionZoneAction(
167 {CATALOGUE_MENU_NAME, CATALOGUE_CREATE_EVENT_MENU_NAME},
168 QObject::tr("In \"").append(catalogueName).append("\""), [this, catalogue](auto zones) {
169 impl->createEventFromZones(DEFAULT_EVENT_NAME, zones, catalogue);
170 });
171 createEventInCatalogueAction->setEnableFunction(impl->createEventEnableFuntion());
172 impl->m_CreateInCatalogueActions << createEventInCatalogueAction;
173 }
136 }
174 }
@@ -24,6 +24,7 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
24 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
24 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
25 QVector<std::shared_ptr<DBEvent> > m_Events;
25 QVector<std::shared_ptr<DBEvent> > m_Events;
26 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
26 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
27 QVector<std::shared_ptr<DBCatalogue> > m_SourceCatalogue;
27
28
28 QStringList columnNames()
29 QStringList columnNames()
29 {
30 {
@@ -47,13 +48,23 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
47 case CatalogueEventsModel::Column::Name:
48 case CatalogueEventsModel::Column::Name:
48 return event->getName();
49 return event->getName();
49 case CatalogueEventsModel::Column::TStart:
50 case CatalogueEventsModel::Column::TStart:
50 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
51 return nbEventProducts(event) > 0
51 : QVariant{};
52 ? DateUtils::dateTime(event->getTStart())
53 .toString(DATETIME_FORMAT_ONE_LINE)
54 : QVariant{};
52 case CatalogueEventsModel::Column::TEnd:
55 case CatalogueEventsModel::Column::TEnd:
53 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
56 return nbEventProducts(event) > 0
54 : QVariant{};
57 ? DateUtils::dateTime(event->getTEnd())
55 case CatalogueEventsModel::Column::Product:
58 .toString(DATETIME_FORMAT_ONE_LINE)
56 return QString::number(nbEventProducts(event)) + " product(s)";
59 : QVariant{};
60 case CatalogueEventsModel::Column::Product: {
61 auto eventProducts = event->getEventProducts();
62 QStringList eventProductList;
63 for (auto evtProduct : eventProducts) {
64 eventProductList << evtProduct.getProductId();
65 }
66 return eventProductList.join(";");
67 }
57 case CatalogueEventsModel::Column::Tags: {
68 case CatalogueEventsModel::Column::Tags: {
58 QString tagList;
69 QString tagList;
59 auto tags = event->getTags();
70 auto tags = event->getTags();
@@ -98,9 +109,11 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
98 case CatalogueEventsModel::Column::Name:
109 case CatalogueEventsModel::Column::Name:
99 return eventProduct->getProductId();
110 return eventProduct->getProductId();
100 case CatalogueEventsModel::Column::TStart:
111 case CatalogueEventsModel::Column::TStart:
101 return DateUtils::dateTime(eventProduct->getTStart());
112 return DateUtils::dateTime(eventProduct->getTStart())
113 .toString(DATETIME_FORMAT_ONE_LINE);
102 case CatalogueEventsModel::Column::TEnd:
114 case CatalogueEventsModel::Column::TEnd:
103 return DateUtils::dateTime(eventProduct->getTEnd());
115 return DateUtils::dateTime(eventProduct->getTEnd())
116 .toString(DATETIME_FORMAT_ONE_LINE);
104 case CatalogueEventsModel::Column::Product:
117 case CatalogueEventsModel::Column::Product:
105 return eventProduct->getProductId();
118 return eventProduct->getProductId();
106 case CatalogueEventsModel::Column::Tags:
119 case CatalogueEventsModel::Column::Tags:
@@ -129,6 +142,12 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
129 {
142 {
130 }
143 }
131
144
145 void CatalogueEventsModel::setSourceCatalogues(
146 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
147 {
148 impl->m_SourceCatalogue = catalogues;
149 }
150
132 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
151 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
133 {
152 {
134 beginResetModel();
153 beginResetModel();
@@ -388,12 +407,12 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
388
407
389 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
408 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
390 {
409 {
391 return Qt::CopyAction;
410 return Qt::CopyAction | Qt::MoveAction;
392 }
411 }
393
412
394 QStringList CatalogueEventsModel::mimeTypes() const
413 QStringList CatalogueEventsModel::mimeTypes() const
395 {
414 {
396 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_TIME_RANGE};
415 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_SOURCE_CATALOGUE_LIST, MIME_TYPE_TIME_RANGE};
397 }
416 }
398
417
399 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
418 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
@@ -436,6 +455,10 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
436 if (!eventList.isEmpty() && eventProductList.isEmpty()) {
455 if (!eventList.isEmpty() && eventProductList.isEmpty()) {
437 auto eventsEncodedData = sqpApp->catalogueController().mimeDataForEvents(eventList);
456 auto eventsEncodedData = sqpApp->catalogueController().mimeDataForEvents(eventList);
438 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
457 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
458
459 auto sourceCataloguesEncodedData
460 = sqpApp->catalogueController().mimeDataForCatalogues(impl->m_SourceCatalogue);
461 mimeData->setData(MIME_TYPE_SOURCE_CATALOGUE_LIST, sourceCataloguesEncodedData);
439 }
462 }
440
463
441 if (eventList.count() + eventProductList.count() == 1) {
464 if (eventList.count() + eventProductList.count() == 1) {
@@ -6,20 +6,31
6 #include <Catalogue/CatalogueExplorerHelper.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
7 #include <CatalogueDao.h>
7 #include <CatalogueDao.h>
8 #include <DBCatalogue.h>
8 #include <DBCatalogue.h>
9 #include <DBEventProduct.h>
10 #include <DataSource/DataSourceController.h>
11 #include <DataSource/DataSourceItem.h>
9 #include <SqpApplication.h>
12 #include <SqpApplication.h>
13 #include <Variable/Variable.h>
14 #include <Variable/VariableController.h>
15 #include <Visualization/VisualizationGraphWidget.h>
10 #include <Visualization/VisualizationTabWidget.h>
16 #include <Visualization/VisualizationTabWidget.h>
11 #include <Visualization/VisualizationWidget.h>
17 #include <Visualization/VisualizationWidget.h>
12 #include <Visualization/VisualizationZoneWidget.h>
18 #include <Visualization/VisualizationZoneWidget.h>
13
19
20 #include <QActionGroup>
14 #include <QDialog>
21 #include <QDialog>
15 #include <QDialogButtonBox>
22 #include <QDialogButtonBox>
23 #include <QKeyEvent>
16 #include <QListWidget>
24 #include <QListWidget>
25 #include <QMenu>
17 #include <QMessageBox>
26 #include <QMessageBox>
18
27
19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
28 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
20
29
21 /// Fixed size of the validation column
30 /// Percentage added to the range of a event when it is displayed
22 const auto VALIDATION_COLUMN_SIZE = 35;
31 const auto EVENT_RANGE_MARGE = 30; // in %
32
33 const QString NEW_ZONE_TEXT = QStringLiteral("New Zone");
23
34
24 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
35 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
25
36
@@ -27,12 +38,15 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
27 QStringList m_ZonesForTimeMode;
38 QStringList m_ZonesForTimeMode;
28 QString m_ZoneForGraphMode;
39 QString m_ZoneForGraphMode;
29 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
40 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
41 bool m_AllEventDisplayed = false;
42 QVector<VisualizationGraphWidget *> m_CustomGraphs;
30
43
31 VisualizationWidget *m_VisualizationWidget = nullptr;
44 VisualizationWidget *m_VisualizationWidget = nullptr;
32
45
33 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
46 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
34 {
47 {
35 widget->ui->treeView->setSortingEnabled(false);
48 widget->ui->treeView->setSortingEnabled(false);
49 m_Model->setSourceCatalogues(m_DisplayedCatalogues);
36 m_Model->setEvents(events);
50 m_Model->setEvents(events);
37 widget->ui->treeView->setSortingEnabled(true);
51 widget->ui->treeView->setSortingEnabled(true);
38
52
@@ -70,72 +84,46 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
70 }
84 }
71
85
72 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
86 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
73 bool allowMultiSelection, const QPoint &location)
87 bool allowMultiSelection, bool addNewZoneOption, const QPoint &location)
74 {
88 {
75 auto availableZones = getAvailableVisualizationZoneList();
89 auto availableZones = getAvailableVisualizationZoneList();
76 if (availableZones.isEmpty()) {
90 if (!addNewZoneOption && availableZones.isEmpty()) {
77 return QStringList{};
91 return QStringList{};
78 }
92 }
79
93
80 QDialog d(parent, Qt::Tool);
94 QActionGroup actionGroup{parent};
81 d.setWindowTitle("Choose a zone");
95 actionGroup.setExclusive(!allowMultiSelection);
82 auto layout = new QVBoxLayout{&d};
83 layout->setContentsMargins(0, 0, 0, 0);
84 auto listWidget = new QListWidget{&d};
85 layout->addWidget(listWidget);
86
96
87 QSet<QListWidgetItem *> checkedItems;
97 QVector<QAction *> zoneActions;
88 for (auto zone : availableZones) {
98
89 auto item = new QListWidgetItem{zone};
99 QMenu selectionMenu{parent};
90 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
91 if (selectedZones.contains(zone)) {
92 item->setCheckState(Qt::Checked);
93 checkedItems << item;
94 }
95 else {
96 item->setCheckState(Qt::Unchecked);
97 }
98
100
99 listWidget->addItem(item);
101 if (addNewZoneOption) {
102 availableZones.prepend(NEW_ZONE_TEXT);
100 }
103 }
101
104
102 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
105 selectionMenu.addSeparator();
103 layout->addWidget(buttonBox);
106 for (auto zone : availableZones) {
104
107 auto zoneAction = selectionMenu.addAction(zone);
105 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
108 zoneAction->setCheckable(true);
106 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
109 zoneAction->setChecked(selectedZones.contains(zone));
107
110 actionGroup.addAction(zoneAction);
108 QObject::connect(listWidget, &QListWidget::itemChanged,
111 zoneActions << zoneAction;
109 [&checkedItems, allowMultiSelection, listWidget](auto item) {
112 }
110 if (item->checkState() == Qt::Checked) {
113
111 if (!allowMultiSelection) {
114 auto resultAction = selectionMenu.exec(QCursor::pos());
112 for (auto checkedItem : checkedItems) {
113 listWidget->blockSignals(true);
114 checkedItem->setCheckState(Qt::Unchecked);
115 listWidget->blockSignals(false);
116 }
117
118 checkedItems.clear();
119 }
120 checkedItems << item;
121 }
122 else {
123 checkedItems.remove(item);
124 }
125 });
126
115
127 QStringList result;
116 QStringList result;
128
117
129 d.setMinimumWidth(120);
118 if (resultAction == nullptr) {
130 d.resize(d.minimumSizeHint());
119 result = selectedZones;
131 d.move(location);
132 if (d.exec() == QDialog::Accepted) {
133 for (auto item : checkedItems) {
134 result += item->text();
135 }
136 }
120 }
137 else {
121 else {
138 result = selectedZones;
122 for (auto zoneAction : zoneActions) {
123 if (zoneAction->isChecked()) {
124 result << zoneAction->text();
125 }
126 }
139 }
127 }
140
128
141 return result;
129 return result;
@@ -177,31 +165,146 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
177 }
165 }
178 }
166 }
179
167
180 void updateForGraphMode(QTreeView *treeView)
168 QVector<SqpRange> getGraphRanges(const std::shared_ptr<DBEvent> &event)
181 {
169 {
182 auto selectedRows = treeView->selectionModel()->selectedRows();
170 // Retrieves the range of each product and the maximum size
183
171 QVector<SqpRange> graphRanges;
184 if (selectedRows.count() == 1) {
172 double maxDt = 0;
185 auto event = m_Model->getEvent(selectedRows.first());
173 for (auto eventProduct : event->getEventProducts()) {
186 if (m_VisualizationWidget) {
174 SqpRange eventRange;
187 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
175 eventRange.m_TStart = eventProduct.getTStart();
188 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
176 eventRange.m_TEnd = eventProduct.getTEnd();
189 // TODO
177 graphRanges << eventRange;
190 }
178
191 }
179 auto dt = eventRange.m_TEnd - eventRange.m_TStart;
192 else {
180 if (dt > maxDt) {
193 qCWarning(LOG_CatalogueEventsWidget())
181 maxDt = dt;
194 << "updateGraphMode: no tab found in the visualization";
195 }
196 }
197 else {
198 qCWarning(LOG_CatalogueEventsWidget())
199 << "updateGraphMode: visualization widget not found";
200 }
182 }
201 }
183 }
202 else {
184
185 // Adds the marge
186 maxDt *= (100.0 + EVENT_RANGE_MARGE) / 100.0;
187
188 // Corrects the graph ranges so that they all have the same size
189 QVector<SqpRange> correctedGraphRanges;
190 for (auto range : graphRanges) {
191 auto dt = range.m_TEnd - range.m_TStart;
192 auto diff = qAbs((maxDt - dt) / 2.0);
193
194 SqpRange correctedRange;
195 correctedRange.m_TStart = range.m_TStart - diff;
196 correctedRange.m_TEnd = range.m_TEnd + diff;
197
198 correctedGraphRanges << correctedRange;
199 }
200
201 return correctedGraphRanges;
202 }
203
204 void updateForGraphMode(CatalogueEventsWidget *catalogueEventWidget)
205 {
206 auto selectedRows = catalogueEventWidget->ui->treeView->selectionModel()->selectedRows();
207 if (selectedRows.count() != 1) {
203 qCWarning(LOG_CatalogueEventsWidget())
208 qCWarning(LOG_CatalogueEventsWidget())
204 << "updateGraphMode: not compatible with multiple events selected";
209 << "updateGraphMode: not compatible with multiple events selected";
210 return;
211 }
212
213 if (!m_VisualizationWidget) {
214 qCWarning(LOG_CatalogueEventsWidget())
215 << "updateGraphMode: visualization widget not found";
216 return;
217 }
218
219 auto event = m_Model->getEvent(selectedRows.first());
220 if (!event) {
221 // A event product is probably selected
222 qCInfo(LOG_CatalogueEventsWidget()) << "updateGraphMode: no events are selected";
223 return;
224 }
225
226 auto tab = m_VisualizationWidget->currentTabWidget();
227 if (!tab) {
228 qCWarning(LOG_CatalogueEventsWidget())
229 << "updateGraphMode: no tab found in the visualization";
230 return;
231 }
232
233 auto isNewZone = m_ZoneForGraphMode == NEW_ZONE_TEXT;
234 auto zone = tab->getZoneWithName(m_ZoneForGraphMode);
235 if (!isNewZone && !zone) {
236 qCWarning(LOG_CatalogueEventsWidget()) << "updateGraphMode: zone not found";
237 return;
238 }
239
240 // Closes the previous graph and delete the asociated variables
241 for (auto graph : m_CustomGraphs) {
242 graph->close();
243 auto variables = graph->variables().toVector();
244
245 QMetaObject::invokeMethod(&sqpApp->variableController(), "deleteVariables",
246 Qt::QueuedConnection,
247 Q_ARG(QVector<std::shared_ptr<Variable> >, variables));
248 }
249 m_CustomGraphs.clear();
250
251 // Closes the remaining graphs inside the zone
252 if (zone) {
253 zone->closeAllGraphs();
254 }
255
256 // Creates the zone if needed
257 if (isNewZone) {
258 zone = tab->createEmptyZone(0);
259 m_ZoneForGraphMode = zone->name();
260 }
261
262 // Calculates the range of each graph which will be created
263 auto graphRange = getGraphRanges(event);
264
265 // Loops through the event products and create the graph
266 auto itRange = graphRange.cbegin();
267 for (auto eventProduct : event->getEventProducts()) {
268 auto productId = eventProduct.getProductId();
269
270 auto range = *itRange;
271 ++itRange;
272
273 SqpRange productRange;
274 productRange.m_TStart = eventProduct.getTStart();
275 productRange.m_TEnd = eventProduct.getTEnd();
276
277 auto context = new QObject{catalogueEventWidget};
278 QObject::connect(
279 &sqpApp->variableController(), &VariableController::variableAdded, context,
280 [this, catalogueEventWidget, zone, context, event, range, productRange,
281 productId](auto variable) {
282
283 if (variable->metadata().value(DataSourceItem::ID_DATA_KEY).toString()
284 == productId) {
285 auto graph = zone->createGraph(variable);
286 graph->setAutoRangeOnVariableInitialization(false);
287
288 auto selectionZone
289 = graph->addSelectionZone(event->getName(), productRange);
290 emit catalogueEventWidget->selectionZoneAdded(event, productId,
291 selectionZone);
292 m_CustomGraphs << graph;
293
294 graph->setGraphRange(range, true);
295
296 // Removes the graph from the graph list if it is closed manually
297 QObject::connect(graph, &VisualizationGraphWidget::destroyed,
298 [this, graph]() { m_CustomGraphs.removeAll(graph); });
299
300 delete context; // removes the connection
301 }
302 },
303 Qt::QueuedConnection);
304
305 QMetaObject::invokeMethod(&sqpApp->dataSourceController(),
306 "requestVariableFromProductIdKey", Qt::QueuedConnection,
307 Q_ARG(QString, productId));
205 }
308 }
206 }
309 }
207
310
@@ -236,11 +339,12 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
236 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
339 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
237 ui->treeView->setDragEnabled(true);
340 ui->treeView->setDragEnabled(true);
238
341
342
239 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
343 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
240 if (checked) {
344 if (checked) {
241 ui->btnChart->setChecked(false);
345 ui->btnChart->setChecked(false);
242 impl->m_ZonesForTimeMode
346 impl->m_ZonesForTimeMode
243 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
347 = impl->selectZone(this, impl->m_ZonesForTimeMode, true, false,
244 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
348 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
245
349
246 impl->updateForTimeMode(ui->treeView);
350 impl->updateForTimeMode(ui->treeView);
@@ -250,12 +354,13 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
250 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
354 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
251 if (checked) {
355 if (checked) {
252 ui->btnTime->setChecked(false);
356 ui->btnTime->setChecked(false);
357
253 impl->m_ZoneForGraphMode
358 impl->m_ZoneForGraphMode
254 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
359 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false, true,
255 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
360 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
256 .value(0);
361 .value(0);
257
362
258 impl->updateForGraphMode(ui->treeView);
363 impl->updateForGraphMode(this);
259 }
364 }
260 });
365 });
261
366
@@ -266,16 +371,38 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
266
371
267 if (!events.isEmpty() && eventProducts.isEmpty()) {
372 if (!events.isEmpty() && eventProducts.isEmpty()) {
268
373
269 if (QMessageBox::warning(this, tr("Remove Event(s)"),
374 auto canRemoveEvent
270 tr("The selected event(s) will be completly removed "
375 = !this->isAllEventsDisplayed()
271 "from the repository!\nAre you sure you want to continue?"),
376 || (QMessageBox::warning(
272 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
377 this, tr("Remove Event(s)"),
273 == QMessageBox::Yes) {
378 tr("The selected event(s) will be permanently removed "
379 "from the repository!\nAre you sure you want to continue?"),
380 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
381 == QMessageBox::Yes);
274
382
383 if (canRemoveEvent) {
275 for (auto event : events) {
384 for (auto event : events) {
276 sqpApp->catalogueController().removeEvent(event);
385 if (this->isAllEventsDisplayed()) {
277 impl->removeEvent(event, ui->treeView);
386 sqpApp->catalogueController().removeEvent(event);
387 impl->removeEvent(event, ui->treeView);
388 }
389 else {
390 QVector<std::shared_ptr<DBCatalogue> > modifiedCatalogues;
391 for (auto catalogue : this->displayedCatalogues()) {
392 if (catalogue->removeEvent(event->getUniqId())) {
393 sqpApp->catalogueController().updateCatalogue(catalogue);
394 modifiedCatalogues << catalogue;
395 }
396 }
397 if (!modifiedCatalogues.empty()) {
398 emit eventCataloguesModified(modifiedCatalogues);
399 }
400 }
401 impl->m_Model->removeEvent(event);
278 }
402 }
403
404
405 emit this->eventsRemoved(events);
279 }
406 }
280 }
407 }
281 });
408 });
@@ -294,7 +421,7 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
294 impl->updateForTimeMode(ui->treeView);
421 impl->updateForTimeMode(ui->treeView);
295 }
422 }
296 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
423 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
297 impl->updateForGraphMode(ui->treeView);
424 impl->updateForGraphMode(this);
298 }
425 }
299
426
300 QVector<std::shared_ptr<DBEvent> > events;
427 QVector<std::shared_ptr<DBEvent> > events;
@@ -307,11 +434,13 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
307 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
434 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
308 QHeaderView::Stretch);
435 QHeaderView::Stretch);
309 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
436 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
310 QHeaderView::Fixed);
437 QHeaderView::ResizeToContents);
311 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
438 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
312 QHeaderView::Interactive);
439 QHeaderView::Interactive);
313 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
440 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TStart,
314 VALIDATION_COLUMN_SIZE);
441 QHeaderView::ResizeToContents);
442 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TEnd,
443 QHeaderView::ResizeToContents);
315 ui->treeView->header()->setSortIndicatorShown(true);
444 ui->treeView->header()->setSortIndicatorShown(true);
316
445
317 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
446 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
@@ -357,12 +486,20 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &even
357 setEventChanges(event, false);
486 setEventChanges(event, false);
358 },
487 },
359 [this, event]() {
488 [this, event]() {
360 sqpApp->catalogueController().discardEvent(event);
489 bool removed = false;
361 setEventChanges(event, false);
490 sqpApp->catalogueController().discardEvent(event, removed);
362 impl->m_Model->refreshEvent(event, true);
491 if (removed) {
492 impl->m_Model->removeEvent(event);
493 }
494 else {
495 setEventChanges(event, false);
496 impl->m_Model->refreshEvent(event, true);
497 }
363 emitSelection();
498 emitSelection();
364 });
499 });
365 ui->treeView->setIndexWidget(validationIndex, widget);
500 ui->treeView->setIndexWidget(validationIndex, widget);
501 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
502 QHeaderView::ResizeToContents);
366 }
503 }
367 }
504 }
368 else {
505 else {
@@ -383,7 +520,7 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogue
383
520
384 bool CatalogueEventsWidget::isAllEventsDisplayed() const
521 bool CatalogueEventsWidget::isAllEventsDisplayed() const
385 {
522 {
386 return impl->m_DisplayedCatalogues.isEmpty() && !impl->m_Model->events().isEmpty();
523 return impl->m_AllEventDisplayed;
387 }
524 }
388
525
389 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
526 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
@@ -391,10 +528,16 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &eve
391 return impl->m_Model->indexOf(event).isValid();
528 return impl->m_Model->indexOf(event).isValid();
392 }
529 }
393
530
531 void CatalogueEventsWidget::refreshEvent(const std::shared_ptr<DBEvent> &event)
532 {
533 impl->m_Model->refreshEvent(event, true);
534 }
535
394 void CatalogueEventsWidget::populateWithCatalogues(
536 void CatalogueEventsWidget::populateWithCatalogues(
395 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
537 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
396 {
538 {
397 impl->m_DisplayedCatalogues = catalogues;
539 impl->m_DisplayedCatalogues = catalogues;
540 impl->m_AllEventDisplayed = false;
398
541
399 QSet<QUuid> eventIds;
542 QSet<QUuid> eventIds;
400 QVector<std::shared_ptr<DBEvent> > events;
543 QVector<std::shared_ptr<DBEvent> > events;
@@ -415,6 +558,7 void CatalogueEventsWidget::populateWithCatalogues(
415 void CatalogueEventsWidget::populateWithAllEvents()
558 void CatalogueEventsWidget::populateWithAllEvents()
416 {
559 {
417 impl->m_DisplayedCatalogues.clear();
560 impl->m_DisplayedCatalogues.clear();
561 impl->m_AllEventDisplayed = true;
418
562
419 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
563 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
420
564
@@ -429,15 +573,16 void CatalogueEventsWidget::populateWithAllEvents()
429 void CatalogueEventsWidget::clear()
573 void CatalogueEventsWidget::clear()
430 {
574 {
431 impl->m_DisplayedCatalogues.clear();
575 impl->m_DisplayedCatalogues.clear();
576 impl->m_AllEventDisplayed = false;
432 impl->setEvents({}, this);
577 impl->setEvents({}, this);
433 }
578 }
434
579
435 void CatalogueEventsWidget::refresh()
580 void CatalogueEventsWidget::refresh()
436 {
581 {
437 if (impl->m_DisplayedCatalogues.isEmpty()) {
582 if (isAllEventsDisplayed()) {
438 populateWithAllEvents();
583 populateWithAllEvents();
439 }
584 }
440 else {
585 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
441 populateWithCatalogues(impl->m_DisplayedCatalogues);
586 populateWithCatalogues(impl->m_DisplayedCatalogues);
442 }
587 }
443 }
588 }
@@ -458,3 +603,15 void CatalogueEventsWidget::emitSelection()
458 emit selectionCleared();
603 emit selectionCleared();
459 }
604 }
460 }
605 }
606
607
608 void CatalogueEventsWidget::keyPressEvent(QKeyEvent *event)
609 {
610 switch (event->key()) {
611 case Qt::Key_Delete: {
612 ui->btnRemove->click();
613 }
614 default:
615 break;
616 }
617 }
@@ -4,13 +4,22
4 #include <Catalogue/CatalogueActionManager.h>
4 #include <Catalogue/CatalogueActionManager.h>
5 #include <Catalogue/CatalogueController.h>
5 #include <Catalogue/CatalogueController.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7 #include <Visualization/VisualizationGraphWidget.h>
8 #include <Visualization/VisualizationSelectionZoneItem.h>
7 #include <Visualization/VisualizationWidget.h>
9 #include <Visualization/VisualizationWidget.h>
8
10
9 #include <DBCatalogue.h>
11 #include <DBCatalogue.h>
10 #include <DBEvent.h>
12 #include <DBEvent.h>
13 #include <DBEventProduct.h>
14
15 #include <unordered_map>
11
16
12 struct CatalogueExplorer::CatalogueExplorerPrivate {
17 struct CatalogueExplorer::CatalogueExplorerPrivate {
13 CatalogueActionManager m_ActionManager;
18 CatalogueActionManager m_ActionManager;
19 std::unordered_map<std::shared_ptr<DBEvent>, QVector<VisualizationSelectionZoneItem *> >
20 m_SelectionZonesPerEvents;
21
22 QMetaObject::Connection m_Conn;
14
23
15 CatalogueExplorerPrivate(CatalogueExplorer *catalogueExplorer)
24 CatalogueExplorerPrivate(CatalogueExplorer *catalogueExplorer)
16 : m_ActionManager(catalogueExplorer)
25 : m_ActionManager(catalogueExplorer)
@@ -27,6 +36,7 CatalogueExplorer::CatalogueExplorer(QWidget *parent)
27
36
28 impl->m_ActionManager.installSelectionZoneActions();
37 impl->m_ActionManager.installSelectionZoneActions();
29
38
39 // Updates events and inspector when something is selected in the catalogue widget
30 connect(ui->catalogues, &CatalogueSideBarWidget::catalogueSelected, [this](auto catalogues) {
40 connect(ui->catalogues, &CatalogueSideBarWidget::catalogueSelected, [this](auto catalogues) {
31 if (catalogues.count() == 1) {
41 if (catalogues.count() == 1) {
32 ui->inspector->setCatalogue(catalogues.first());
42 ui->inspector->setCatalogue(catalogues.first());
@@ -66,6 +76,13 CatalogueExplorer::CatalogueExplorer(QWidget *parent)
66 ui->events->clear();
76 ui->events->clear();
67 });
77 });
68
78
79 connect(ui->catalogues, &CatalogueSideBarWidget::catalogueSaved, ui->events,
80 &CatalogueEventsWidget::refresh);
81
82 connect(ui->catalogues, &CatalogueSideBarWidget::catalogueListChanged,
83 [this]() { impl->m_ActionManager.refreshCreateInCatalogueAction(); });
84
85 // Updates the inspectot when something is selected in the events
69 connect(ui->events, &CatalogueEventsWidget::eventsSelected, [this](auto events) {
86 connect(ui->events, &CatalogueEventsWidget::eventsSelected, [this](auto events) {
70 if (events.count() == 1) {
87 if (events.count() == 1) {
71 ui->inspector->setEvent(events.first());
88 ui->inspector->setEvent(events.first());
@@ -88,9 +105,31 CatalogueExplorer::CatalogueExplorer(QWidget *parent)
88 connect(ui->events, &CatalogueEventsWidget::selectionCleared,
105 connect(ui->events, &CatalogueEventsWidget::selectionCleared,
89 [this]() { ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty); });
106 [this]() { ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty); });
90
107
108 // Manage Selection Zones associated to events
109 connect(ui->events, &CatalogueEventsWidget::selectionZoneAdded,
110 [this](auto event, auto productId, auto zone) {
111 this->addSelectionZoneItem(event, productId, zone);
112 });
113
114 connect(ui->events, &CatalogueEventsWidget::eventsRemoved, [this](auto events) {
115 for (auto event : events) {
116 auto associatedSelectionZonesIt = impl->m_SelectionZonesPerEvents.find(event);
117 if (associatedSelectionZonesIt != impl->m_SelectionZonesPerEvents.cend()) {
118 for (auto selectionZone : associatedSelectionZonesIt->second) {
119 auto parentGraph = selectionZone->parentGraphWidget();
120 parentGraph->removeSelectionZone(selectionZone);
121 }
122
123 impl->m_SelectionZonesPerEvents.erase(event);
124 }
125 }
126 });
127
128 // Updates changes from the inspector
91 connect(ui->inspector, &CatalogueInspectorWidget::catalogueUpdated, [this](auto catalogue) {
129 connect(ui->inspector, &CatalogueInspectorWidget::catalogueUpdated, [this](auto catalogue) {
92 sqpApp->catalogueController().updateCatalogue(catalogue);
130 sqpApp->catalogueController().updateCatalogue(catalogue);
93 ui->catalogues->setCatalogueChanges(catalogue, true);
131 ui->catalogues->setCatalogueChanges(catalogue, true);
132 impl->m_ActionManager.refreshCreateInCatalogueAction();
94 });
133 });
95
134
96 connect(ui->inspector, &CatalogueInspectorWidget::eventUpdated, [this](auto event) {
135 connect(ui->inspector, &CatalogueInspectorWidget::eventUpdated, [this](auto event) {
@@ -103,10 +142,18 CatalogueExplorer::CatalogueExplorer(QWidget *parent)
103 sqpApp->catalogueController().updateEventProduct(eventProduct);
142 sqpApp->catalogueController().updateEventProduct(eventProduct);
104 ui->events->setEventChanges(event, true);
143 ui->events->setEventChanges(event, true);
105 });
144 });
145
146 connect(ui->events, &CatalogueEventsWidget::eventCataloguesModified,
147 [this](const QVector<std::shared_ptr<DBCatalogue> > &catalogues) {
148 for (auto catalogue : catalogues) {
149 ui->catalogues->setCatalogueChanges(catalogue, true);
150 }
151 });
106 }
152 }
107
153
108 CatalogueExplorer::~CatalogueExplorer()
154 CatalogueExplorer::~CatalogueExplorer()
109 {
155 {
156 disconnect(impl->m_Conn);
110 delete ui;
157 delete ui;
111 }
158 }
112
159
@@ -124,3 +171,37 CatalogueSideBarWidget &CatalogueExplorer::sideBarWidget() const
124 {
171 {
125 return *ui->catalogues;
172 return *ui->catalogues;
126 }
173 }
174
175 void CatalogueExplorer::clearSelectionZones()
176 {
177 impl->m_SelectionZonesPerEvents.clear();
178 }
179
180 void CatalogueExplorer::addSelectionZoneItem(const std::shared_ptr<DBEvent> &event,
181 const QString &productId,
182 VisualizationSelectionZoneItem *selectionZone)
183 {
184 impl->m_SelectionZonesPerEvents[event] << selectionZone;
185 connect(selectionZone, &VisualizationSelectionZoneItem::rangeEdited,
186 [event, productId, this](auto range) {
187 auto productList = event->getEventProducts();
188 for (auto &product : productList) {
189 if (product.getProductId() == productId) {
190 product.setTStart(range.m_TStart);
191 product.setTEnd(range.m_TEnd);
192 }
193 }
194 event->setEventProducts(productList);
195 sqpApp->catalogueController().updateEvent(event);
196 ui->events->refreshEvent(event);
197 ui->events->setEventChanges(event, true);
198 ui->inspector->refresh();
199 });
200
201 impl->m_Conn = connect(selectionZone, &VisualizationSelectionZoneItem::destroyed,
202 [event, selectionZone, this]() {
203 if (!impl->m_SelectionZonesPerEvents.empty()) {
204 impl->m_SelectionZonesPerEvents[event].removeAll(selectionZone);
205 }
206 });
207 }
@@ -3,7 +3,6
3 #include <QBoxLayout>
3 #include <QBoxLayout>
4 #include <QToolButton>
4 #include <QToolButton>
5
5
6 const auto VALIDATION_BUTTON_ICON_SIZE = 12;
7
6
8 QWidget *CatalogueExplorerHelper::buildValidationWidget(QWidget *parent, std::function<void()> save,
7 QWidget *CatalogueExplorerHelper::buildValidationWidget(QWidget *parent, std::function<void()> save,
9 std::function<void()> discard)
8 std::function<void()> discard)
@@ -11,22 +10,21 QWidget *CatalogueExplorerHelper::buildValidationWidget(QWidget *parent, std::fu
11 auto widget = new QWidget{parent};
10 auto widget = new QWidget{parent};
12
11
13 auto layout = new QHBoxLayout{widget};
12 auto layout = new QHBoxLayout{widget};
14 layout->setContentsMargins(0, 0, 0, 0);
15 layout->setSpacing(0);
16
13
17 auto btnValid = new QToolButton{widget};
14 auto btnValid = new QToolButton{widget};
18 btnValid->setIcon(QIcon{":/icones/save"});
15 btnValid->setIcon(QIcon{":/icones/save"});
19 btnValid->setIconSize(QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
20 btnValid->setAutoRaise(true);
16 btnValid->setAutoRaise(true);
21 QObject::connect(btnValid, &QToolButton::clicked, save);
17 QObject::connect(btnValid, &QToolButton::clicked, save);
22 layout->addWidget(btnValid);
18 layout->addWidget(btnValid);
23
19
24 auto btnDiscard = new QToolButton{widget};
20 auto btnDiscard = new QToolButton{widget};
25 btnDiscard->setIcon(QIcon{":/icones/discard"});
21 btnDiscard->setIcon(QIcon{":/icones/discard"});
26 btnDiscard->setIconSize(QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
27 btnDiscard->setAutoRaise(true);
22 btnDiscard->setAutoRaise(true);
28 QObject::connect(btnDiscard, &QToolButton::clicked, discard);
23 QObject::connect(btnDiscard, &QToolButton::clicked, discard);
29 layout->addWidget(btnDiscard);
24 layout->addWidget(btnDiscard);
30
25
26 layout->setContentsMargins(0, 0, 0, 0);
27 layout->setSpacing(0);
28
31 return widget;
29 return widget;
32 }
30 }
@@ -28,6 +28,9 CatalogueInspectorWidget::CatalogueInspectorWidget(QWidget *parent)
28
28
29 impl->connectCatalogueUpdateSignals(this, ui);
29 impl->connectCatalogueUpdateSignals(this, ui);
30 impl->connectEventUpdateSignals(this, ui);
30 impl->connectEventUpdateSignals(this, ui);
31
32 ui->dateTimeEventTStart->setDisplayFormat(DATETIME_FORMAT);
33 ui->dateTimeEventTEnd->setDisplayFormat(DATETIME_FORMAT);
31 }
34 }
32
35
33 CatalogueInspectorWidget::~CatalogueInspectorWidget()
36 CatalogueInspectorWidget::~CatalogueInspectorWidget()
@@ -64,7 +67,7 void CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate::connectEventUpda
64 });
67 });
65
68
66 connect(ui->leEventTags, &QLineEdit::editingFinished, [ui, inspector, this]() {
69 connect(ui->leEventTags, &QLineEdit::editingFinished, [ui, inspector, this]() {
67 auto tags = ui->leEventTags->text().split(QRegExp("\\s+"));
70 auto tags = ui->leEventTags->text().split(QRegExp("\\s+"), QString::SkipEmptyParts);
68 std::list<QString> tagNames;
71 std::list<QString> tagNames;
69 for (auto tag : tags) {
72 for (auto tag : tags) {
70 tagNames.push_back(tag);
73 tagNames.push_back(tag);
@@ -148,8 +151,14 void CatalogueInspectorWidget::setEvent(const std::shared_ptr<DBEvent> &event)
148 ui->leEventName->setEnabled(true);
151 ui->leEventName->setEnabled(true);
149 ui->leEventName->setText(event->getName());
152 ui->leEventName->setText(event->getName());
150 ui->leEventProduct->setEnabled(false);
153 ui->leEventProduct->setEnabled(false);
151 ui->leEventProduct->setText(
154
152 QString::number(event->getEventProducts().size()).append(" product(s)"));
155 auto eventProducts = event->getEventProducts();
156 QStringList eventProductList;
157 for (auto evtProduct : eventProducts) {
158 eventProductList << evtProduct.getProductId();
159 }
160
161 ui->leEventProduct->setText(eventProductList.join(";"));
153
162
154 QString tagList;
163 QString tagList;
155 auto tags = event->getTagsNames();
164 auto tags = event->getTagsNames();
@@ -209,3 +218,19 void CatalogueInspectorWidget::setCatalogue(const std::shared_ptr<DBCatalogue> &
209
218
210 blockSignals(false);
219 blockSignals(false);
211 }
220 }
221
222 void CatalogueInspectorWidget::refresh()
223 {
224 switch (static_cast<Page>(ui->stackedWidget->currentIndex())) {
225 case Page::CatalogueProperties:
226 setCatalogue(impl->m_DisplayedCatalogue);
227 break;
228 case Page::EventProperties: {
229 auto isEventShowed = ui->leEventName->isEnabled();
230 setEvent(impl->m_DisplayedEvent);
231 if (!isEventShowed && impl->m_DisplayedEvent) {
232 setEventProduct(impl->m_DisplayedEvent, impl->m_DisplayedEventProduct);
233 }
234 }
235 }
236 }
@@ -8,10 +8,14
8 #include <Catalogue/CatalogueTreeItems/CatalogueTreeItem.h>
8 #include <Catalogue/CatalogueTreeItems/CatalogueTreeItem.h>
9 #include <Catalogue/CatalogueTreeModel.h>
9 #include <Catalogue/CatalogueTreeModel.h>
10 #include <CatalogueDao.h>
10 #include <CatalogueDao.h>
11 #include <Common/MimeTypesDef.h>
11 #include <ComparaisonPredicate.h>
12 #include <ComparaisonPredicate.h>
12 #include <DBCatalogue.h>
13 #include <DBCatalogue.h>
13
14
15 #include <QKeyEvent>
14 #include <QMenu>
16 #include <QMenu>
17 #include <QMessageBox>
18 #include <QMimeData>
15
19
16 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
20 Q_LOGGING_CATEGORY(LOG_CatalogueSideBarWidget, "CatalogueSideBarWidget")
17
21
@@ -21,6 +25,8 constexpr auto TRASH_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 2;
21 constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3;
25 constexpr auto CATALOGUE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 3;
22 constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4;
26 constexpr auto DATABASE_ITEM_TYPE = CatalogueAbstractTreeItem::DEFAULT_TYPE + 4;
23
27
28 const auto DEFAULT_CATALOGUE_NAME = QObject::tr("Catalogue");
29
24
30
25 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
31 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
26
32
@@ -29,11 +35,11 struct CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate {
29 void configureTreeWidget(QTreeView *treeView);
35 void configureTreeWidget(QTreeView *treeView);
30 QModelIndex addDatabaseItem(const QString &name);
36 QModelIndex addDatabaseItem(const QString &name);
31 CatalogueAbstractTreeItem *getDatabaseItem(const QString &name);
37 CatalogueAbstractTreeItem *getDatabaseItem(const QString &name);
32 void addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
38 CatalogueAbstractTreeItem *addCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue,
33 const QModelIndex &databaseIndex);
39 const QModelIndex &databaseIndex);
34
40
35 CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
41 CatalogueTreeItem *getCatalogueItem(const std::shared_ptr<DBCatalogue> &catalogue) const;
36 void setHasChanges(bool value, const QModelIndex &index, QTreeView *treeView);
42 void setHasChanges(bool value, const QModelIndex &index, CatalogueSideBarWidget *sideBarWidget);
37 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
43 bool hasChanges(const QModelIndex &index, QTreeView *treeView);
38
44
39 int selectionType(QTreeView *treeView) const
45 int selectionType(QTreeView *treeView) const
@@ -104,44 +110,93 CatalogueSideBarWidget::CatalogueSideBarWidget(QWidget *parent)
104 ui->treeView->setModel(impl->m_TreeModel);
110 ui->treeView->setModel(impl->m_TreeModel);
105
111
106 impl->configureTreeWidget(ui->treeView);
112 impl->configureTreeWidget(ui->treeView);
113 emit catalogueListChanged();
107
114
108 ui->treeView->header()->setStretchLastSection(false);
115 ui->treeView->header()->setStretchLastSection(false);
109 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
116 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
110 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
117 ui->treeView->header()->setSectionResizeMode((int)CatalogueTreeModel::Column::Name,
111
118 QHeaderView::Stretch);
112 auto emitSelection = [this]() {
119
113
120 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueSideBarWidget::emitSelection);
114 auto selectionType = impl->selectionType(ui->treeView);
121 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this,
115
122 &CatalogueSideBarWidget::emitSelection);
116 switch (selectionType) {
123
117 case CATALOGUE_ITEM_TYPE:
124
118 emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView));
125 connect(ui->btnAdd, &QToolButton::clicked, [this]() {
119 break;
126 auto catalogue = std::make_shared<DBCatalogue>();
120 case DATABASE_ITEM_TYPE:
127 catalogue->setName(DEFAULT_CATALOGUE_NAME);
121 emit this->databaseSelected(impl->selectedRepositories(ui->treeView));
128 sqpApp->catalogueController().addCatalogue(catalogue);
122 break;
129 auto item = this->addCatalogue(catalogue, REPOSITORY_DEFAULT);
123 case ALL_EVENT_ITEM_TYPE:
130 this->setCatalogueChanges(catalogue, true);
124 emit this->allEventsSelected();
131 ui->treeView->edit(impl->m_TreeModel->indexOf(item));
125 break;
132
126 case TRASH_ITEM_TYPE:
133 });
127 emit this->trashSelected();
134
128 break;
135
129 default:
136 connect(impl->m_TreeModel, &CatalogueTreeModel::itemDropped,
130 emit this->selectionCleared();
137 [this](auto index, auto mimeData, auto action) {
131 break;
138 auto item = impl->m_TreeModel->item(index);
139
140 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
141 auto catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
142 this->setCatalogueChanges(catalogue, true);
143 }
144
145 if (action == Qt::MoveAction) {
146 /// Display a save button on source catalogues
147 auto sourceCatalogues = sqpApp->catalogueController().cataloguesForMimeData(
148 mimeData->data(MIME_TYPE_SOURCE_CATALOGUE_LIST));
149 for (auto catalogue : sourceCatalogues) {
150 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
151 catalogueItem->replaceCatalogue(catalogue);
152 this->setCatalogueChanges(catalogue, true);
153 }
154 }
155
156 this->emitSelection();
157 }
158 });
159
160 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
161 QVector<QPair<std::shared_ptr<DBCatalogue>, CatalogueAbstractTreeItem *> >
162 cataloguesToItems;
163 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
164
165 for (auto index : selectedIndexes) {
166 auto item = impl->m_TreeModel->item(index);
167 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
168 auto catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
169 cataloguesToItems << qMakePair(catalogue, item);
170 }
132 }
171 }
133 };
134
172
135 connect(ui->treeView, &QTreeView::clicked, emitSelection);
173 if (!cataloguesToItems.isEmpty()) {
136 connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, emitSelection);
174
137 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [emitSelection, this](auto index) {
175 if (QMessageBox::warning(this, tr("Remove Catalogue(s)"),
176 tr("The selected catalogues(s) will be completly removed "
177 "from the repository!\nAre you sure you want to continue?"),
178 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
179 == QMessageBox::Yes) {
180
181 for (auto catalogueToItem : cataloguesToItems) {
182 sqpApp->catalogueController().removeCatalogue(catalogueToItem.first);
183 impl->m_TreeModel->removeChildItem(
184 catalogueToItem.second,
185 impl->m_TreeModel->indexOf(catalogueToItem.second->parent()));
186 }
187 emitSelection();
188 emit catalogueListChanged();
189 }
190 }
191 });
192
193 connect(impl->m_TreeModel, &CatalogueTreeModel::itemRenamed, [this](auto index) {
138 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
194 auto selectedIndexes = ui->treeView->selectionModel()->selectedRows();
139 if (selectedIndexes.contains(index)) {
195 if (selectedIndexes.contains(index)) {
140 emitSelection();
196 this->emitSelection();
141 }
197 }
142
198 impl->setHasChanges(true, index, this);
143 auto item = impl->m_TreeModel->item(index);
199 emit this->catalogueListChanged();
144 impl->setHasChanges(true, index, ui->treeView);
145 });
200 });
146
201
147 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
202 ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -154,11 +209,17 CatalogueSideBarWidget::~CatalogueSideBarWidget()
154 delete ui;
209 delete ui;
155 }
210 }
156
211
157 void CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
212 CatalogueAbstractTreeItem *
158 const QString &repository)
213 CatalogueSideBarWidget::addCatalogue(const std::shared_ptr<DBCatalogue> &catalogue,
214 const QString &repository)
159 {
215 {
160 auto repositoryItem = impl->getDatabaseItem(repository);
216 auto repositoryItem = impl->getDatabaseItem(repository);
161 impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem));
217 auto catalogueItem
218 = impl->addCatalogueItem(catalogue, impl->m_TreeModel->indexOf(repositoryItem));
219
220 emit catalogueListChanged();
221
222 return catalogueItem;
162 }
223 }
163
224
164 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
225 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalogue> &catalogue,
@@ -166,7 +227,7 void CatalogueSideBarWidget::setCatalogueChanges(const std::shared_ptr<DBCatalog
166 {
227 {
167 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
228 if (auto catalogueItem = impl->getCatalogueItem(catalogue)) {
168 auto index = impl->m_TreeModel->indexOf(catalogueItem);
229 auto index = impl->m_TreeModel->indexOf(catalogueItem);
169 impl->setHasChanges(hasChanges, index, ui->treeView);
230 impl->setHasChanges(hasChanges, index, this);
170 // catalogueItem->refresh();
231 // catalogueItem->refresh();
171 }
232 }
172 }
233 }
@@ -189,6 +250,29 CatalogueSideBarWidget::getCatalogues(const QString &repository) const
189 return result;
250 return result;
190 }
251 }
191
252
253 void CatalogueSideBarWidget::emitSelection()
254 {
255 auto selectionType = impl->selectionType(ui->treeView);
256
257 switch (selectionType) {
258 case CATALOGUE_ITEM_TYPE:
259 emit this->catalogueSelected(impl->selectedCatalogues(ui->treeView));
260 break;
261 case DATABASE_ITEM_TYPE:
262 emit this->databaseSelected(impl->selectedRepositories(ui->treeView));
263 break;
264 case ALL_EVENT_ITEM_TYPE:
265 emit this->allEventsSelected();
266 break;
267 case TRASH_ITEM_TYPE:
268 emit this->trashSelected();
269 break;
270 default:
271 emit this->selectionCleared();
272 break;
273 }
274 }
275
192 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
276 void CatalogueSideBarWidget::onContextMenuRequested(const QPoint &pos)
193 {
277 {
194 QMenu menu{this};
278 QMenu menu{this};
@@ -274,12 +358,14 CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getDatabaseItem(const QSt
274 return nullptr;
358 return nullptr;
275 }
359 }
276
360
277 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
361 CatalogueAbstractTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::addCatalogueItem(
278 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
362 const std::shared_ptr<DBCatalogue> &catalogue, const QModelIndex &databaseIndex)
279 {
363 {
280 auto catalogueItem
364 auto catalogueItem
281 = new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE};
365 = new CatalogueTreeItem{catalogue, QIcon{":/icones/catalogue.png"}, CATALOGUE_ITEM_TYPE};
282 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
366 m_TreeModel->addChildItem(catalogueItem, databaseIndex);
367
368 return catalogueItem;
283 }
369 }
284
370
285 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
371 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCatalogueItem(
@@ -290,7 +376,7 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCat
290 for (auto childItem : item->children()) {
376 for (auto childItem : item->children()) {
291 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
377 if (childItem->type() == CATALOGUE_ITEM_TYPE) {
292 auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem);
378 auto catalogueItem = static_cast<CatalogueTreeItem *>(childItem);
293 if (catalogueItem->catalogue() == catalogue) {
379 if (catalogueItem->catalogue()->getUniqId() == catalogue->getUniqId()) {
294 return catalogueItem;
380 return catalogueItem;
295 }
381 }
296 }
382 }
@@ -307,25 +393,51 CatalogueTreeItem *CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::getCat
307 return nullptr;
393 return nullptr;
308 }
394 }
309
395
310 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(bool value,
396 void CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::setHasChanges(
311 const QModelIndex &index,
397 bool value, const QModelIndex &index, CatalogueSideBarWidget *sideBarWidget)
312 QTreeView *treeView)
313 {
398 {
399 std::shared_ptr<DBCatalogue> catalogue = nullptr;
400 auto item = m_TreeModel->item(index);
401 if (item && item->type() == CATALOGUE_ITEM_TYPE) {
402 catalogue = static_cast<CatalogueTreeItem *>(item)->catalogue();
403 }
404
314 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
405 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
315 if (value) {
406 if (value) {
316 if (!hasChanges(validationIndex, treeView)) {
407 if (!hasChanges(validationIndex, sideBarWidget->ui->treeView)) {
317 auto widget = CatalogueExplorerHelper::buildValidationWidget(
408 auto widget = CatalogueExplorerHelper::buildValidationWidget(
318 treeView, [this, validationIndex,
409 sideBarWidget->ui->treeView,
319 treeView]() { setHasChanges(false, validationIndex, treeView); },
410 [this, validationIndex, sideBarWidget, catalogue]() {
320 [this, validationIndex, treeView]() {
411 if (catalogue) {
321 setHasChanges(false, validationIndex, treeView);
412 sqpApp->catalogueController().saveCatalogue(catalogue);
413 emit sideBarWidget->catalogueSaved(catalogue);
414 }
415 setHasChanges(false, validationIndex, sideBarWidget);
416 },
417 [this, validationIndex, sideBarWidget, catalogue, item]() {
418 if (catalogue) {
419 bool removed;
420 sqpApp->catalogueController().discardCatalogue(catalogue, removed);
421
422 if (removed) {
423 m_TreeModel->removeChildItem(item,
424 m_TreeModel->indexOf(item->parent()));
425 }
426 else {
427 m_TreeModel->refresh(m_TreeModel->indexOf(item));
428 setHasChanges(false, validationIndex, sideBarWidget);
429 }
430 sideBarWidget->emitSelection();
431 }
322 });
432 });
323 treeView->setIndexWidget(validationIndex, widget);
433 sideBarWidget->ui->treeView->setIndexWidget(validationIndex, widget);
434 sideBarWidget->ui->treeView->header()->resizeSection(
435 (int)CatalogueTreeModel::Column::Validation, QHeaderView::ResizeToContents);
324 }
436 }
325 }
437 }
326 else {
438 else {
327 // Note: the widget is destroyed
439 // Note: the widget is destroyed
328 treeView->setIndexWidget(validationIndex, nullptr);
440 sideBarWidget->ui->treeView->setIndexWidget(validationIndex, nullptr);
329 }
441 }
330 }
442 }
331
443
@@ -335,3 +447,15 bool CatalogueSideBarWidget::CatalogueSideBarWidgetPrivate::hasChanges(const QMo
335 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
447 auto validationIndex = index.sibling(index.row(), (int)CatalogueTreeModel::Column::Validation);
336 return treeView->indexWidget(validationIndex) != nullptr;
448 return treeView->indexWidget(validationIndex) != nullptr;
337 }
449 }
450
451
452 void CatalogueSideBarWidget::keyPressEvent(QKeyEvent *event)
453 {
454 switch (event->key()) {
455 case Qt::Key_Delete: {
456 ui->btnRemove->click();
457 }
458 default:
459 break;
460 }
461 }
@@ -24,6 +24,12 void CatalogueAbstractTreeItem::addChild(CatalogueAbstractTreeItem *child)
24 child->impl->m_Parent = this;
24 child->impl->m_Parent = this;
25 }
25 }
26
26
27 void CatalogueAbstractTreeItem::removeChild(CatalogueAbstractTreeItem *child)
28 {
29 impl->m_Children.removeAll(child);
30 delete child;
31 }
32
27 QVector<CatalogueAbstractTreeItem *> CatalogueAbstractTreeItem::children() const
33 QVector<CatalogueAbstractTreeItem *> CatalogueAbstractTreeItem::children() const
28 {
34 {
29 return impl->m_Children;
35 return impl->m_Children;
@@ -76,20 +76,56 Qt::ItemFlags CatalogueTreeItem::flags(int column) const
76
76
77 bool CatalogueTreeItem::canDropMimeData(const QMimeData *data, Qt::DropAction action)
77 bool CatalogueTreeItem::canDropMimeData(const QMimeData *data, Qt::DropAction action)
78 {
78 {
79 return data->hasFormat(MIME_TYPE_EVENT_LIST);
79 // Check that the event is not dropped on the same catalogue
80 auto sourceCatalogues = sqpApp->catalogueController().cataloguesForMimeData(
81 data->data(MIME_TYPE_SOURCE_CATALOGUE_LIST));
82 for (auto catalogue : sourceCatalogues) {
83 if (catalogue->getUniqId() == impl->m_Catalogue->getUniqId()) {
84 return false;
85 }
86 }
87
88 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
89 auto canDrop = data->hasFormat(MIME_TYPE_EVENT_LIST);
90
91 for (auto event : events) {
92 canDrop &= (event->getRepository() == impl->m_Catalogue->getRepository());
93 }
94
95 return canDrop;
80 }
96 }
81
97
82 bool CatalogueTreeItem::dropMimeData(const QMimeData *data, Qt::DropAction action)
98 bool CatalogueTreeItem::dropMimeData(const QMimeData *data, Qt::DropAction action)
83 {
99 {
84 Q_ASSERT(canDropMimeData(data, action));
100 Q_ASSERT(canDropMimeData(data, action));
101 // Warning: Check that the events aren't already in the catalogue
102 // No need to check check for the repository: inter-repository drop is forbidden in
103 // canDropMimeData
85
104
86 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
105 auto events = sqpApp->catalogueController().eventsForMimeData(data->data(MIME_TYPE_EVENT_LIST));
87 // impl->m_Catalogue->addEvents(events); TODO: move events in the new catalogue
106 auto sourceCatalogues = sqpApp->catalogueController().cataloguesForMimeData(
88 // Warning: Check that the events aren't already in the catalogue
107 data->data(MIME_TYPE_SOURCE_CATALOGUE_LIST));
89 // Also check for the repository !!!
108
109 for (auto event : events) {
110
111 if (action == Qt::MoveAction) {
112 for (auto catalogue : sourceCatalogues) {
113 catalogue->removeEvent(event->getUniqId());
114 sqpApp->catalogueController().updateCatalogue(catalogue);
115 }
116 }
117
118 impl->m_Catalogue->addEvent(event->getUniqId());
119 sqpApp->catalogueController().updateCatalogue(impl->m_Catalogue);
120 }
90 }
121 }
91
122
92 std::shared_ptr<DBCatalogue> CatalogueTreeItem::catalogue() const
123 std::shared_ptr<DBCatalogue> CatalogueTreeItem::catalogue() const
93 {
124 {
94 return impl->m_Catalogue;
125 return impl->m_Catalogue;
95 }
126 }
127
128 void CatalogueTreeItem::replaceCatalogue(const std::shared_ptr<DBCatalogue> &catalogue)
129 {
130 impl->m_Catalogue = catalogue;
131 }
@@ -46,6 +46,23 void CatalogueTreeModel::addChildItem(CatalogueAbstractTreeItem *child,
46 emit dataChanged(parentIndex, parentIndex);
46 emit dataChanged(parentIndex, parentIndex);
47 }
47 }
48
48
49 void CatalogueTreeModel::removeChildItem(CatalogueAbstractTreeItem *child,
50 const QModelIndex &parentIndex)
51 {
52 auto parentItem = item(parentIndex);
53 int i = parentItem->children().indexOf(child);
54 beginRemoveRows(parentIndex, i, i);
55 parentItem->removeChild(child);
56 endRemoveRows();
57
58 emit dataChanged(parentIndex, parentIndex);
59 }
60
61 void CatalogueTreeModel::refresh(const QModelIndex &index)
62 {
63 emit dataChanged(index, index);
64 }
65
49 CatalogueAbstractTreeItem *CatalogueTreeModel::item(const QModelIndex &index) const
66 CatalogueAbstractTreeItem *CatalogueTreeModel::item(const QModelIndex &index) const
50 {
67 {
51 return static_cast<CatalogueAbstractTreeItem *>(index.internalPointer());
68 return static_cast<CatalogueAbstractTreeItem *>(index.internalPointer());
@@ -161,6 +178,7 bool CatalogueTreeModel::setData(const QModelIndex &index, const QVariant &value
161
178
162 return false;
179 return false;
163 }
180 }
181
164 bool CatalogueTreeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
182 bool CatalogueTreeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
165 int column, const QModelIndex &parent) const
183 int column, const QModelIndex &parent) const
166 {
184 {
@@ -183,7 +201,7 bool CatalogueTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction acti
183 if (draggedItem) {
201 if (draggedItem) {
184 result = draggedItem->dropMimeData(data, action);
202 result = draggedItem->dropMimeData(data, action);
185 if (result) {
203 if (result) {
186 emit itemDropped(draggedIndex);
204 emit itemDropped(draggedIndex, data, action);
187 }
205 }
188 }
206 }
189
207
@@ -197,5 +215,5 Qt::DropActions CatalogueTreeModel::supportedDropActions() const
197
215
198 QStringList CatalogueTreeModel::mimeTypes() const
216 QStringList CatalogueTreeModel::mimeTypes() const
199 {
217 {
200 return {MIME_TYPE_EVENT_LIST};
218 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_SOURCE_CATALOGUE_LIST};
201 }
219 }
@@ -7,6 +7,7
7 #include "Visualization/VisualizationWidget.h"
7 #include "Visualization/VisualizationWidget.h"
8 #include "Visualization/operations/FindVariableOperation.h"
8 #include "Visualization/operations/FindVariableOperation.h"
9
9
10 #include "DataSource/DataSourceController.h"
10 #include "Variable/Variable.h"
11 #include "Variable/Variable.h"
11 #include "Variable/VariableController.h"
12 #include "Variable/VariableController.h"
12
13
@@ -286,11 +287,22 bool DragDropGuiController::checkMimeDataForVisualization(
286 // result = false: cannot drop multiple variables in the visualisation
287 // result = false: cannot drop multiple variables in the visualisation
287 }
288 }
288 }
289 }
290 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
291 auto productDataList = sqpApp->dataSourceController().productsDataForMimeData(
292 mimeData->data(MIME_TYPE_PRODUCT_LIST));
293 if (productDataList.count() == 1) {
294 result = true;
295 }
296 else {
297 // result = false: cannot drop multiple products in the visualisation
298 }
299 }
289 else {
300 else {
290 // Other MIME data
301 // Other MIME data
291 // no special rules, accepted by default
302 // no special rules, accepted by default
292 result = true;
303 result = true;
293 }
304 }
294
305
306
295 return result;
307 return result;
296 }
308 }
@@ -109,6 +109,8 SqpApplication::SqpApplication(int &argc, char **argv)
109 {
109 {
110 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
110 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
111
111
112 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
113
112 connect(&impl->m_DataSourceControllerThread, &QThread::started,
114 connect(&impl->m_DataSourceControllerThread, &QThread::started,
113 impl->m_DataSourceController.get(), &DataSourceController::initialize);
115 impl->m_DataSourceController.get(), &DataSourceController::initialize);
114 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
116 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
@@ -4,6 +4,8
4 #include <Data/SpectrogramSeries.h>
4 #include <Data/SpectrogramSeries.h>
5 #include <Data/VectorSeries.h>
5 #include <Data/VectorSeries.h>
6
6
7 #include <Variable/Variable.h>
8
7 #include <Visualization/SqpColorScale.h>
9 #include <Visualization/SqpColorScale.h>
8 #include <Visualization/qcustomplot.h>
10 #include <Visualization/qcustomplot.h>
9
11
@@ -11,8 +13,6 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
11
13
12 namespace {
14 namespace {
13
15
14 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
15
16 /// Format for datetimes on a axis
16 /// Format for datetimes on a axis
17 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
17 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
18
18
@@ -68,11 +68,17 void setAxisProperties(QCPAxis &axis, const Unit &unit,
68 */
68 */
69 template <typename T, typename Enabled = void>
69 template <typename T, typename Enabled = void>
70 struct AxisSetter {
70 struct AxisSetter {
71 static void setProperties(T &, QCustomPlot &, SqpColorScale &)
71 static void setProperties(QCustomPlot &, SqpColorScale &)
72 {
72 {
73 // Default implementation does nothing
73 // Default implementation does nothing
74 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
74 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
75 }
75 }
76
77 static void setUnits(T &, QCustomPlot &, SqpColorScale &)
78 {
79 // Default implementation does nothing
80 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis units: unmanaged type of data";
81 }
76 };
82 };
77
83
78 /**
84 /**
@@ -83,7 +89,12 struct AxisSetter {
83 template <typename T>
89 template <typename T>
84 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
90 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
85 or std::is_base_of<VectorSeries, T>::value> > {
91 or std::is_base_of<VectorSeries, T>::value> > {
86 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &)
92 static void setProperties(QCustomPlot &, SqpColorScale &)
93 {
94 // Nothing to do
95 }
96
97 static void setUnits(T &dataSeries, QCustomPlot &plot, SqpColorScale &)
87 {
98 {
88 dataSeries.lockRead();
99 dataSeries.lockRead();
89 auto xAxisUnit = dataSeries.xAxisUnit();
100 auto xAxisUnit = dataSeries.xAxisUnit();
@@ -101,17 +112,8 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>:
101 */
112 */
102 template <typename T>
113 template <typename T>
103 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
114 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
104 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &colorScale)
115 static void setProperties(QCustomPlot &plot, SqpColorScale &colorScale)
105 {
116 {
106 dataSeries.lockRead();
107 auto xAxisUnit = dataSeries.xAxisUnit();
108 auto yAxisUnit = dataSeries.yAxisUnit();
109 auto valuesUnit = dataSeries.valuesUnit();
110 dataSeries.unlock();
111
112 setAxisProperties(*plot.xAxis, xAxisUnit);
113 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
114
115 // Displays color scale in plot
117 // Displays color scale in plot
116 plot.plotLayout()->insertRow(0);
118 plot.plotLayout()->insertRow(0);
117 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
119 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
@@ -125,9 +127,21 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries
125 }
127 }
126
128
127 // Set color scale properties
129 // Set color scale properties
128 setAxisProperties(*colorScale.m_Scale->axis(), valuesUnit, QCPAxis::stLogarithmic);
129 colorScale.m_AutomaticThreshold = true;
130 colorScale.m_AutomaticThreshold = true;
130 }
131 }
132
133 static void setUnits(T &dataSeries, QCustomPlot &plot, SqpColorScale &colorScale)
134 {
135 dataSeries.lockRead();
136 auto xAxisUnit = dataSeries.xAxisUnit();
137 auto yAxisUnit = dataSeries.yAxisUnit();
138 auto valuesUnit = dataSeries.valuesUnit();
139 dataSeries.unlock();
140
141 setAxisProperties(*plot.xAxis, xAxisUnit);
142 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
143 setAxisProperties(*colorScale.m_Scale->axis(), valuesUnit, QCPAxis::stLogarithmic);
144 }
131 };
145 };
132
146
133 /**
147 /**
@@ -136,14 +150,25 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries
136 */
150 */
137 template <typename T>
151 template <typename T>
138 struct AxisHelper : public IAxisHelper {
152 struct AxisHelper : public IAxisHelper {
139 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
153 explicit AxisHelper(std::shared_ptr<T> dataSeries) : m_DataSeries{dataSeries} {}
140
154
141 void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) override
155 void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) override
142 {
156 {
143 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
157 AxisSetter<T>::setProperties(plot, colorScale);
144 }
158 }
145
159
146 T &m_DataSeries;
160 void setUnits(QCustomPlot &plot, SqpColorScale &colorScale) override
161 {
162 if (m_DataSeries) {
163 AxisSetter<T>::setUnits(*m_DataSeries, plot, colorScale);
164 }
165 else {
166 qCCritical(LOG_AxisRenderingUtils()) << "Can't set units: inconsistency between the "
167 "type of data series and the type supposed";
168 }
169 }
170
171 std::shared_ptr<T> m_DataSeries;
147 };
172 };
148
173
149 } // namespace
174 } // namespace
@@ -159,19 +184,22 QString formatValue(double value, const QCPAxis &axis)
159 }
184 }
160 }
185 }
161
186
162 std::unique_ptr<IAxisHelper>
187 std::unique_ptr<IAxisHelper> IAxisHelperFactory::create(const Variable &variable) noexcept
163 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
164 {
188 {
165 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
189 switch (variable.type()) {
166 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
190 case DataSeriesType::SCALAR:
167 }
191 return std::make_unique<AxisHelper<ScalarSeries> >(
168 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
192 std::dynamic_pointer_cast<ScalarSeries>(variable.dataSeries()));
169 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
193 case DataSeriesType::SPECTROGRAM:
170 }
194 return std::make_unique<AxisHelper<SpectrogramSeries> >(
171 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
195 std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()));
172 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
196 case DataSeriesType::VECTOR:
173 }
197 return std::make_unique<AxisHelper<VectorSeries> >(
174 else {
198 std::dynamic_pointer_cast<VectorSeries>(variable.dataSeries()));
175 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
199 default:
200 // Creates default helper
201 break;
176 }
202 }
203
204 return std::make_unique<AxisHelper<IDataSeries> >(nullptr);
177 }
205 }
@@ -6,6 +6,8
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <Variable/Variable.h>
10
9 #include <Visualization/qcustomplot.h>
11 #include <Visualization/qcustomplot.h>
10
12
11 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
13 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
@@ -17,7 +19,7 namespace {
17 */
19 */
18 template <typename T, typename Enabled = void>
20 template <typename T, typename Enabled = void>
19 struct PlottablesSetter {
21 struct PlottablesSetter {
20 static void setProperties(T &, PlottablesMap &)
22 static void setProperties(PlottablesMap &)
21 {
23 {
22 // Default implementation does nothing
24 // Default implementation does nothing
23 qCCritical(LOG_PlottablesRenderingUtils())
25 qCCritical(LOG_PlottablesRenderingUtils())
@@ -33,20 +35,25 struct PlottablesSetter {
33 template <typename T>
35 template <typename T>
34 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
36 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
35 or std::is_base_of<VectorSeries, T>::value> > {
37 or std::is_base_of<VectorSeries, T>::value> > {
36 static void setProperties(T &dataSeries, PlottablesMap &plottables)
38 static void setProperties(PlottablesMap &plottables)
37 {
39 {
38 // Gets the number of components of the data series
40 // Finds the plottable with the highest index to determine the number of colors to generate
39 dataSeries.lockRead();
41 auto end = plottables.cend();
40 auto componentCount = dataSeries.valuesData()->componentCount();
42 auto maxPlottableIndexIt
41 dataSeries.unlock();
43 = std::max_element(plottables.cbegin(), end, [](const auto &it1, const auto &it2) {
44 return it1.first < it2.first;
45 });
46 auto componentCount = maxPlottableIndexIt != end ? maxPlottableIndexIt->first + 1 : 0;
42
47
43 // Generates colors for each component
48 // Generates colors for each component
44 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
49 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
45
50
46 // For each component of the data series, creates a QCPGraph to add to the plot
51 // For each component of the data series, creates a QCPGraph to add to the plot
47 for (auto i = 0; i < componentCount; ++i) {
52 for (auto i = 0; i < componentCount; ++i) {
48 auto graph = plottables.at(i);
53 auto graphIt = plottables.find(i);
49 graph->setPen(QPen{colors.at(i)});
54 if (graphIt != end) {
55 graphIt->second->setPen(QPen{colors.at(i)});
56 }
50 }
57 }
51 }
58 }
52 };
59 };
@@ -58,7 +65,7 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSerie
58 template <typename T>
65 template <typename T>
59 struct PlottablesSetter<T,
66 struct PlottablesSetter<T,
60 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
67 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
61 static void setProperties(T &, PlottablesMap &plottables)
68 static void setProperties(PlottablesMap &plottables)
62 {
69 {
63 // Checks that for a spectrogram there is only one plottable, that is a colormap
70 // Checks that for a spectrogram there is only one plottable, that is a colormap
64 if (plottables.size() != 1) {
71 if (plottables.size() != 1) {
@@ -92,31 +99,28 struct PlottablesSetter<T,
92 */
99 */
93 template <typename T>
100 template <typename T>
94 struct PlottablesHelper : public IPlottablesHelper {
101 struct PlottablesHelper : public IPlottablesHelper {
95 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
96
97 void setProperties(PlottablesMap &plottables) override
102 void setProperties(PlottablesMap &plottables) override
98 {
103 {
99 PlottablesSetter<T>::setProperties(m_DataSeries, plottables);
104 PlottablesSetter<T>::setProperties(plottables);
100 }
105 }
101
102 T &m_DataSeries;
103 };
106 };
104
107
105 } // namespace
108 } // namespace
106
109
107 std::unique_ptr<IPlottablesHelper>
110 std::unique_ptr<IPlottablesHelper>
108 IPlottablesHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
111 IPlottablesHelperFactory::create(const Variable &variable) noexcept
109 {
112 {
110 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
113 switch (variable.type()) {
111 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
114 case DataSeriesType::SCALAR:
112 }
115 return std::make_unique<PlottablesHelper<ScalarSeries> >();
113 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
116 case DataSeriesType::SPECTROGRAM:
114 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
117 return std::make_unique<PlottablesHelper<SpectrogramSeries> >();
115 }
118 case DataSeriesType::VECTOR:
116 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
119 return std::make_unique<PlottablesHelper<VectorSeries> >();
117 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
120 default:
118 }
121 // Returns default helper
119 else {
122 break;
120 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
121 }
123 }
124
125 return std::make_unique<PlottablesHelper<IDataSeries> >();
122 }
126 }
@@ -25,7 +25,7 public:
25 */
25 */
26 template <typename T, typename Enabled = void>
26 template <typename T, typename Enabled = void>
27 struct PlottablesCreator {
27 struct PlottablesCreator {
28 static PlottablesMap createPlottables(T &, QCustomPlot &)
28 static PlottablesMap createPlottables(QCustomPlot &)
29 {
29 {
30 qCCritical(LOG_DataSeries())
30 qCCritical(LOG_DataSeries())
31 << QObject::tr("Can't create plottables: unmanaged data series type");
31 << QObject::tr("Can't create plottables: unmanaged data series type");
@@ -33,34 +33,37 struct PlottablesCreator {
33 }
33 }
34 };
34 };
35
35
36 PlottablesMap createGraphs(QCustomPlot &plot, int nbGraphs)
37 {
38 PlottablesMap result{};
39
40 // Creates {nbGraphs} QCPGraph to add to the plot
41 for (auto i = 0; i < nbGraphs; ++i) {
42 auto graph = plot.addGraph();
43 result.insert({i, graph});
44 }
45
46 plot.replot();
47
48 return result;
49 }
50
36 /**
51 /**
37 * Specialization of PlottablesCreator for scalars and vectors
52 * Specialization of PlottablesCreator for scalars
38 * @sa ScalarSeries
53 * @sa ScalarSeries
39 * @sa VectorSeries
40 */
54 */
41 template <typename T>
55 template <typename T>
42 struct PlottablesCreator<T,
56 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value> > {
43 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
57 static PlottablesMap createPlottables(QCustomPlot &plot) { return createGraphs(plot, 1); }
44 or std::is_base_of<VectorSeries, T>::value> > {
58 };
45 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
46 {
47 PlottablesMap result{};
48
49 // Gets the number of components of the data series
50 dataSeries.lockRead();
51 auto componentCount = dataSeries.valuesData()->componentCount();
52 dataSeries.unlock();
53
54 // For each component of the data series, creates a QCPGraph to add to the plot
55 for (auto i = 0; i < componentCount; ++i) {
56 auto graph = plot.addGraph();
57 result.insert({i, graph});
58 }
59
60 plot.replot();
61
59
62 return result;
60 /**
63 }
61 * Specialization of PlottablesCreator for vectors
62 * @sa VectorSeries
63 */
64 template <typename T>
65 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorSeries, T>::value> > {
66 static PlottablesMap createPlottables(QCustomPlot &plot) { return createGraphs(plot, 3); }
64 };
67 };
65
68
66 /**
69 /**
@@ -70,7 +73,7 struct PlottablesCreator<T,
70 template <typename T>
73 template <typename T>
71 struct PlottablesCreator<T,
74 struct PlottablesCreator<T,
72 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
75 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
73 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
76 static PlottablesMap createPlottables(QCustomPlot &plot)
74 {
77 {
75 PlottablesMap result{};
78 PlottablesMap result{};
76 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
79 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
@@ -264,41 +267,59 struct IPlottablesHelper {
264 */
267 */
265 template <typename T>
268 template <typename T>
266 struct PlottablesHelper : public IPlottablesHelper {
269 struct PlottablesHelper : public IPlottablesHelper {
267 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
270 explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries{dataSeries} {}
268
271
269 PlottablesMap create(QCustomPlot &plot) const override
272 PlottablesMap create(QCustomPlot &plot) const override
270 {
273 {
271 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
274 return PlottablesCreator<T>::createPlottables(plot);
272 }
275 }
273
276
274 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
277 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
275 {
278 {
276 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
279 if (m_DataSeries) {
280 PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes);
281 }
282 else {
283 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
284 "between the type of data series and the "
285 "type supposed";
286 }
277 }
287 }
278
288
279 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
289 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
280 {
290 {
281 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
291 if (m_DataSeries) {
292 PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot);
293 }
294 else {
295 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
296 "between the type of data series and the "
297 "type supposed";
298 }
282 }
299 }
283
300
284 T &m_DataSeries;
301 std::shared_ptr<T> m_DataSeries;
285 };
302 };
286
303
287 /// Creates IPlottablesHelper according to a data series
304 /// Creates IPlottablesHelper according to the type of data series a variable holds
288 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
305 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable> variable) noexcept
289 {
306 {
290 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
307 switch (variable->type()) {
291 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
308 case DataSeriesType::SCALAR:
292 }
309 return std::make_unique<PlottablesHelper<ScalarSeries> >(
293 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
310 std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries()));
294 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
311 case DataSeriesType::SPECTROGRAM:
295 }
312 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(
296 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
313 std::dynamic_pointer_cast<SpectrogramSeries>(variable->dataSeries()));
297 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
314 case DataSeriesType::VECTOR:
298 }
315 return std::make_unique<PlottablesHelper<VectorSeries> >(
299 else {
316 std::dynamic_pointer_cast<VectorSeries>(variable->dataSeries()));
300 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
317 default:
318 // Creates default helper
319 break;
301 }
320 }
321
322 return std::make_unique<PlottablesHelper<IDataSeries> >(nullptr);
302 }
323 }
303
324
304 } // namespace
325 } // namespace
@@ -307,7 +328,7 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variabl
307 QCustomPlot &plot) noexcept
328 QCustomPlot &plot) noexcept
308 {
329 {
309 if (variable) {
330 if (variable) {
310 auto helper = createHelper(variable->dataSeries());
331 auto helper = createHelper(variable);
311 auto plottables = helper->create(plot);
332 auto plottables = helper->create(plot);
312 return plottables;
333 return plottables;
313 }
334 }
@@ -322,7 +343,7 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
322 QCustomPlot &plot) noexcept
343 QCustomPlot &plot) noexcept
323 {
344 {
324 if (variable) {
345 if (variable) {
325 auto helper = createHelper(variable->dataSeries());
346 auto helper = createHelper(variable);
326 helper->setYAxisRange(variable->range(), plot);
347 helper->setYAxisRange(variable->range(), plot);
327 }
348 }
328 else {
349 else {
@@ -332,9 +353,9 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
332 }
353 }
333
354
334 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
355 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
335 std::shared_ptr<IDataSeries> dataSeries,
356 std::shared_ptr<Variable> variable,
336 const SqpRange &dateTime)
357 const SqpRange &dateTime)
337 {
358 {
338 auto helper = createHelper(dataSeries);
359 auto helper = createHelper(variable);
339 helper->update(plottables, dateTime);
360 helper->update(plottables, dateTime);
340 }
361 }
@@ -9,6 +9,7
9 #include <Common/DateUtils.h>
9 #include <Common/DateUtils.h>
10
10
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <Variable/Variable.h>
12
13
13 #include <SqpApplication.h>
14 #include <SqpApplication.h>
14
15
@@ -302,14 +303,14 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
302 impl->m_Plot.replot();
303 impl->m_Plot.replot();
303 }
304 }
304
305
305 void VisualizationGraphRenderingDelegate::setAxesProperties(
306 void VisualizationGraphRenderingDelegate::setAxesUnits(const Variable &variable) noexcept
306 std::shared_ptr<IDataSeries> dataSeries) noexcept
307 {
307 {
308 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
309 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
310
308
311 auto axisHelper = IAxisHelperFactory::create(dataSeries);
309 auto axisHelper = IAxisHelperFactory::create(variable);
312 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
310 axisHelper->setUnits(impl->m_Plot, impl->m_ColorScale);
311
312 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
313 impl->m_XAxisLabel = impl->m_Plot.xAxis->label();
313
314
314 // Updates x-axis state
315 // Updates x-axis state
315 impl->updateXAxisState();
316 impl->updateXAxisState();
@@ -317,10 +318,15 void VisualizationGraphRenderingDelegate::setAxesProperties(
317 impl->m_Plot.layer(AXES_LAYER)->replot();
318 impl->m_Plot.layer(AXES_LAYER)->replot();
318 }
319 }
319
320
320 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
321 void VisualizationGraphRenderingDelegate::setGraphProperties(const Variable &variable,
321 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
322 PlottablesMap &plottables) noexcept
322 {
323 {
323 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
324 // Axes' properties
325 auto axisHelper = IAxisHelperFactory::create(variable);
326 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
327
328 // Plottables' properties
329 auto plottablesHelper = IPlottablesHelperFactory::create(variable);
324 plottablesHelper->setProperties(plottables);
330 plottablesHelper->setProperties(plottables);
325 }
331 }
326
332
@@ -12,6 +12,7
12 #include "ui_VisualizationGraphWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
13
13
14 #include <Actions/ActionsGuiController.h>
14 #include <Actions/ActionsGuiController.h>
15 #include <Actions/FilteringAction.h>
15 #include <Common/MimeTypesDef.h>
16 #include <Common/MimeTypesDef.h>
16 #include <Data/ArrayData.h>
17 #include <Data/ArrayData.h>
17 #include <Data/IDataSeries.h>
18 #include <Data/IDataSeries.h>
@@ -59,16 +60,16 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
59
60
60 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 : m_Name{name},
62 : m_Name{name},
62 m_DoAcquisition{true},
63 m_Flags{GraphFlag::EnableAll},
63 m_IsCalibration{false},
64 m_IsCalibration{false},
64 m_RenderingDelegate{nullptr}
65 m_RenderingDelegate{nullptr}
65 {
66 {
66 }
67 }
67
68
68 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
69 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
69 const SqpRange &range)
70 const SqpRange &range)
70 {
71 {
71 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
72 VisualizationGraphHelper::updateData(plottables, variable, range);
72
73
73 // Prevents that data has changed to update rendering
74 // Prevents that data has changed to update rendering
74 m_RenderingDelegate->onPlotUpdated();
75 m_RenderingDelegate->onPlotUpdated();
@@ -77,7 +78,7 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
77 QString m_Name;
78 QString m_Name;
78 // 1 variable -> n qcpplot
79 // 1 variable -> n qcpplot
79 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
80 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
80 bool m_DoAcquisition;
81 GraphFlags m_Flags;
81 bool m_IsCalibration;
82 bool m_IsCalibration;
82 /// Delegate used to attach rendering features to the plot
83 /// Delegate used to attach rendering features to the plot
83 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
84 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
@@ -94,6 +95,8 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
94
95
95 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
96 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
96
97
98 bool m_VariableAutoRangeOnInit = true;
99
97 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
100 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
98 {
101 {
99 removeDrawingRect(plot);
102 removeDrawingRect(plot);
@@ -243,7 +246,7 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget
243 &VisualizationGraphWidget::onMouseDoubleClick);
246 &VisualizationGraphWidget::onMouseDoubleClick);
244 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
247 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
245 &QCPAxis::rangeChanged),
248 &QCPAxis::rangeChanged),
246 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
249 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
247
250
248 // Activates menu when right clicking on the graph
251 // Activates menu when right clicking on the graph
249 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
252 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -256,9 +259,8 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget
256 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
259 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
257 &VisualizationGraphWidget::onUpdateVarDisplaying);
260 &VisualizationGraphWidget::onUpdateVarDisplaying);
258
261
259 #ifdef Q_OS_MAC
262 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
260 plot().setPlottingHint(QCP::phFastPolylines, true);
263 plot().setPlottingHint(QCP::phFastPolylines, true);
261 #endif
262 }
264 }
263
265
264
266
@@ -287,35 +289,54 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
287 return qobject_cast<VisualizationWidget *>(parent);
289 return qobject_cast<VisualizationWidget *>(parent);
288 }
290 }
289
291
290 void VisualizationGraphWidget::enableAcquisition(bool enable)
292 void VisualizationGraphWidget::setFlags(GraphFlags flags)
291 {
293 {
292 impl->m_DoAcquisition = enable;
294 impl->m_Flags = std::move(flags);
293 }
295 }
294
296
295 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
297 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
296 {
298 {
297 // Uses delegate to create the qcpplot components according to the variable
299 /// Lambda used to set graph's units and range according to the variable passed in parameter
298 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
300 auto loadRange = [this](std::shared_ptr<Variable> variable, const SqpRange &range) {
301 impl->m_RenderingDelegate->setAxesUnits(*variable);
302
303 this->setFlags(GraphFlag::DisableAll);
304 setGraphRange(range);
305 this->setFlags(GraphFlag::EnableAll);
306 emit requestDataLoading({variable}, range, false);
307 };
299
308
300 if (auto dataSeries = variable->dataSeries()) {
309 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
301 // Set axes properties according to the units of the data series
302 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
303
310
304 // Sets rendering properties for the new plottables
311 // Calls update of graph's range and units when the data of the variable have been initialized.
305 // Warning: this method must be called after setAxesProperties(), as it can access to some
312 // Note: we use QueuedConnection here as the update event must be called in the UI thread
306 // axes properties that have to be initialized
313 connect(variable.get(), &Variable::dataInitialized, this,
307 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
314 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
308 }
315 if (auto var = varW.lock()) {
316 // If the variable is the first added in the graph, we load its range
317 auto firstVariableInGraph = range == INVALID_RANGE;
318 auto loadedRange = graphRange();
319 if (impl->m_VariableAutoRangeOnInit) {
320 loadedRange = firstVariableInGraph ? var->range() : range;
321 }
322 loadRange(var, loadedRange);
323 setYRange(var);
324 }
325 },
326 Qt::QueuedConnection);
309
327
310 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
328 // Uses delegate to create the qcpplot components according to the variable
329 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
311
330
312 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
331 // Sets graph properties
332 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
313
333
314 this->enableAcquisition(false);
334 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
315 this->setGraphRange(range);
316 this->enableAcquisition(true);
317
335
318 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
336 // If the variable already has its data loaded, load its units and its range in the graph
337 if (variable->dataSeries() != nullptr) {
338 loadRange(variable, range);
339 }
319
340
320 emit variableAdded(variable);
341 emit variableAdded(variable);
321 }
342 }
@@ -371,14 +392,29 SqpRange VisualizationGraphWidget::graphRange() const noexcept
371 return SqpRange{graphRange.lower, graphRange.upper};
392 return SqpRange{graphRange.lower, graphRange.upper};
372 }
393 }
373
394
374 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
395 void VisualizationGraphWidget::setGraphRange(const SqpRange &range, bool calibration)
375 {
396 {
376 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
397 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
398
399 if (calibration) {
400 impl->m_IsCalibration = true;
401 }
402
377 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
403 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
378 ui->widget->replot();
404 ui->widget->replot();
405
406 if (calibration) {
407 impl->m_IsCalibration = false;
408 }
409
379 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
410 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
380 }
411 }
381
412
413 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
414 {
415 impl->m_VariableAutoRangeOnInit = value;
416 }
417
382 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
418 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
383 {
419 {
384 QVector<SqpRange> ranges;
420 QVector<SqpRange> ranges;
@@ -401,6 +437,20 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges
401 plot().replot(QCustomPlot::rpQueuedReplot);
437 plot().replot(QCustomPlot::rpQueuedReplot);
402 }
438 }
403
439
440 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
441 const SqpRange &range)
442 {
443 // note: ownership is transfered to QCustomPlot
444 auto zone = new VisualizationSelectionZoneItem(&plot());
445 zone->setName(name);
446 zone->setRange(range.m_TStart, range.m_TEnd);
447 impl->addSelectionZone(zone);
448
449 plot().replot(QCustomPlot::rpQueuedReplot);
450
451 return zone;
452 }
453
404 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
454 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
405 {
455 {
406 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
456 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
@@ -584,6 +634,10 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
584 {
634 {
585 Q_UNUSED(event);
635 Q_UNUSED(event);
586
636
637 for (auto i : impl->m_SelectionZones) {
638 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
639 }
640
587 // Prevents that all variables will be removed from graph when it will be closed
641 // Prevents that all variables will be removed from graph when it will be closed
588 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
642 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
589 emit variableAboutToBeRemoved(variableEntry.first);
643 emit variableAboutToBeRemoved(variableEntry.first);
@@ -654,32 +708,51 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
654
708
655 QHash<QString, QMenu *> subMenus;
709 QHash<QString, QMenu *> subMenus;
656 QHash<QString, bool> subMenusEnabled;
710 QHash<QString, bool> subMenusEnabled;
711 QHash<QString, FilteringAction *> filteredMenu;
657
712
658 for (auto zoneAction : zoneActions) {
713 for (auto zoneAction : zoneActions) {
659
714
660 auto isEnabled = zoneAction->isEnabled(selectedItems);
715 auto isEnabled = zoneAction->isEnabled(selectedItems);
661
716
662 auto menu = &graphMenu;
717 auto menu = &graphMenu;
718 QString menuPath;
663 for (auto subMenuName : zoneAction->subMenuList()) {
719 for (auto subMenuName : zoneAction->subMenuList()) {
664 if (!subMenus.contains(subMenuName)) {
720 menuPath += '/';
721 menuPath += subMenuName;
722
723 if (!subMenus.contains(menuPath)) {
665 menu = menu->addMenu(subMenuName);
724 menu = menu->addMenu(subMenuName);
666 subMenus[subMenuName] = menu;
725 subMenus[menuPath] = menu;
667 subMenusEnabled[subMenuName] = isEnabled;
726 subMenusEnabled[menuPath] = isEnabled;
668 }
727 }
669 else {
728 else {
670 menu = subMenus.value(subMenuName);
729 menu = subMenus.value(menuPath);
671 if (isEnabled) {
730 if (isEnabled) {
672 // The sub menu is enabled if at least one of its actions is enabled
731 // The sub menu is enabled if at least one of its actions is enabled
673 subMenusEnabled[subMenuName] = true;
732 subMenusEnabled[menuPath] = true;
674 }
733 }
675 }
734 }
676 }
735 }
677
736
737 FilteringAction *filterAction = nullptr;
738 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
739 filterAction = filteredMenu.value(menuPath);
740 if (!filterAction) {
741 filterAction = new FilteringAction{this};
742 filteredMenu[menuPath] = filterAction;
743 menu->addAction(filterAction);
744 }
745 }
746
678 auto action = menu->addAction(zoneAction->name());
747 auto action = menu->addAction(zoneAction->name());
679 action->setEnabled(isEnabled);
748 action->setEnabled(isEnabled);
680 action->setShortcut(zoneAction->displayedShortcut());
749 action->setShortcut(zoneAction->displayedShortcut());
681 QObject::connect(action, &QAction::triggered,
750 QObject::connect(action, &QAction::triggered,
682 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
751 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
752
753 if (filterAction && zoneAction->isFilteringAllowed()) {
754 filterAction->addActionToFilter(action);
755 }
683 }
756 }
684
757
685 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
758 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
@@ -696,12 +769,12 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange
696 {
769 {
697 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
770 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
698 << QThread::currentThread()->objectName() << "DoAcqui"
771 << QThread::currentThread()->objectName() << "DoAcqui"
699 << impl->m_DoAcquisition;
772 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
700
773
701 auto graphRange = SqpRange{t1.lower, t1.upper};
774 auto graphRange = SqpRange{t1.lower, t1.upper};
702 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
775 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
703
776
704 if (impl->m_DoAcquisition) {
777 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
705 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
778 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
706
779
707 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
780 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
@@ -711,13 +784,13 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange
711 }
784 }
712 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
785 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
713 !impl->m_IsCalibration);
786 !impl->m_IsCalibration);
787 }
714
788
715 if (!impl->m_IsCalibration) {
789 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
716 qCDebug(LOG_VisualizationGraphWidget())
790 qCDebug(LOG_VisualizationGraphWidget())
717 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
791 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
718 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
792 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
719 emit synchronize(graphRange, oldGraphRange);
793 emit synchronize(graphRange, oldGraphRange);
720 }
721 }
794 }
722
795
723 auto pos = mapFromGlobal(QCursor::pos());
796 auto pos = mapFromGlobal(QCursor::pos());
@@ -733,6 +806,9 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange
733 else {
806 else {
734 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
807 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
735 }
808 }
809
810 // Quits calibration
811 impl->m_IsCalibration = false;
736 }
812 }
737
813
738 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
814 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
@@ -803,6 +879,11 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
803
879
804 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
880 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
805 {
881 {
882 // Processes event only if the wheel occurs on axis rect
883 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
884 return;
885 }
886
806 auto value = event->angleDelta().x() + event->angleDelta().y();
887 auto value = event->angleDelta().x() + event->angleDelta().y();
807 if (value != 0) {
888 if (value != 0) {
808
889
@@ -917,8 +998,6 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
917
998
918 impl->endDrawingZone(this);
999 impl->endDrawingZone(this);
919
1000
920 impl->m_IsCalibration = false;
921
922 // Selection / Deselection
1001 // Selection / Deselection
923 auto isSelectionZoneMode
1002 auto isSelectionZoneMode
924 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1003 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
@@ -988,7 +1067,7 void VisualizationGraphWidget::onDataCacheVariableUpdated()
988 qCDebug(LOG_VisualizationGraphWidget())
1067 qCDebug(LOG_VisualizationGraphWidget())
989 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1068 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
990 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1069 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
991 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
1070 impl->updateData(variableEntry.second, variable, variable->range());
992 }
1071 }
993 }
1072 }
994 }
1073 }
@@ -998,6 +1077,6 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> v
998 {
1077 {
999 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1078 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1000 if (it != impl->m_VariableToPlotMultiMap.end()) {
1079 if (it != impl->m_VariableToPlotMultiMap.end()) {
1001 impl->updateData(it->second, variable->dataSeries(), range);
1080 impl->updateData(it->second, variable, range);
1002 }
1081 }
1003 }
1082 }
@@ -4,7 +4,7
4 #include "Common/DateUtils.h"
4 #include "Common/DateUtils.h"
5 #include "Visualization/VisualizationSelectionZoneItem.h"
5 #include "Visualization/VisualizationSelectionZoneItem.h"
6
6
7 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss");
7 const auto DATETIME_FORMAT_S = QStringLiteral("yyyy/MM/dd hh:mm:ss");
8
8
9 struct VisualizationMultiZoneSelectionDialog::VisualizationMultiZoneSelectionDialogPrivate {
9 struct VisualizationMultiZoneSelectionDialog::VisualizationMultiZoneSelectionDialogPrivate {
10 QVector<VisualizationSelectionZoneItem *> m_Zones;
10 QVector<VisualizationSelectionZoneItem *> m_Zones;
@@ -46,9 +46,9 void VisualizationMultiZoneSelectionDialog::setZones(
46 }
46 }
47
47
48 auto range = zone->range();
48 auto range = zone->range();
49 name += DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT);
49 name += DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT_S);
50 name += " - ";
50 name += " - ";
51 name += DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT);
51 name += DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT_S);
52
52
53 auto item = new QListWidgetItem(name, ui->listWidget);
53 auto item = new QListWidgetItem(name, ui->listWidget);
54 item->setSelected(zone->selected());
54 item->setSelected(zone->selected());
@@ -388,8 +388,11 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QP
388 break;
388 break;
389 }
389 }
390
390
391 emit rangeEdited(range());
392
391 for (auto associatedZone : impl->m_AssociatedEditedZones) {
393 for (auto associatedZone : impl->m_AssociatedEditedZones) {
392 associatedZone->parentPlot()->replot();
394 associatedZone->parentPlot()->replot();
395 emit associatedZone->rangeEdited(associatedZone->range());
393 }
396 }
394 }
397 }
395 else {
398 else {
@@ -39,7 +39,10 void VisualizationSelectionZoneManager::clearSelection()
39 {
39 {
40 for (auto item : impl->m_SelectedItems) {
40 for (auto item : impl->m_SelectedItems) {
41 item->setSelected(false);
41 item->setSelected(false);
42 item->parentPlot()->replot(QCustomPlot::rpQueuedReplot);
42 auto parentPlot = item->parentPlot();
43 if (parentPlot) {
44 parentPlot->replot(QCustomPlot::rpQueuedReplot);
45 }
43 }
46 }
44
47
45 impl->m_SelectedItems.clear();
48 impl->m_SelectedItems.clear();
@@ -7,6 +7,7
7
7
8 #include "Visualization/MacScrollBarStyle.h"
8 #include "Visualization/MacScrollBarStyle.h"
9
9
10 #include "DataSource/DataSourceController.h"
10 #include "Variable/VariableController.h"
11 #include "Variable/VariableController.h"
11
12
12 #include "Common/MimeTypesDef.h"
13 #include "Common/MimeTypesDef.h"
@@ -69,6 +70,8 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
69 void dropZone(int index, VisualizationTabWidget *tabWidget);
70 void dropZone(int index, VisualizationTabWidget *tabWidget);
70 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
71 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
71 VisualizationTabWidget *tabWidget);
72 VisualizationTabWidget *tabWidget);
73 void dropProducts(const QVariantList &productsMetaData, int index,
74 VisualizationTabWidget *tabWidget);
72 };
75 };
73
76
74 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
77 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
@@ -91,6 +94,8 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *par
91 VisualizationDragDropContainer::DropBehavior::Inserted);
94 VisualizationDragDropContainer::DropBehavior::Inserted);
92 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
95 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
93 VisualizationDragDropContainer::DropBehavior::Inserted);
96 VisualizationDragDropContainer::DropBehavior::Inserted);
97 ui->dragDropContainer->setMimeType(MIME_TYPE_PRODUCT_LIST,
98 VisualizationDragDropContainer::DropBehavior::Inserted);
94
99
95 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
100 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
96 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
101 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
@@ -229,6 +234,11 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
229 mimeData->data(MIME_TYPE_VARIABLE_LIST));
234 mimeData->data(MIME_TYPE_VARIABLE_LIST));
230 impl->dropVariables(variables, index, this);
235 impl->dropVariables(variables, index, this);
231 }
236 }
237 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
238 auto productsData = sqpApp->dataSourceController().productsDataForMimeData(
239 mimeData->data(MIME_TYPE_PRODUCT_LIST));
240 impl->dropProducts(productsData, index, this);
241 }
232 else {
242 else {
233 qCWarning(LOG_VisualizationZoneWidget())
243 qCWarning(LOG_VisualizationZoneWidget())
234 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
244 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
@@ -352,3 +362,28 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
352
362
353 tabWidget->createZone(variables, index);
363 tabWidget->createZone(variables, index);
354 }
364 }
365
366 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropProducts(
367 const QVariantList &productsMetaData, int index, VisualizationTabWidget *tabWidget)
368 {
369 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
370 // compatible variable here
371 if (productsMetaData.count() != 1) {
372 qCWarning(LOG_VisualizationZoneWidget())
373 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
374 "aborted.");
375 return;
376 }
377
378 auto context = new QObject{tabWidget};
379 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
380 [this, index, tabWidget, context](auto variable) {
381 tabWidget->createZone({variable}, index);
382 delete context; // removes the connection
383 },
384 Qt::QueuedConnection);
385
386 auto productData = productsMetaData.first().toHash();
387 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
388 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
389 }
@@ -10,6 +10,7
10 #include "Common/VisualizationDef.h"
10 #include "Common/VisualizationDef.h"
11
11
12 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
13 #include <DataSource/DataSourceController.h>
13 #include <Time/TimeController.h>
14 #include <Time/TimeController.h>
14 #include <Variable/Variable.h>
15 #include <Variable/Variable.h>
15 #include <Variable/VariableController.h>
16 #include <Variable/VariableController.h>
@@ -78,6 +79,8 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
78 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
79 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
79 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
80 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
80 VisualizationZoneWidget *zoneWidget);
81 VisualizationZoneWidget *zoneWidget);
82 void dropProducts(const QVariantList &productsData, int index,
83 VisualizationZoneWidget *zoneWidget);
81 };
84 };
82
85
83 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
86 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
@@ -94,6 +97,8 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *p
94 VisualizationDragDropContainer::DropBehavior::Inserted);
97 VisualizationDragDropContainer::DropBehavior::Inserted);
95 ui->dragDropContainer->setMimeType(
98 ui->dragDropContainer->setMimeType(
96 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
99 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
100 ui->dragDropContainer->setMimeType(
101 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
97 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
102 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
98 VisualizationDragDropContainer::DropBehavior::Merged);
103 VisualizationDragDropContainer::DropBehavior::Merged);
99 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
104 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
@@ -264,7 +269,7 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<V
264 // No action
269 // No action
265 break;
270 break;
266 }
271 }
267 graphChild->enableAcquisition(false);
272 graphChild->setFlags(GraphFlag::DisableAll);
268 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
273 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
269 << graphChild->graphRange();
274 << graphChild->graphRange();
270 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
275 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
@@ -272,7 +277,7 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<V
272 qCDebug(LOG_VisualizationZoneWidget())
277 qCDebug(LOG_VisualizationZoneWidget())
273 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
278 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
274 graphChild->setGraphRange(graphChildRange);
279 graphChild->setGraphRange(graphChildRange);
275 graphChild->enableAcquisition(true);
280 graphChild->setFlags(GraphFlag::EnableAll);
276 }
281 }
277 }
282 }
278 };
283 };
@@ -331,6 +336,12 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
331 return firstGraph;
336 return firstGraph;
332 }
337 }
333
338
339 void VisualizationZoneWidget::closeAllGraphs()
340 {
341 processGraphs(*ui->dragDropContainer->layout(),
342 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
343 }
344
334 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
345 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
335 {
346 {
336 if (visitor) {
347 if (visitor) {
@@ -477,6 +488,11 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
477 mimeData->data(MIME_TYPE_VARIABLE_LIST));
488 mimeData->data(MIME_TYPE_VARIABLE_LIST));
478 impl->dropVariables(variables, index, this);
489 impl->dropVariables(variables, index, this);
479 }
490 }
491 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
492 auto products = sqpApp->dataSourceController().productsDataForMimeData(
493 mimeData->data(MIME_TYPE_PRODUCT_LIST));
494 impl->dropProducts(products, index, this);
495 }
480 else {
496 else {
481 qCWarning(LOG_VisualizationZoneWidget())
497 qCWarning(LOG_VisualizationZoneWidget())
482 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
498 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
@@ -502,6 +518,22 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragW
502 graphWidget->addVariable(var, graphWidget->graphRange());
518 graphWidget->addVariable(var, graphWidget->graphRange());
503 }
519 }
504 }
520 }
521 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
522 auto products = sqpApp->dataSourceController().productsDataForMimeData(
523 mimeData->data(MIME_TYPE_PRODUCT_LIST));
524
525 auto context = new QObject{this};
526 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
527 [this, graphWidget, context](auto variable) {
528 graphWidget->addVariable(variable, graphWidget->graphRange());
529 delete context; // removes the connection
530 },
531 Qt::QueuedConnection);
532
533 auto productData = products.first().toHash();
534 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
535 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
536 }
505 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
537 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
506 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
538 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
507 graphWidget->setGraphRange(range);
539 graphWidget->setGraphRange(range);
@@ -599,3 +631,28 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
599
631
600 zoneWidget->createGraph(variables, index);
632 zoneWidget->createGraph(variables, index);
601 }
633 }
634
635 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
636 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
637 {
638 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
639 // compatible variable here
640 if (productsData.count() != 1) {
641 qCWarning(LOG_VisualizationZoneWidget())
642 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
643 "aborted.");
644 return;
645 }
646
647 auto context = new QObject{zoneWidget};
648 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
649 [this, index, zoneWidget, context](auto variable) {
650 zoneWidget->createGraph(variable, index);
651 delete context; // removes the connection
652 },
653 Qt::QueuedConnection);
654
655 auto productData = productsData.first().toHash();
656 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
657 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
658 }
@@ -59,9 +59,11 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
59 if (graphWidget) {
59 if (graphWidget) {
60 // If the widget contains the variable, rescale it
60 // If the widget contains the variable, rescale it
61 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
61 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
62 graphWidget->enableAcquisition(false);
62 // During rescale, acquisition for the graph is disabled but synchronization is still
63 // enabled
64 graphWidget->setFlags(GraphFlag::EnableSynchronization);
63 graphWidget->setGraphRange(impl->m_Range);
65 graphWidget->setGraphRange(impl->m_Range);
64 graphWidget->enableAcquisition(true);
66 graphWidget->setFlags(GraphFlag::EnableAll);
65 }
67 }
66 }
68 }
67 else {
69 else {
@@ -85,9 +85,6
85 </item>
85 </item>
86 <item>
86 <item>
87 <widget class="QToolButton" name="btnChart">
87 <widget class="QToolButton" name="btnChart">
88 <property name="enabled">
89 <bool>false</bool>
90 </property>
91 <property name="text">
88 <property name="text">
92 <string>G</string>
89 <string>G</string>
93 </property>
90 </property>
@@ -142,7 +139,6
142 </widget>
139 </widget>
143 <resources>
140 <resources>
144 <include location="../../resources/sqpguiresources.qrc"/>
141 <include location="../../resources/sqpguiresources.qrc"/>
145 <include location="../../resources/sqpguiresources.qrc"/>
146 </resources>
142 </resources>
147 <connections/>
143 <connections/>
148 </ui>
144 </ui>
@@ -31,7 +31,7
31 <item>
31 <item>
32 <widget class="QToolButton" name="btnAdd">
32 <widget class="QToolButton" name="btnAdd">
33 <property name="enabled">
33 <property name="enabled">
34 <bool>false</bool>
34 <bool>true</bool>
35 </property>
35 </property>
36 <property name="text">
36 <property name="text">
37 <string>+</string>
37 <string>+</string>
@@ -48,7 +48,7
48 <item>
48 <item>
49 <widget class="QToolButton" name="btnRemove">
49 <widget class="QToolButton" name="btnRemove">
50 <property name="enabled">
50 <property name="enabled">
51 <bool>false</bool>
51 <bool>true</bool>
52 </property>
52 </property>
53 <property name="text">
53 <property name="text">
54 <string> - </string>
54 <string> - </string>
@@ -100,7 +100,6
100 </widget>
100 </widget>
101 <resources>
101 <resources>
102 <include location="../../resources/sqpguiresources.qrc"/>
102 <include location="../../resources/sqpguiresources.qrc"/>
103 <include location="../../resources/sqpguiresources.qrc"/>
104 </resources>
103 </resources>
105 <connections/>
104 <connections/>
106 </ui>
105 </ui>
@@ -1,168 +1,40
1 ## amda - CMakeLists.txt
1 include_directories(include)
2 STRING(TOLOWER ${CMAKE_PROJECT_NAME} LIBRARY_PREFFIX)
2 FILE (GLOB_RECURSE amdaplugin_SRCS
3 SET(SQPAMDA_LIBRARY_NAME "${LIBRARY_PREFFIX}_amda${DEBUG_SUFFIX}")
3 include/*.h
4 SET(SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
4 src/*.cpp
5 SET(INCLUDES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
5 resources/*.qrc
6 SET(RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources")
6 )
7 SET(TESTS_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests-resources")
8
7
9 # Include amda directory
10 INCLUDE_DIRECTORIES(${INCLUDES_DIR})
11 INCLUDE_DIRECTORIES(${RESOURCES_DIR})
12
8
13 #
9 set(AMDA_server_type hybrid CACHE STRING "AMDA server type selected at CMake configure time")
14 # Find Qt modules
15 #
16 SCIQLOP_FIND_QT(Core Widgets Network)
17
10
18 #
11 set(AMDA_SERVER_TYPE "hybrid;amdatest;localhost" CACHE STRING
19 # Find dependent libraries
12 "List of possible for AMDA server type")
20 # ========================
21
13
22 # sciqlop plugin
14 set_property(CACHE AMDA_server_type PROPERTY STRINGS ${AMDA_SERVER_TYPE})
23 find_package(sciqlop-plugin)
15 add_definitions(-DSCIQLOP_AMDA_SERVER="{AMDA_server_type}")
24 INCLUDE_DIRECTORIES(${SCIQLOP-PLUGIN_INCLUDE_DIR})
25
16
26 # sciqlop core
17 add_definitions(-DQT_PLUGIN)
27 find_package(sciqlop-core)
18 add_definitions(-DSCIQLOP_PLUGIN_JSON_FILE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/amda.json")
28 INCLUDE_DIRECTORIES(${SCIQLOP-CORE_INCLUDE_DIR})
19 if(NOT BUILD_SHARED_LIBS)
29 list(APPEND LIBRARIES ${SCIQLOP-CORE_LIBRARIES})
20 add_definitions(-DQT_STATICPLUGIN)
21 endif()
30
22
31 # sciqlop gui
23 add_library(amdaplugin ${amdaplugin_SRCS})
32 find_package(sciqlop-gui)
24 SET_TARGET_PROPERTIES(amdaplugin PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
33 INCLUDE_DIRECTORIES(${SCIQLOP-GUI_INCLUDE_DIR})
34 list(APPEND LIBRARIES ${SCIQLOP-GUI_LIBRARIES})
35
25
36 # Description file
26 target_link_libraries(amdaplugin PUBLIC sciqlopgui)
37 FILE (GLOB_RECURSE PLUGIN_FILE ${RESOURCES_DIR}/amda.json)
38
27
39 # Resources files
28 install(TARGETS amdaplugin
40 FILE (GLOB_RECURSE PROJECT_RESOURCES ${RESOURCES_DIR}/*.qrc)
29 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop
30 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop
31 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
41
32
42 #
33 include(sciqlop_tests)
43 # Compile the library
44 #
45
34
46 ADD_DEFINITIONS(-DAMDA_LIB)
35 add_definitions(-DAMDA_TESTS_RESOURCES_DIR="${CMAKE_CURRENT_LIST_DIR}/tests-resources")
47
36
48 FILE (GLOB_RECURSE MODULE_SOURCES
37 declare_test(TestAmdaParser TestAmdaParser tests/TestAmdaParser.cpp "amdaplugin;Qt5::Test")
49 ${INCLUDES_DIR}/*.h
38 declare_test(TestAmdaResultParser TestAmdaResultParser tests/TestAmdaResultParser.cpp "amdaplugin;Qt5::Test")
50 ${SOURCES_DIR}/*.c
39 declare_test(TestAmdaAcquisition TestAmdaAcquisition tests/TestAmdaAcquisition.cpp "amdaplugin;Qt5::Test")
51 ${SOURCES_DIR}/*.cpp
40 declare_test(TestAmdaFuzzing TestAmdaFuzzing "tests/TestAmdaFuzzing.cpp;tests/FuzzingValidators.cpp;tests/FuzzingUtils.cpp;tests/FuzzingOperations.cpp;tests/FuzzingDefs.cpp" "amdaplugin;Qt5::Test")
52 ${SOURCES_DIR}/*.h
53 ${PLUGIN_FILE})
54
55 QT5_ADD_RESOURCES(RCC_AMDA
56 ${PROJECT_RESOURCES}
57 )
58
59 ADD_LIBRARY(${SQPAMDA_LIBRARY_NAME} ${MODULE_SOURCES} ${RCC_AMDA})
60 set_property(TARGET ${SQPAMDA_LIBRARY_NAME} PROPERTY CXX_STANDARD 14)
61 set_property(TARGET ${SQPAMDA_LIBRARY_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
62
63 INSTALL(TARGETS ${SQPAMDA_LIBRARY_NAME}
64 RUNTIME DESTINATION ${INSTALL_BINARY_DIR}
65 LIBRARY DESTINATION ${INSTALL_PLUGINS_LIBRARY_DIR}
66 ARCHIVE DESTINATION ${INSTALL_PLUGINS_LIBRARY_DIR}
67 )
68
69
70 TARGET_LINK_LIBRARIES(${SQPAMDA_LIBRARY_NAME} ${LIBRARIES})
71 qt5_use_modules(${SQPAMDA_LIBRARY_NAME} Core Widgets Network)
72
73 add_dependencies(${SQPAMDA_LIBRARY_NAME} ${SQPPLUGIN_LIBRARY_NAME} ${SQPGUI_LIBRARY_NAME} ${SQPCORE_LIBRARY_NAME})
74
75 # From cmake documentation: http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
76 # Entries in the COMPILE_DEFINITIONS are prefixed with -D or /D and added to the compile line in an unspecified order.
77 # The DEFINE_SYMBOL target property is also added as a compile definition as a special convenience case for SHARED and MODULE library targets
78 IF(BUILD_SHARED_LIBS)
79 SET_TARGET_PROPERTIES(${SQPAMDA_LIBRARY_NAME} PROPERTIES COMPILE_DEFINITIONS "SCIQLOP_EXPORT")
80 ELSE()
81 TARGET_COMPILE_DEFINITIONS(${SQPAMDA_LIBRARY_NAME} PUBLIC "SCIQLOP_STATIC_LIBRARIES")
82 ENDIF()
83
84 # Set the variable to parent scope so that the other projects can copy the
85 # dependent shared libraries
86 SCIQLOP_SET_TO_PARENT_SCOPE(SQPAMDA_LIBRARY_NAME)
87
88 # Copy extern shared libraries to the lib folder
89 SCIQLOP_COPY_TO_TARGET(LIBRARY ${SQPAMDA_LIBRARY_NAME} ${EXTERN_SHARED_LIBRARIES})
90
91 # Add the files to the list of files to be analyzed
92 LIST(APPEND CHECKSTYLE_INPUT_FILES ${MODULE_SOURCES})
93 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_INPUT_FILES)
94 # Vera++ exclusion files
95 LIST(APPEND CHECKSTYLE_EXCLUSION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vera-exclusions/exclusions.txt)
96 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_EXCLUSION_FILES)
97
98 #
99 # Compile the tests
100 #
101 IF(BUILD_TESTS)
102 INCLUDE_DIRECTORIES(${SOURCES_DIR})
103 FILE (GLOB_RECURSE TESTS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test*.cpp)
104 FILE (GLOB_RECURSE TESTS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Test*.h)
105 SET( TEST_LIBRARIES ${SQPAMDA_LIBRARY_NAME})
106
107 FOREACH( testFile ${TESTS_SOURCES} )
108 GET_FILENAME_COMPONENT( testDirectory ${testFile} DIRECTORY )
109 GET_FILENAME_COMPONENT( testName ${testFile} NAME_WE )
110
111 # Add to the list of sources files all the sources in the same
112 # directory that aren't another test
113 FILE (GLOB currentTestSources
114 ${testDirectory}/*.c
115 ${testDirectory}/*.cpp
116 ${testDirectory}/*.h)
117 LIST (REMOVE_ITEM currentTestSources ${TESTS_SOURCES})
118 LIST(APPEND testFilesToFormat ${currentTestSources})
119 # LIST (REMOVE_ITEM currentTestSources ${TESTS_HEADERS})
120
121 ADD_EXECUTABLE(${testName} ${testFile} ${currentTestSources})
122 set_property(TARGET ${testName} PROPERTY CXX_STANDARD 14)
123 set_property(TARGET ${testName} PROPERTY CXX_STANDARD_REQUIRED ON)
124 TARGET_LINK_LIBRARIES( ${testName} ${TEST_LIBRARIES} )
125 qt5_use_modules(${testName} Test)
126
127 ADD_TEST( NAME ${testName} COMMAND ${testName} )
128
129 SCIQLOP_COPY_TO_TARGET(RUNTIME ${testName} ${EXTERN_SHARED_LIBRARIES})
130 ENDFOREACH( testFile )
131
132 LIST(APPEND testFilesToFormat ${TESTS_SOURCES})
133 LIST(APPEND testFilesToFormat ${TESTS_HEADERS})
134 LIST(APPEND FORMATTING_INPUT_FILES ${testFilesToFormat})
135 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
136
137 ADD_DEFINITIONS(-DAMDA_TESTS_RESOURCES_DIR="${TESTS_RESOURCES_DIR}")
138 ENDIF(BUILD_TESTS)
139
140 #
141 # Set the files that must be formatted by clang-format.
142 #
143 LIST (APPEND FORMATTING_INPUT_FILES ${MODULE_SOURCES})
144 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
145
146 #
147 # Set the directories that doxygen must browse to generate the
148 # documentation.
149 #
150 # Source directories:
151 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/docs")
152 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
153 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_INPUT_DIRS)
154 # Source directories to exclude from the documentation generation
155 #LIST (APPEND DOXYGEN_EXCLUDE_PATTERNS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir/*")
156 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_EXCLUDE_PATTERNS)
157
158 #
159 # Set the directories with the sources to analyze and propagate the
160 # modification to the parent scope
161 #
162 # Source directories to analyze:
163 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
164 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
165 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_INPUT_DIRS)
166 # Source directories to exclude from the analysis
167 #LIST (APPEND ANALYSIS_EXCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir")
168 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_EXCLUDE_DIRS)
@@ -3,6 +3,8
3
3
4 #include "AmdaGlobal.h"
4 #include "AmdaGlobal.h"
5
5
6 #include <Data/DataSeriesType.h>
7
6 #include <QLoggingCategory>
8 #include <QLoggingCategory>
7
9
8 #include <memory>
10 #include <memory>
@@ -12,10 +14,8 class IDataSeries;
12 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParser)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParser)
13
15
14 struct SCIQLOP_AMDA_EXPORT AmdaResultParser {
16 struct SCIQLOP_AMDA_EXPORT AmdaResultParser {
15 enum class ValueType { SCALAR, SPECTROGRAM, VECTOR, UNKNOWN };
16
17 static std::shared_ptr<IDataSeries> readTxt(const QString &filePath,
17 static std::shared_ptr<IDataSeries> readTxt(const QString &filePath,
18 ValueType valueType) noexcept;
18 DataSeriesType valueType) noexcept;
19 };
19 };
20
20
21 #endif // SCIQLOP_AMDARESULTPARSER_H
21 #endif // SCIQLOP_AMDARESULTPARSER_H
@@ -20,14 +20,14 amdaplugin_resources_files = [
20 'resources/amdaresources.qrc'
20 'resources/amdaresources.qrc'
21 ]
21 ]
22
22
23 amdaplugin_inc = include_directories(['include', '../../plugin/include'])
23 amdaplugin_inc = include_directories(['include'])
24
24
25 moc_gen = generator(moc,
25 moc_gen = generator(moc,
26 output : 'moc_@BASENAME@.cpp',
26 output : 'moc_@BASENAME@.cpp',
27 arguments : ['@INPUT@',
27 arguments : ['@INPUT@',
28 '-DSCIQLOP_PLUGIN_JSON_FILE_PATH="'+meson.source_root()+'/plugins/amda/resources/amda.json"',
28 '-DSCIQLOP_PLUGIN_JSON_FILE_PATH="'+meson.source_root()+'/plugins/amda/resources/amda.json"',
29 '-I', meson.current_source_dir()+'/include',
29 '-I', meson.current_source_dir()+'/include',
30 '-I', meson.current_source_dir()+'/../../plugin/include',
30 '-I', meson.current_source_dir()+'/../../core/include/',
31 '-o', '@OUTPUT@'])
31 '-o', '@OUTPUT@'])
32
32
33 rcc_gen = generator(rcc,
33 rcc_gen = generator(rcc,
@@ -39,21 +39,6 QString dateFormat(double sqpRange) noexcept
39 return dateTime.toString(AMDA_TIME_FORMAT);
39 return dateTime.toString(AMDA_TIME_FORMAT);
40 }
40 }
41
41
42 AmdaResultParser::ValueType valueType(const QString &valueType)
43 {
44 if (valueType == QStringLiteral("scalar")) {
45 return AmdaResultParser::ValueType::SCALAR;
46 }
47 else if (valueType == QStringLiteral("spectrogram")) {
48 return AmdaResultParser::ValueType::SPECTROGRAM;
49 }
50 else if (valueType == QStringLiteral("vector")) {
51 return AmdaResultParser::ValueType::VECTOR;
52 }
53 else {
54 return AmdaResultParser::ValueType::UNKNOWN;
55 }
56 }
57
42
58 } // namespace
43 } // namespace
59
44
@@ -171,7 +156,8 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVa
171
156
172 // Retrieves the data type that determines whether the expected format for the result file is
157 // Retrieves the data type that determines whether the expected format for the result file is
173 // scalar, vector...
158 // scalar, vector...
174 auto productValueType = valueType(data.value(AMDA_DATA_TYPE_KEY).toString());
159 auto productValueType
160 = DataSeriesTypeUtils::fromString(data.value(AMDA_DATA_TYPE_KEY).toString());
175
161
176 // /////////// //
162 // /////////// //
177 // Creates URL //
163 // Creates URL //
@@ -24,16 +24,16 bool isCommentLine(const QString &line)
24 * @param valueType the type of values expected in the AMDA file (scalars, vectors, spectrograms...)
24 * @param valueType the type of values expected in the AMDA file (scalars, vectors, spectrograms...)
25 * @return the helper created
25 * @return the helper created
26 */
26 */
27 std::unique_ptr<IAmdaResultParserHelper> createHelper(AmdaResultParser::ValueType valueType)
27 std::unique_ptr<IAmdaResultParserHelper> createHelper(DataSeriesType valueType)
28 {
28 {
29 switch (valueType) {
29 switch (valueType) {
30 case AmdaResultParser::ValueType::SCALAR:
30 case DataSeriesType::SCALAR:
31 return std::make_unique<ScalarParserHelper>();
31 return std::make_unique<ScalarParserHelper>();
32 case AmdaResultParser::ValueType::SPECTROGRAM:
32 case DataSeriesType::SPECTROGRAM:
33 return std::make_unique<SpectrogramParserHelper>();
33 return std::make_unique<SpectrogramParserHelper>();
34 case AmdaResultParser::ValueType::VECTOR:
34 case DataSeriesType::VECTOR:
35 return std::make_unique<VectorParserHelper>();
35 return std::make_unique<VectorParserHelper>();
36 case AmdaResultParser::ValueType::UNKNOWN:
36 case DataSeriesType::UNKNOWN:
37 // Invalid case
37 // Invalid case
38 break;
38 break;
39 }
39 }
@@ -82,9 +82,9 void readResults(IAmdaResultParserHelper &helper, QTextStream &stream)
82 } // namespace
82 } // namespace
83
83
84 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
84 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
85 ValueType valueType) noexcept
85 DataSeriesType type) noexcept
86 {
86 {
87 if (valueType == ValueType::UNKNOWN) {
87 if (type == DataSeriesType::UNKNOWN) {
88 qCCritical(LOG_AmdaResultParser())
88 qCCritical(LOG_AmdaResultParser())
89 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
89 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
90 return nullptr;
90 return nullptr;
@@ -110,7 +110,7 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
110 return nullptr;
110 return nullptr;
111 }
111 }
112
112
113 auto helper = createHelper(valueType);
113 auto helper = createHelper(type);
114 Q_ASSERT(helper != nullptr);
114 Q_ASSERT(helper != nullptr);
115
115
116 // Reads header file to retrieve properties
116 // Reads header file to retrieve properties
@@ -67,14 +67,18 void FuzzingState::synchronizeVariable(VariableId variableId, SyncGroupId syncGr
67 return;
67 return;
68 }
68 }
69
69
70 // Registers variable into sync group: if it's the first variable, sets the variable range as
70 // Registers variable into sync group
71 // the sync group range
72 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
71 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
72 auto &variableState = m_VariablesPool.at(variableId);
73 syncGroup.m_Variables.insert(variableId);
73 syncGroup.m_Variables.insert(variableId);
74 if (syncGroup.m_Variables.size() == 1) {
74 if (syncGroup.m_Variables.size() == 1) {
75 auto &variableState = m_VariablesPool.at(variableId);
75 // If it's the first variable, sets the variable range as the sync group range
76 syncGroup.m_Range = variableState.m_Range;
76 syncGroup.m_Range = variableState.m_Range;
77 }
77 }
78 else {
79 // If a variable is added to an existing group, sets its range to the group's range
80 variableState.m_Range = syncGroup.m_Range;
81 }
78 }
82 }
79
83
80 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
84 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
@@ -97,13 +101,18 void FuzzingState::updateRanges(VariableId variableId, const SqpRange &newRange)
97 auto syncGroupId = this->syncGroupId(variableId);
101 auto syncGroupId = this->syncGroupId(variableId);
98
102
99 // Retrieves the variables to update:
103 // Retrieves the variables to update:
100 // - if the variable is synchronized to others, updates all synchronized variables
104 // - if the variable is synchronized to others, updates the range of the group and of all
105 // synchronized variables
101 // - otherwise, updates only the variable
106 // - otherwise, updates only the variable
102 auto variablesToUpdate = syncGroupId.isNull() ? std::set<VariableId>{variableId}
107 if (syncGroupId.isNull()) {
103 : m_SyncGroupsPool.at(syncGroupId).m_Variables;
104
105 // Sets new range
106 for (const auto &variableId : variablesToUpdate) {
107 m_VariablesPool.at(variableId).m_Range = newRange;
108 m_VariablesPool.at(variableId).m_Range = newRange;
108 }
109 }
110 else {
111 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
112 syncGroup.m_Range = newRange;
113
114 for (const auto &variableId : syncGroup.m_Variables) {
115 m_VariablesPool.at(variableId).m_Range = newRange;
116 }
117 }
109 }
118 }
@@ -176,6 +176,9 struct SynchronizeOperation : public IFuzzingOperation {
176
176
177 // Updates state
177 // Updates state
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
179
180 variableController.onRequestDataLoading({variableState.m_Variable}, variableState.m_Range,
181 false);
179 }
182 }
180 };
183 };
181
184
@@ -197,7 +200,7 struct DesynchronizeOperation : public IFuzzingOperation {
197 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
200 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
198 << "from synchronization group" << syncGroupId
201 << "from synchronization group" << syncGroupId
199 << "...";
202 << "...";
200 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
203 variableController.desynchronize(variableState.m_Variable, syncGroupId);
201
204
202 // Updates state
205 // Updates state
203 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
206 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
@@ -96,7 +96,7 public:
96 auto dataHoleIt = std::adjacent_find(
96 auto dataHoleIt = std::adjacent_find(
97 dataIts.first, dataIts.second, [](const auto &it1, const auto &it2) {
97 dataIts.first, dataIts.second, [](const auto &it1, const auto &it2) {
98 /// @todo: validate resolution
98 /// @todo: validate resolution
99 return std::abs(it1.x() - it2.x()) > 2 * (LOCALHOST_SERVER_RESOLUTION - 1);
99 return std::abs(it1.x() - it2.x()) > 2 * LOCALHOST_SERVER_RESOLUTION;
100 });
100 });
101
101
102 if (dataHoleIt != dataIts.second) {
102 if (dataHoleIt != dataIts.second) {
@@ -115,7 +115,7 void TestAmdaAcquisition::testAcquisition()
115 // Retrieves data file
115 // Retrieves data file
116 QFETCH(QString, dataFilename);
116 QFETCH(QString, dataFilename);
117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
118 auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR);
118 auto results = AmdaResultParser::readTxt(filePath, DataSeriesType::SCALAR);
119
119
120 /// Lambda used to validate a variable at each step
120 /// Lambda used to validate a variable at each step
121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const SqpRange &range) {
121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const SqpRange &range) {
@@ -370,6 +370,10 void TestAmdaFuzzing::testFuzzing()
370
370
371 int main(int argc, char *argv[])
371 int main(int argc, char *argv[])
372 {
372 {
373 // Increases the test function timeout (which is 5 minutes by default) to 12 hours
374 // https://stackoverflow.com/questions/42655932/setting-timeout-to-qt-test
375 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
376
373 QLoggingCategory::setFilterRules(
377 QLoggingCategory::setFilterRules(
374 "*.warning=false\n"
378 "*.warning=false\n"
375 "*.info=false\n"
379 "*.info=false\n"
@@ -187,7 +187,7 private:
187 }
187 }
188
188
189 template <typename T>
189 template <typename T>
190 void testRead(AmdaResultParser::ValueType valueType)
190 void testRead(DataSeriesType valueType)
191 {
191 {
192 QFETCH(QString, inputFileName);
192 QFETCH(QString, inputFileName);
193 QFETCH(ExpectedResults<T>, expectedResults);
193 QFETCH(ExpectedResults<T>, expectedResults);
@@ -319,7 +319,7 void TestAmdaResultParser::testReadScalarTxt_data()
319
319
320 void TestAmdaResultParser::testReadScalarTxt()
320 void TestAmdaResultParser::testReadScalarTxt()
321 {
321 {
322 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
322 testRead<ScalarSeries>(DataSeriesType::SCALAR);
323 }
323 }
324
324
325 void TestAmdaResultParser::testReadSpectrogramTxt_data()
325 void TestAmdaResultParser::testReadSpectrogramTxt_data()
@@ -533,7 +533,7 void TestAmdaResultParser::testReadSpectrogramTxt_data()
533
533
534 void TestAmdaResultParser::testReadSpectrogramTxt()
534 void TestAmdaResultParser::testReadSpectrogramTxt()
535 {
535 {
536 testRead<SpectrogramSeries>(AmdaResultParser::ValueType::SPECTROGRAM);
536 testRead<SpectrogramSeries>(DataSeriesType::SPECTROGRAM);
537 }
537 }
538
538
539 void TestAmdaResultParser::testReadVectorTxt_data()
539 void TestAmdaResultParser::testReadVectorTxt_data()
@@ -572,7 +572,7 void TestAmdaResultParser::testReadVectorTxt_data()
572
572
573 void TestAmdaResultParser::testReadVectorTxt()
573 void TestAmdaResultParser::testReadVectorTxt()
574 {
574 {
575 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
575 testRead<VectorSeries>(DataSeriesType::VECTOR);
576 }
576 }
577
577
578 QTEST_MAIN(TestAmdaResultParser)
578 QTEST_MAIN(TestAmdaResultParser)
@@ -1,160 +1,29
1 ## mockplugin - CMakeLists.txt
1 include_directories(include)
2 STRING(TOLOWER ${CMAKE_PROJECT_NAME} LIBRARY_PREFFIX)
2 FILE (GLOB_RECURSE mockplugin_SRCS
3 SET(SQPMOCKPLUGIN_LIBRARY_NAME "${LIBRARY_PREFFIX}_mockplugin${DEBUG_SUFFIX}")
3 include/*.h
4 SET(SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
4 src/*.cpp
5 SET(INCLUDES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
5 resources/*.qrc
6 SET(RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources")
6 )
7 SET(TESTS_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests-resources")
8
7
9 # Include mockplugin directory
8 add_definitions(-DQT_PLUGIN)
10 INCLUDE_DIRECTORIES(${INCLUDES_DIR})
9 add_definitions(-DPLUGIN_JSON_FILE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/mockplugin.json")
11 INCLUDE_DIRECTORIES(${RESOURCES_DIR})
10 if(NOT BUILD_SHARED_LIBS)
11 add_definitions(-DQT_STATICPLUGIN)
12 endif()
12
13
13 #
14 add_library(mockplugin ${mockplugin_SRCS})
14 # Find Qt modules
15 SET_TARGET_PROPERTIES(mockplugin PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
15 #
16 SCIQLOP_FIND_QT(Core Widgets)
17
16
18 #
17 target_link_libraries(mockplugin sciqlopgui)
19 # Find dependent libraries
20 # ========================
21
18
22 # sciqlop plugin
19 install(TARGETS mockplugin
23 find_package(sciqlop-plugin)
20 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop
24 INCLUDE_DIRECTORIES(${SCIQLOP-PLUGIN_INCLUDE_DIR})
21 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop
22 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
25
23
26 # sciqlop core
24 include(sciqlop_tests)
27 find_package(sciqlop-core)
28 INCLUDE_DIRECTORIES(${SCIQLOP-CORE_INCLUDE_DIR})
29 list(APPEND LIBRARIES ${SCIQLOP-CORE_LIBRARIES})
30
25
31 # sciqlop gui
26 add_definitions(-DMOCKPLUGIN_TESTS_RESOURCES_DIR="${CMAKE_CURRENT_LIST_DIR}/tests-resources")
32 find_package(sciqlop-gui)
33 INCLUDE_DIRECTORIES(${SCIQLOP-GUI_INCLUDE_DIR})
34 list(APPEND LIBRARIES ${SCIQLOP-GUI_LIBRARIES})
35
27
36 # Description file
28 declare_test(TestCosinusAcquisition TestCosinusAcquisition tests/TestCosinusAcquisition.cpp "mockplugin;Qt5::Test")
37 FILE (GLOB_RECURSE PLUGIN_FILE ${RESOURCES_DIR}/mockplugin.json)
38
29
39 #
40 # Compile the library
41 #
42
43 ADD_DEFINITIONS(-DMOCKPLUGIN_LIB)
44
45 FILE (GLOB_RECURSE MODULE_SOURCES
46 ${INCLUDES_DIR}/*.h
47 ${SOURCES_DIR}/*.c
48 ${SOURCES_DIR}/*.cpp
49 ${SOURCES_DIR}/*.h
50 ${PLUGIN_FILE})
51
52 ADD_LIBRARY(${SQPMOCKPLUGIN_LIBRARY_NAME} ${MODULE_SOURCES})
53 set_property(TARGET ${SQPMOCKPLUGIN_LIBRARY_NAME} PROPERTY CXX_STANDARD 14)
54 set_property(TARGET ${SQPMOCKPLUGIN_LIBRARY_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
55
56 INSTALL(TARGETS ${SQPMOCKPLUGIN_LIBRARY_NAME}
57 RUNTIME DESTINATION ${INSTALL_BINARY_DIR}
58 LIBRARY DESTINATION ${INSTALL_PLUGINS_LIBRARY_DIR}
59 ARCHIVE DESTINATION ${INSTALL_PLUGINS_LIBRARY_DIR}
60 )
61
62
63 TARGET_LINK_LIBRARIES(${SQPMOCKPLUGIN_LIBRARY_NAME} ${LIBRARIES})
64 qt5_use_modules(${SQPMOCKPLUGIN_LIBRARY_NAME} Core Widgets)
65
66 add_dependencies(${SQPMOCKPLUGIN_LIBRARY_NAME} ${SQPPLUGIN_LIBRARY_NAME} ${SQPGUI_LIBRARY_NAME} ${SQPCORE_LIBRARY_NAME})
67
68 # From cmake documentation: http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
69 # Entries in the COMPILE_DEFINITIONS are prefixed with -D or /D and added to the compile line in an unspecified order.
70 # The DEFINE_SYMBOL target property is also added as a compile definition as a special convenience case for SHARED and MODULE library targets
71 IF(BUILD_SHARED_LIBS)
72 SET_TARGET_PROPERTIES(${SQPMOCKPLUGIN_LIBRARY_NAME} PROPERTIES COMPILE_DEFINITIONS "SCIQLOP_EXPORT")
73 ELSE()
74 TARGET_COMPILE_DEFINITIONS(${SQPMOCKPLUGIN_LIBRARY_NAME} PUBLIC "SCIQLOP_STATIC_LIBRARIES")
75 ENDIF()
76
77 # Set the variable to parent scope so that the other projects can copy the
78 # dependent shared libraries
79 SCIQLOP_SET_TO_PARENT_SCOPE(SQPMOCKPLUGIN_LIBRARY_NAME)
80
81 # Copy extern shared libraries to the lib folder
82 SCIQLOP_COPY_TO_TARGET(LIBRARY ${SQPMOCKPLUGIN_LIBRARY_NAME} ${EXTERN_SHARED_LIBRARIES})
83
84 # Add the files to the list of files to be analyzed
85 LIST(APPEND CHECKSTYLE_INPUT_FILES ${MODULE_SOURCES})
86 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_INPUT_FILES)
87 # Vera++ exclusion files
88 #LIST(APPEND CHECKSTYLE_EXCLUSION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vera-exclusions/exclusions.txt)
89 SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_EXCLUSION_FILES)
90
91 #
92 # Compile the tests
93 #
94 IF(BUILD_TESTS)
95 INCLUDE_DIRECTORIES(${SOURCES_DIR})
96 FILE (GLOB_RECURSE TESTS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Test*.cpp)
97 FILE (GLOB_RECURSE TESTS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/Test*.h)
98 SET( TEST_LIBRARIES ${SQPMOCKPLUGIN_LIBRARY_NAME})
99
100 FOREACH( testFile ${TESTS_SOURCES} )
101 GET_FILENAME_COMPONENT( testDirectory ${testFile} DIRECTORY )
102 GET_FILENAME_COMPONENT( testName ${testFile} NAME_WE )
103
104 # Add to the list of sources files all the sources in the same
105 # directory that aren't another test
106 FILE (GLOB currentTestSources
107 ${testDirectory}/*.c
108 ${testDirectory}/*.cpp
109 ${testDirectory}/*.h)
110 LIST (REMOVE_ITEM currentTestSources ${TESTS_SOURCES})
111 # LIST (REMOVE_ITEM currentTestSources ${TESTS_HEADERS})
112
113 ADD_EXECUTABLE(${testName} ${testFile} ${currentTestSources})
114 set_property(TARGET ${testName} PROPERTY CXX_STANDARD 14)
115 set_property(TARGET ${testName} PROPERTY CXX_STANDARD_REQUIRED ON)
116 TARGET_LINK_LIBRARIES( ${testName} ${TEST_LIBRARIES} )
117 qt5_use_modules(${testName} Test)
118
119 ADD_TEST( NAME ${testName} COMMAND ${testName} )
120
121 SCIQLOP_COPY_TO_TARGET(RUNTIME ${testName} ${EXTERN_SHARED_LIBRARIES})
122 ENDFOREACH( testFile )
123
124 LIST(APPEND testFilesToFormat ${TESTS_SOURCES})
125 LIST(APPEND testFilesToFormat ${TESTS_HEADERS})
126 LIST(APPEND FORMATTING_INPUT_FILES ${testFilesToFormat})
127 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
128
129 ADD_DEFINITIONS(-DMOCKPLUGIN_TESTS_RESOURCES_DIR="${TESTS_RESOURCES_DIR}")
130 ENDIF(BUILD_TESTS)
131
132 #
133 # Set the files that must be formatted by clang-format.
134 #
135 LIST (APPEND FORMATTING_INPUT_FILES ${MODULE_SOURCES})
136 SCIQLOP_SET_TO_PARENT_SCOPE(FORMATTING_INPUT_FILES)
137
138 #
139 # Set the directories that doxygen must browse to generate the
140 # documentation.
141 #
142 # Source directories:
143 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/docs")
144 LIST (APPEND DOXYGEN_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
145 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_INPUT_DIRS)
146 # Source directories to exclude from the documentation generation
147 #LIST (APPEND DOXYGEN_EXCLUDE_PATTERNS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir/*")
148 SCIQLOP_SET_TO_PARENT_SCOPE(DOXYGEN_EXCLUDE_PATTERNS)
149
150 #
151 # Set the directories with the sources to analyze and propagate the
152 # modification to the parent scope
153 #
154 # Source directories to analyze:
155 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src")
156 LIST (APPEND ANALYSIS_INPUT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
157 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_INPUT_DIRS)
158 # Source directories to exclude from the analysis
159 #LIST (APPEND ANALYSIS_EXCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/path/to/subdir")
160 SCIQLOP_SET_TO_PARENT_SCOPE(ANALYSIS_EXCLUDE_DIRS)
@@ -9,7 +9,7 mockplugin_sources = [
9 'src/MockPlugin.cpp'
9 'src/MockPlugin.cpp'
10 ]
10 ]
11
11
12 mockplugin_inc = include_directories(['include', '../../plugin/include'])
12 mockplugin_inc = include_directories(['include'])
13
13
14
14
15 gen = generator(moc,
15 gen = generator(moc,
@@ -17,7 +17,7 gen = generator(moc,
17 arguments : ['@INPUT@',
17 arguments : ['@INPUT@',
18 '-DPLUGIN_JSON_FILE_PATH="'+meson.source_root()+'/plugins/mockplugin/resources/mockplugin.json"',
18 '-DPLUGIN_JSON_FILE_PATH="'+meson.source_root()+'/plugins/mockplugin/resources/mockplugin.json"',
19 '-I', meson.current_source_dir()+'/include',
19 '-I', meson.current_source_dir()+'/include',
20 '-I', meson.current_source_dir()+'/../../plugin/include',
20 '-I', meson.current_source_dir()+'/../../core/include/',
21 '-o', '@OUTPUT@'])
21 '-o', '@OUTPUT@'])
22
22
23 mockplugin_moc_files = gen.process(mockplugin_moc_headers)
23 mockplugin_moc_files = gen.process(mockplugin_moc_headers)
@@ -43,4 +43,4 foreach unit_test : tests
43 cpp_args : ['-DMOCKPLUGIN_TESTS_RESOURCES_DIR="'+meson.current_source_dir()+'/tests-resources"'],
43 cpp_args : ['-DMOCKPLUGIN_TESTS_RESOURCES_DIR="'+meson.current_source_dir()+'/tests-resources"'],
44 dependencies : [sciqlop_core, sciqlop_gui, qt5test])
44 dependencies : [sciqlop_core, sciqlop_gui, qt5test])
45 test(unit_test[2], test_exe, args: ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test[1])], timeout: 3 * 60)
45 test(unit_test[2], test_exe, args: ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test[1])], timeout: 3 * 60)
46 endforeach No newline at end of file
46 endforeach
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now