##// END OF EJS Templates
Started PySide2 migration, builds with CMake and produces a working binary...
jeandet -
r1477:70de8bd3d575
parent child
Show More
@@ -0,0 +1,79
1 find_package(PythonLibs 3 REQUIRED)
2 find_package(PythonInterp 3 REQUIRED)
3 find_package(PySide2 REQUIRED)
4 find_package(Shiboken2 REQUIRED)
5 include(PythonInfo)
6 find_python_site_packages(PYTHON_SITE_PACKAGES)
7
8 set(BINDINGS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
9 set(BINDINGS_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}")
10
11 configure_file("${BINDINGS_SRC_DIR}/bindings.xml" "${BINDINGS_BUILD_DIR}/bindings.xml" COPYONLY)
12 configure_file("${BINDINGS_SRC_DIR}/main.py" "${BINDINGS_BUILD_DIR}/main.py" COPYONLY)
13
14 execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${BINDINGS_SRC_DIR}/src_list.py" cmake "${BINDINGS_BUILD_DIR}" OUTPUT_VARIABLE BINDINGS_SOURCE)
15
16 set_property(SOURCE ${BINDINGS_SOURCE} PROPERTY SKIP_AUTOGEN ON)
17
18 list(APPEND BINDINGS_INCLUDE_DIRS
19 ${PYTHON_INCLUDE_DIRS}
20 ${Qt5Core_INCLUDE_DIRS}
21 ${Qt5Widgets_INCLUDE_DIRS}
22 ${Qt5Gui_INCLUDE_DIRS}
23 ${CMAKE_CURRENT_SOURCE_DIR}/../../gui/include
24 ${CMAKE_CURRENT_SOURCE_DIR}/../../core/include
25 ${CMAKE_CURRENT_SOURCE_DIR}/../../core/external/TimeSeries/include
26 )
27 list(REMOVE_DUPLICATES BINDINGS_INCLUDE_DIRS)
28 foreach(DIR ${BINDINGS_INCLUDE_DIRS})
29 list(APPEND BINDINGS_INCLUDE_DIRS_ARGS "-I${DIR}")
30 endforeach()
31
32 set(SHIBOKEN_OPTIONS --generator-set=shiboken
33 --enable-parent-ctor-heuristic
34 --enable-return-value-heuristic
35 --use-isnull-as-nb_nonzero
36 --avoid-protected-hack
37 --enable-pyside-extensions
38 -std=c++17)
39 add_custom_command(
40 OUTPUT ${BINDINGS_SOURCE}
41 COMMAND Shiboken2::shiboken2 ${SHIBOKEN_OPTIONS}
42 ${BINDINGS_INCLUDE_DIRS_ARGS}
43 --typesystem-paths=${PYSIDE_TYPESYSTEMS}
44 --output-directory=${CMAKE_CURRENT_BINARY_DIR}
45 ${CMAKE_CURRENT_SOURCE_DIR}/bindings.h ${CMAKE_CURRENT_SOURCE_DIR}/bindings.xml
46
47 DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/bindings.xml"
48 IMPLICIT_DEPENDS CXX "${CMAKE_CURRENT_SOURCE_DIR}/bindings.h"
49 WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
50 COMMENT "Generating Python bindings with shiboken2")
51
52 include_directories(
53 ${PYSIDE_INCLUDE_DIR}/QtCore
54 ${PYSIDE_INCLUDE_DIR}/QtGui
55 ${PYSIDE_INCLUDE_DIR}/QtWidgets)
56
57 include_directories(
58 ${PYTHON_SITE_PACKAGES}/numpy/core/include/
59 ${PYTHON_INCLUDE_DIRS}
60 ${SHIBOKEN_INCLUDE_DIR}
61 ${PYSIDE_INCLUDE_DIR}
62 ${PYSIDE_INCLUDE_DIR}/QtCore
63 ${PYSIDE_INCLUDE_DIR}/QtGui
64 ${PYSIDE_INCLUDE_DIR}/QtWidgets)
65
66 add_library(SciQLopBindings MODULE ${BINDINGS_SOURCE} numpy_wrappers.h)
67 set_target_properties(
68 SciQLopBindings
69 PROPERTIES
70 PREFIX ""
71 OUTPUT_NAME "SciQLopBindings"
72 )
73 target_link_libraries(SciQLopBindings sciqlopapp)
74 target_link_libraries(SciQLopBindings Shiboken2::libshiboken)
75 target_link_libraries(SciQLopBindings PySide2::pyside2)
76
77 add_executable(debug_sciqlop_app main.cpp )
78 find_package (Python3 COMPONENTS Development)
79 target_link_libraries(debug_sciqlop_app PRIVATE Python3::Python)
@@ -0,0 +1,16
1 #pragma once
2 #include <Data/IDataProvider.h>
3
4 class PyDataProvider : public IDataProvider
5 {
6 public:
7 PyDataProvider() {}
8
9 virtual TimeSeries::ITimeSerie getData(const std::string& key, double start_time, double stop_time)
10 {}
11
12 virtual TimeSeries::ITimeSerie* getData(const DataProviderParameters& parameters)
13 {
14 return nullptr;
15 }
16 };
@@ -0,0 +1,12
1 #ifndef SCIQLOP_BINDINGS_H
2 #define SCIQLOP_BINDINGS_H
3 #define QT_ANNOTATE_ACCESS_SPECIFIER(a) __attribute__((annotate(#a)))
4 #include "../include/MainWindow.h"
5 #include "PyDataProvider.h"
6 #include "numpy_wrappers.h"
7 #include <Data/IDataProvider.h>
8 #include <Data/ScalarTimeSerie.h>
9 #include <SqpApplication.h>
10
11
12 #endif // SCIQLOP_BINDINGS_H
@@ -0,0 +1,72
1 <?xml version="1.0"?>
2 <typesystem package="SciQLopBindings">
3 <load-typesystem name="typesystem_core.xml" generate="no" />
4 <load-typesystem name="typesystem_gui.xml" generate="no" />
5 <load-typesystem name="typesystem_widgets.xml" generate="no" />
6 <primitive-type name="std::string"/>
7 <primitive-type name="std::size_t"/>
8 <container-type name="std::vector" type="vector">
9 <include file-name="vector" location="global"/>
10 <conversion-rule>
11 <native-to-target>
12 %INTYPE::size_type vectorSize = %in.size();
13 PyObject* %out = PyList_New((int) vectorSize);
14 for (%INTYPE::size_type idx = 0; idx &lt; vectorSize; ++idx) {
15 %INTYPE_0 cppItem(%in[idx]);
16 PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
17 }
18 return %out;
19 </native-to-target>
20 <target-to-native>
21 <add-conversion type="PySequence">
22 Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0));
23 int vectorSize = PySequence_Fast_GET_SIZE(seq.object());
24 %out.reserve(vectorSize);
25 for (int idx = 0; idx &lt; vectorSize; ++idx ) {
26 PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), idx);
27 %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
28 %out.push_back(cppItem);
29 }
30 </add-conversion>
31 </target-to-native>
32 </conversion-rule>
33 </container-type>
34 <object-type name="MainWindow" />
35 <object-type name="SqpApplication">
36 <modify-function signature="SqpApplication(int&amp;,char**)" access="private"/>
37 </object-type>
38 <object-type name="PyDataProvider" />
39 <function signature="SqpApplication_ctor()"/>
40 <function signature="init_resources()"/>
41 <primitive-type name="NpArray" target-lang-api-name="PyObject">
42 <include file-name="numpy_wrappers.h" location="local"/>
43 <conversion-rule>
44 <native-to-target>
45 return %in.py_object();
46 </native-to-target>
47 <target-to-native>
48 <add-conversion type="PyObject" check="NpArray::isNpArray(%in)">
49 %out = %OUTTYPE(%in);
50 </add-conversion>
51 </target-to-native>
52 </conversion-rule>
53 </primitive-type>
54 <function signature="load_plugins(const SqpApplication&amp;)"/>
55 <object-type name="ScalarTimeSerie">
56 <add-function signature="ScalarTimeSerie(NpArray&amp;,NpArray&amp;)" return-type="ScalarTimeSerie">
57 <inject-code class="target">
58 %BEGIN_ALLOW_THREADS
59 %0 = new ScalarTimeSerieWrapper();
60 %0.set_data(%1.to_std_vect(),%2.to_std_vect());
61 %END_ALLOW_THREADS
62 </inject-code>
63 </add-function>
64 <add-function signature="size()" return-type="int" access="public" static="no">
65 <inject-code class="target">
66 %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME();
67 %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
68 </inject-code>
69 </add-function>
70 </object-type>
71 <function signature="test_np_array(NpArray&amp;)"/>
72 </typesystem>
@@ -0,0 +1,26
1 #include <fstream>
2 #include <iostream>
3 #define PY_SSIZE_T_CLEAN
4 #define Py_DEBUG
5 #include <Python.h>
6
7 int main(int argc, char** argv)
8 {
9 wchar_t* program = Py_DecodeLocale(argv[0], NULL);
10 if (program == NULL)
11 {
12 fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
13 exit(1);
14 }
15 Py_SetProgramName(program); /* optional but recommended */
16 Py_Initialize();
17 std::ifstream t(argv[1]);
18 std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
19 PyRun_SimpleString(str.data());
20 if (Py_FinalizeEx() < 0)
21 {
22 exit(120);
23 }
24 PyMem_RawFree(program);
25 return 0;
26 }
@@ -0,0 +1,102
1 # This Python file uses the following encoding: utf-8
2 import os
3 print(os.getcwd())
4 import sys
5 from PySide2.QtWidgets import QApplication, QMainWindow, QDockWidget
6 from PySide2.QtCore import QSize, Qt
7 from PySide2 import QtGui
8 import os
9 from SciQLopBindings import SqpApplication, MainWindow, init_resources, load_plugins, SqpApplication_ctor
10 from qtconsole.rich_ipython_widget import RichJupyterWidget
11 from qtconsole.inprocess import QtInProcessKernelManager
12
13
14 class IPythonWidget(RichJupyterWidget):
15 """Live IPython console widget.
16
17 .. image:: img/IPythonWidget.png
18
19 :param custom_banner: Custom welcome message to be printed at the top of
20 the console.
21 """
22
23 def __init__(self, parent=None, custom_banner=None, *args, **kwargs):
24 if parent is not None:
25 kwargs["parent"] = parent
26 super(IPythonWidget, self).__init__(*args, **kwargs)
27 if custom_banner is not None:
28 self.banner = custom_banner
29 self.setWindowTitle(self.banner)
30 self.kernel_manager = kernel_manager = QtInProcessKernelManager()
31 kernel_manager.start_kernel()
32 self.kernel_client = kernel_client = self._kernel_manager.client()
33 kernel_client.start_channels()
34
35 def stop():
36 kernel_client.stop_channels()
37 kernel_manager.shutdown_kernel()
38 self.exit_requested.connect(stop)
39
40 def sizeHint(self):
41 """Return a reasonable default size for usage in :class:`PlotWindow`"""
42 return QSize(500, 300)
43
44 def pushVariables(self, variable_dict):
45 """ Given a dictionary containing name / value pairs, push those
46 variables to the IPython console widget.
47
48 :param variable_dict: Dictionary of variables to be pushed to the
49 console's interactive namespace (```{variable_name: object, …}```)
50 """
51 self.kernel_manager.kernel.shell.push(variable_dict)
52
53
54 class IPythonDockWidget(QDockWidget):
55 """Dock Widget including a :class:`IPythonWidget` inside
56 a vertical layout.
57
58 .. image:: img/IPythonDockWidget.png
59
60 :param available_vars: Dictionary of variables to be pushed to the
61 console's interactive namespace: ``{"variable_name": object, …}``
62 :param custom_banner: Custom welcome message to be printed at the top of
63 the console
64 :param title: Dock widget title
65 :param parent: Parent :class:`qt.QMainWindow` containing this
66 :class:`qt.QDockWidget`
67 """
68 def __init__(self, parent=None, available_vars=None, custom_banner=None,
69 title="Console"):
70 super(IPythonDockWidget, self).__init__(title, parent)
71
72 self.ipyconsole = IPythonWidget(custom_banner=custom_banner)
73
74 self.layout().setContentsMargins(0, 0, 0, 0)
75 self.setWidget(self.ipyconsole)
76
77 if available_vars is not None:
78 self.ipyconsole.pushVariables(available_vars)
79 self.ipyconsole.pushVariables({"blah":self})
80
81 def showEvent(self, event):
82 """Make sure this widget is raised when it is shown
83 (when it is first created as a tab in PlotWindow or when it is shown
84 again after hiding).
85 """
86 self.raise_()
87
88 def print_process_id():
89 print ('Process ID is:', os.getpid())
90
91
92 if __name__ == "__main__":
93 init_resources()
94 app = SqpApplication_ctor()
95 QtGui.qApp = app
96 load_plugins(app)
97 main_window = MainWindow()
98 term = IPythonDockWidget(available_vars={"app":app, "main_window":main_window}, custom_banner="SciQLop IPython Console ")
99 main_window.addDockWidget(Qt.BottomDockWidgetArea, term)
100 main_window.show()
101 sys.exit(app.exec_())
102
@@ -0,0 +1,19
1 #include "numpy_wrappers.h"
2
3 // ScalarTimeSerie ScalarTimeSerie_from_np(PyObject* time, PyObject* values)
4 //{
5 // assert(time);
6 // assert(values);
7 // assert(PyArray_NDIM(time) == 1);
8 // assert(PyArray_NDIM(values) == 1);
9 // assert(PyArray_ISFLOAT(time));
10 // assert(PyArray_ISFLOAT(values));
11 // assert(PyArray_DIM(time, 0) == PyArray_DIM(values, 0));
12 // assert(PyArray_IS_C_CONTIGUOUS(time));
13 // assert(PyArray_IS_C_CONTIGUOUS(values));
14 // int size = PyArray_DIM(time, 0);
15 // ScalarTimeSerie ts(size);
16 // for (int i = 0; i < size; i++)
17 // {
18 // }
19 //}
@@ -0,0 +1,178
1 #ifndef NUMPY_WRAPPERS_H
2 #define NUMPY_WRAPPERS_H
3 #include <Data/ScalarTimeSerie.h>
4 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
5 #if defined(slots) && (defined(__GNUC__) || defined(_MSC_VER) || defined(__clang__))
6 #pragma push_macro("slots")
7 #undef slots
8 extern "C"
9 {
10 /*
11 * Python 2 uses the "register" keyword, which is deprecated in C++ 11
12 * and forbidden in C++17.
13 */
14 #if defined(__clang__)
15 #pragma clang diagnostic push
16 #pragma clang diagnostic ignored "-Wdeprecated-register"
17 #endif
18
19 #include <Python.h>
20 #include <numpy/arrayobject.h>
21
22 #if defined(__clang__)
23 #pragma clang diagnostic pop
24 #endif
25 }
26 #else
27 #include <Python.h>
28 #include <numpy/arrayobject.h>
29 #endif
30 #include <assert.h>
31
32 inline int init_numpy()
33 {
34 import_array(); // PyError if not successful
35 return 0;
36 }
37 const static int numpy_initialized = init_numpy();
38 template <typename dest_type = PyObject>
39 struct PyObjectWrapper
40 {
41 private:
42 PyObject* _py_obj;
43
44 void inc_refcount()
45 {
46 if (_py_obj)
47 Py_IncRef(_py_obj);
48 }
49 void dec_refcount()
50 {
51 if (_py_obj)
52 Py_DecRef(_py_obj);
53 }
54
55 public:
56 PyObjectWrapper() : _py_obj { nullptr } {}
57 PyObjectWrapper(const PyObjectWrapper& other) : _py_obj { other._py_obj } { inc_refcount(); };
58 PyObjectWrapper(PyObjectWrapper&& other) : _py_obj { other._py_obj }
59 {
60 other._py_obj = nullptr;
61 }
62 PyObjectWrapper(PyObject* obj) : _py_obj { obj } { inc_refcount(); }
63 ~PyObjectWrapper() { dec_refcount(); }
64 PyObjectWrapper& operator=(PyObjectWrapper&& other)
65 {
66 this->_py_obj = other._py_obj;
67 other._py_obj = nullptr;
68 return *this;
69 }
70 PyObjectWrapper& operator=(const PyObjectWrapper& other)
71 {
72 dec_refcount();
73 this->_py_obj = other._py_obj;
74 inc_refcount();
75 return *this;
76 }
77
78 PyObject* py_object() { return _py_obj; }
79 inline dest_type* get() { return reinterpret_cast<dest_type*>(_py_obj); }
80 inline bool is_null() { return _py_obj == nullptr; }
81 };
82
83 struct NpArray
84 {
85 private:
86 PyObjectWrapper<PyArrayObject> _py_obj;
87 NpArray(NpArray& other) = delete;
88 NpArray(const NpArray& other) = delete;
89 NpArray(const NpArray&& other) = delete;
90
91 public:
92 static bool isNpArray(PyObject* obj)
93 {
94 return obj && PyArray_Check(reinterpret_cast<PyArrayObject*>(obj))
95 && PyArray_IS_C_CONTIGUOUS(reinterpret_cast<PyArrayObject*>(obj));
96 }
97 NpArray() : _py_obj { nullptr } {}
98 NpArray(NpArray&& other) : _py_obj { std::move(other._py_obj) } {}
99 explicit NpArray(PyObject* obj) : _py_obj { obj }
100 {
101 std::cout << "NpArray ctor" << std::endl;
102 assert(isNpArray(obj));
103 assert(PyArray_ISFLOAT(_py_obj.get()));
104 }
105
106 NpArray& operator=(const NpArray& other)
107 {
108 this->_py_obj = other._py_obj;
109 return *this;
110 }
111
112 NpArray& operator=(NpArray&& other)
113 {
114 this->_py_obj = std::move(other._py_obj);
115 return *this;
116 }
117
118 std::vector<std::size_t> shape()
119 {
120 std::vector<std::size_t> shape;
121 if (!_py_obj.is_null())
122 {
123 if (int ndim = PyArray_NDIM(_py_obj.get()); ndim > 0)
124 {
125 if (ndim < 10)
126 {
127 shape.resize(ndim);
128 std::copy_n(PyArray_SHAPE(_py_obj.get()), ndim, std::begin(shape));
129 }
130 }
131 }
132 return shape;
133 }
134
135 std::size_t flat_size()
136 {
137 auto s = this->shape();
138 return std::accumulate(std::cbegin(s), std::cend(s), 0);
139 }
140
141 double data(std::size_t pos)
142 {
143 if (!_py_obj.is_null())
144 {
145 return reinterpret_cast<double*>(PyArray_DATA(_py_obj.get()))[pos];
146 }
147 return nan("NAN");
148 }
149
150 std::vector<double> to_std_vect()
151 {
152 auto sz = flat_size();
153 std::vector<double> v(sz);
154 auto d_ptr = reinterpret_cast<double*>(PyArray_DATA(_py_obj.get()));
155 std::copy(d_ptr, d_ptr + sz, std::begin(v));
156 return v;
157 }
158
159 PyObject* py_object() { return _py_obj.py_object(); }
160 };
161
162 inline int test_np_array(NpArray& arr)
163 {
164 auto shape = arr.shape();
165 std::cout << "len(shape)=" << shape.size() << std::endl;
166 std::for_each(std::cbegin(shape), std::cend(shape), [](auto sz) {
167 static int i = 0;
168 std::cout << "shape[" << i++ << "]=" << sz << std::endl;
169 });
170 auto flatsize = std::accumulate(std::cbegin(shape), std::cend(shape), 0);
171 for (auto i = 0; i < flatsize; i++)
172 {
173 std::cout << "data[" << i << "]=" << arr.data(i) << std::endl;
174 }
175 return 1;
176 }
177
178 #endif //#ifndef NUMPY_WRAPPERS_H
@@ -0,0 +1,49
1 #!/bin/env python3
2 # taken from https://github.com/radareorg/cutter/blob/master/src/bindings/src_list.py
3
4
5 import os
6 import re
7 import sys
8
9
10 script_path = os.path.dirname(os.path.realpath(__file__))
11
12
13 def get_cpp_files_gen(args, include_package=True):
14 with open(os.path.join(script_path, "bindings.xml"),'r') as f:
15 txt = f.read()
16 package = re.findall("<typesystem *package=.*", txt)[0].split('"')[1]
17 types = re.findall('(.*object-type *name=.*|.*value-type *name=.*)', txt)
18 types = [t.split('"')[1] for t in types]
19
20 cpp_files_gen = [f"{package.lower()}_module_wrapper.cpp"]
21 cpp_files_gen.extend([f"{typename.lower()}_wrapper.cpp" for typename in types])
22
23 if include_package:
24 cpp_files_gen = [os.path.join(package, f) for f in cpp_files_gen]
25
26 if len(args) > 0:
27 cpp_files_gen = [os.path.join(args[0], f) for f in cpp_files_gen]
28
29 return cpp_files_gen
30
31
32 def cmd_cmake(args):
33 sys.stdout.write(";".join(get_cpp_files_gen(args)))
34
35
36 def cmd_qmake(args):
37 sys.stdout.write("\n".join(get_cpp_files_gen(args)) + "\n")
38
39
40 def cmd_meson(args):
41 sys.stdout.write(";".join(get_cpp_files_gen(args, include_package=False)))
42
43
44 cmds = {"cmake": cmd_cmake, "qmake": cmd_qmake, "meson": cmd_meson}
45
46 if len(sys.argv) < 2 or sys.argv[1] not in cmds:
47 print(f"""usage: {sys.argv[0]} [{"/".join(cmds.keys())}] [base path]""")
48 exit(1)
49 cmds[sys.argv[1]](sys.argv[2:])
@@ -0,0 +1,84
1
2 set(_module PySide2)
3
4 find_package(${_module} ${${_module}_FIND_VERSION} CONFIG QUIET)
5 set(_lib_target ${_module}::pyside2)
6
7 if(NOT ${_module}_FOUND)
8 include(PythonInfo)
9 find_python_site_packages(PYTHON_SITE_PACKAGES)
10 get_python_extension_suffix(PYTHON_EXTENSION_SUFFIX)
11 execute_process(
12 COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
13 from PySide2 import _config
14 print(_config.pyside_library_soversion.split('.')[0])
15 "
16 OUTPUT_VARIABLE ${_module}_FIND_VERSION_MAJOR
17 OUTPUT_STRIP_TRAILING_WHITESPACE)
18 execute_process(
19 COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
20 from PySide2 import _config
21 print(_config.pyside_library_soversion.split('.')[1])
22 "
23 OUTPUT_VARIABLE ${_module}_FIND_VERSION_MINOR
24 OUTPUT_STRIP_TRAILING_WHITESPACE)
25
26 find_library(PYSIDE_LIBRARY
27 NAMES
28 "pyside2${PYTHON_EXTENSION_SUFFIX}"
29 "libpyside2${PYTHON_EXTENSION_SUFFIX}"
30 "pyside2${PYTHON_EXTENSION_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}"
31 "libpyside2${PYTHON_EXTENSION_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}"
32 PATHS "${PYTHON_SITE_PACKAGES}/PySide2")
33
34 find_path(PYSIDE_INCLUDE_DIR
35 pyside.h
36 PATHS "${PYTHON_SITE_PACKAGES}/PySide2/include")
37
38 find_path(PYSIDE_TYPESYSTEMS
39 typesystem_core.xml
40 PATHS "${PYTHON_SITE_PACKAGES}/PySide2/typesystems")
41 endif()
42
43 if(TARGET ${_lib_target})
44 get_target_property(_is_imported ${_lib_target} IMPORTED)
45 if(_is_imported)
46 get_target_property(_imported_location ${_lib_target} IMPORTED_LOCATION)
47 if(NOT _imported_location)
48 message(STATUS "Target ${_lib_target} does not specify its IMPORTED_LOCATION! Trying to find it ourselves...")
49 set(_find_args)
50 if(${_module}_CONFIG)
51 get_filename_component(_pyside2_lib_dir "${${_module}_CONFIG}/../../../" ABSOLUTE)
52 set(_find_args PATHS "${_pyside2_lib_dir}")
53 endif()
54 find_library(PYSIDE_LIBRARY
55 NAMES
56 "pyside2${PYTHON_CONFIG_SUFFIX}"
57 "pyside2${PYTHON_CONFIG_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}"
58 ${_find_args})
59 if(NOT PYSIDE_LIBRARY)
60 set(_message_type WARNING)
61 if(${_module}_FIND_REQUIRED)
62 set(_message_type FATAL_ERROR)
63 endif()
64 message(${_message_type} "Failed to manually find library for ${_module}")
65 return()
66 endif()
67 message(STATUS "IMPORTED_LOCATION for ${_lib_target} found: ${PYSIDE_LIBRARY}")
68 set_target_properties(${_lib_target} PROPERTIES IMPORTED_LOCATION "${PYSIDE_LIBRARY}")
69 endif()
70 endif()
71 else()
72 include(FindPackageHandleStandardArgs)
73 find_package_handle_standard_args(${_module}
74 FOUND_VAR ${_module}_FOUND
75 REQUIRED_VARS PYSIDE_LIBRARY PYSIDE_INCLUDE_DIR PYSIDE_TYPESYSTEMS
76 VERSION_VAR ${_module}_VERSION)
77
78 add_library(${_module}::pyside2 INTERFACE IMPORTED)
79 set_target_properties(${_module}::pyside2 PROPERTIES
80 INTERFACE_INCLUDE_DIRECTORIES "${PYSIDE_INCLUDE_DIR}"
81 INTERFACE_LINK_LIBRARIES "${PYSIDE_LIBRARY}")
82 endif()
83
84 mark_as_advanced(PYSIDE_INCLUDE_DIR PYSIDE_LIBRARY PYSIDE_BINARY)
@@ -0,0 +1,106
1
2 set(_module Shiboken2)
3
4 find_package(${_module} ${${_module}_FIND_VERSION} CONFIG QUIET)
5 set(_executable_target ${_module}::shiboken2)
6 set(_lib_target ${_module}::libshiboken)
7
8 if(NOT ${_module}_FOUND)
9 include(PythonInfo)
10 find_python_site_packages(PYTHON_SITE_PACKAGES)
11 get_python_extension_suffix(PYTHON_EXTENSION_SUFFIX)
12
13 execute_process(
14 COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
15 from shiboken2 import _config
16 print(_config.shiboken_library_soversion.split('.')[0])
17 "
18 OUTPUT_VARIABLE ${_module}_FIND_VERSION_MAJOR
19 OUTPUT_STRIP_TRAILING_WHITESPACE)
20 execute_process(
21 COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
22 from shiboken2 import _config
23 print(_config.shiboken_library_soversion.split('.')[1])
24 "
25 OUTPUT_VARIABLE ${_module}_FIND_VERSION_MINOR
26 OUTPUT_STRIP_TRAILING_WHITESPACE)
27
28 find_library(SHIBOKEN_LIBRARY
29 NAMES
30 "libshiboken2${PYTHON_EXTENSION_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}"
31 "shiboken2${PYTHON_EXTENSION_SUFFIX}"
32 PATHS "${PYTHON_SITE_PACKAGES}/shiboken2")
33
34 find_path(SHIBOKEN_INCLUDE_DIR
35 shiboken.h
36 PATHS "${PYTHON_SITE_PACKAGES}/shiboken2_generator/include")
37
38 find_file(SHIBOKEN_BINARY
39 shiboken2
40 PATHS "${PYTHON_SITE_PACKAGES}/shiboken2_generator")
41 endif()
42
43 if(TARGET ${_executable_target})
44 get_target_property(_is_imported ${_executable_target} IMPORTED)
45 if(_is_imported)
46 get_target_property(_imported_location ${_executable_target} IMPORTED_LOCATION)
47 if(NOT _imported_location)
48 message(STATUS "Target ${_executable_target} does not specify its IMPORTED_LOCATION! Trying to find it ourselves...")
49 find_file(SHIBOKEN_BINARY
50 shiboken2
51 PATHS "${SHIBOKEN_SHARED_LIBRARY_DIR}/../bin"
52 NO_DEFAULT_PATH)
53 if(NOT SHIBOKEN_BINARY)
54 set(_message_type WARNING)
55 if(${_module}_FIND_REQUIRED)
56 set(_message_type FATAL_ERROR)
57 endif()
58 message(${_message_type} "Failed to manually find executable for ${_module}")
59 return()
60 endif()
61 message(STATUS "IMPORTED_LOCATION for ${_executable_target} found: ${SHIBOKEN_BINARY}")
62 set_target_properties(${_executable_target} PROPERTIES IMPORTED_LOCATION "${SHIBOKEN_BINARY}")
63 endif()
64 endif()
65
66 get_target_property(_is_imported ${_lib_target} IMPORTED)
67 if(_is_imported)
68 get_target_property(_imported_location ${_lib_target} IMPORTED_LOCATION)
69 if(NOT _imported_location)
70 message(STATUS "Target ${_lib_target} does not specify its IMPORTED_LOCATION! Trying to find it ourselves...")
71 find_library(SHIBOKEN_LIBRARY
72 NAMES
73 "shiboken2${SHIBOKEN_PYTHON_EXTENSION_SUFFIX}"
74 "shiboken2${SHIBOKEN_PYTHON_EXTENSION_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}"
75 PATHS "${SHIBOKEN_SHARED_LIBRARY_DIR}")
76 if(NOT SHIBOKEN_LIBRARY)
77 set(_message_type WARNING)
78 if(${_module}_FIND_REQUIRED)
79 set(_message_type FATAL_ERROR)
80 endif()
81 message(${_message_type} "Failed to manually find library for ${_module}")
82 return()
83 endif()
84 message(STATUS "IMPORTED_LOCATION for ${_lib_target} found: ${SHIBOKEN_LIBRARY}")
85 set_target_properties(${_lib_target} PROPERTIES IMPORTED_LOCATION "${SHIBOKEN_LIBRARY}")
86 endif()
87 endif()
88 else()
89 include(FindPackageHandleStandardArgs)
90 find_package_handle_standard_args(${_module}
91 FOUND_VAR ${_module}_FOUND
92 REQUIRED_VARS SHIBOKEN_LIBRARY SHIBOKEN_INCLUDE_DIR SHIBOKEN_BINARY
93 VERSION_VAR ${_module}_VERSION)
94
95 add_library(${_module}::libshiboken INTERFACE IMPORTED)
96 set_target_properties(${_module}::libshiboken PROPERTIES
97 INTERFACE_INCLUDE_DIRECTORIES "${SHIBOKEN_INCLUDE_DIR}"
98 INTERFACE_LINK_LIBRARIES "${SHIBOKEN_LIBRARY}")
99
100 add_executable(${_module}::shiboken2 IMPORTED)
101 set_target_properties(${_module}::shiboken2 PROPERTIES
102 IMPORTED_LOCATION "${SHIBOKEN_BINARY}")
103 endif()
104
105 mark_as_advanced(SHIBOKEN_INCLUDE_DIR SHIBOKEN_LIBRARY SHIBOKEN_BINARY)
106
@@ -0,0 +1,32
1
2 function(find_python_site_packages VAR)
3 if(Python_SITELIB)
4 set("${VAR}" "${Python_SITELIB}" PARENT_SCOPE)
5 return()
6 endif()
7
8 execute_process(
9 COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
10 from distutils import sysconfig
11 print(sysconfig.get_python_lib(prefix=None, plat_specific=True))"
12 OUTPUT_VARIABLE "${VAR}"
13 OUTPUT_STRIP_TRAILING_WHITESPACE)
14 set("${VAR}" "${${VAR}}" PARENT_SCOPE)
15 endfunction()
16
17 function(get_python_extension_suffix VAR)
18 # from PySide2 CMakeLists.txt
19 # Result of imp.get_suffixes() depends on the platform, but generally looks something like:
20 # [('.cpython-34m-x86_64-linux-gnu.so', 'rb', 3), ('.cpython-34m.so', 'rb', 3),
21 # ('.abi3.so', 'rb', 3), ('.so', 'rb', 3), ('.py', 'r', 1), ('.pyc', 'rb', 2)]
22 # We pick the first most detailed one, strip of the file extension part.
23
24 execute_process(
25 COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
26 import sysconfig
27 print(sysconfig.get_config_var('EXT_SUFFIX'))
28 "
29 OUTPUT_VARIABLE "${VAR}"
30 OUTPUT_STRIP_TRAILING_WHITESPACE)
31 set("${VAR}" "${${VAR}}" PARENT_SCOPE)
32 endfunction()
@@ -1,47 +1,61
1 1 include_directories(include)
2 2
3 3 FILE (GLOB_RECURSE app_SRCS
4 4 include/*.h
5 src/*.cpp
5 src/MainWindow.cpp
6 src/toolbar.cpp
6 7 resources/*.qrc
7 8 )
8 9
9 10 QT5_WRAP_UI(UiGenerated_SRCS
10 11 ui/MainWindow.ui
11 12 )
12 13
14 add_library(sciqlopapp ${UiGenerated_SRCS} ${app_SRCS})
15
13 16 if(ENABLE_WIN32_CONSOLE)
14 add_executable(sciqlopapp ${app_SRCS} ${UiGenerated_SRCS})
17 add_executable(sciqlop src/Main.cpp)
15 18 else()
16 add_executable(sciqlopapp WIN32 ${app_SRCS} ${UiGenerated_SRCS})
19 add_executable(sciqlop WIN32 src/Main.cpp)
17 20 endif()
18 21
19 22 if(NOT BUILD_SHARED_LIBS)
20 23 add_definitions(-DQT_STATICPLUGIN)
21 24 if(BUILD_PLUGINS)
22 25 #target_link_libraries(sciqlopapp mockplugin)
23 26 #target_link_libraries(sciqlopapp amdaplugin)
24 27 target_link_libraries(sciqlopapp python_providers)
25 28 endif()
26 29 endif()
27 30
28 31 if(NOT BUILD_PLUGINS)
29 32 add_definitions(-DSQP_NO_PLUGINS)
30 33 endif()
31 34
32 35 target_link_libraries(sciqlopapp
33 36 Qt5::Core
34 37 Qt5::Widgets
35 38 Qt5::Network
36 39 Qt5::PrintSupport
37 40 Qt5::Svg
38 41 sciqlopgui
39 42 sciqlopcore
40 43 )
41 44
42 install(TARGETS sciqlopapp DESTINATION ${CMAKE_INSTALL_BINDIR})
45 target_link_libraries(sciqlop
46 sciqlopapp
47 )
48
49 install(TARGETS sciqlopapp
50 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
51 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
52 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
53
54
55 install(TARGETS sciqlop DESTINATION ${CMAKE_INSTALL_BINDIR})
43 56 install(FILES resources/SciQLOP.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications/)
44 57 install(FILES resources/SciQLOP.appdata.xml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo/)
45 58 install(FILES resources/sciqlopLOGO.svg DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/SciQLOP/icons/)
46 59
47 60
61 add_subdirectory(PySide2-bindings)
@@ -1,68 +1,120
1 1 /*------------------------------------------------------------------------------
2 2 -- This file is a part of the SciQLop Software
3 3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 4 --
5 5 -- This program is free software; you can redistribute it and/or modify
6 6 -- it under the terms of the GNU General Public License as published by
7 7 -- the Free Software Foundation; either version 2 of the License, or
8 8 -- (at your option) any later version.
9 9 --
10 10 -- This program is distributed in the hope that it will be useful,
11 11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 -- GNU General Public License for more details.
14 14 --
15 15 -- You should have received a copy of the GNU General Public License
16 16 -- along with this program; if not, write to the Free Software
17 17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18 -------------------------------------------------------------------------------*/
19 19 /*-- Author : Alexis Jeandet
20 20 -- Mail : alexis.jeandet@member.fsf.org
21 21 ----------------------------------------------------------------------------*/
22 22 #ifndef SCIQLOP_MAINWINDOW_H
23 23 #define SCIQLOP_MAINWINDOW_H
24 24
25 #include <QListWidgetItem>
25 #include <PluginManager/PluginManager.h>
26 #include <QDir>
26 27 #include <QLoggingCategory>
27 28 #include <QMainWindow>
28 29 #include <QProgressBar>
29 30 #include <QProgressDialog>
30 31 #include <QThread>
31 32 #include <QVBoxLayout>
32 33 #include <QWidget>
34 #include <QtPlugin>
35 #include <SqpApplication.h>
33 36
34 37 #include <Common/spimpl.h>
35 38
36 39 #include <memory>
37 40
38 Q_DECLARE_LOGGING_CATEGORY(LOG_MainWindow)
39
40 namespace Ui {
41 namespace Ui
42 {
41 43 class MainWindow;
42 44 } // namespace Ui
43 45
44 46
45 class MainWindow : public QMainWindow {
47 class MainWindow : public QMainWindow
48 {
46 49 Q_OBJECT
47 50
48 51 public:
49 explicit MainWindow(QWidget *parent = nullptr);
52 explicit MainWindow(QWidget* parent = nullptr);
50 53 virtual ~MainWindow() override;
51 54 public slots:
52 55
53 56 protected:
54 void changeEvent(QEvent *e) override;
55 void closeEvent(QCloseEvent *event) override;
57 void changeEvent(QEvent* e) override;
58 void closeEvent(QCloseEvent* event) override;
56 59
57 void keyPressEvent(QKeyEvent *event) override;
60 void keyPressEvent(QKeyEvent* event) override;
58 61
59 62 private:
60 63 std::unique_ptr<Ui::MainWindow> m_Ui;
61 64 // QWidget *m_progressWidget;
62 65 // QVBoxLayout *m_progressLayout;
63 66 // QList<QLopService*> m_qlopServices;
64 67 class MainWindowPrivate;
65 68 spimpl::unique_impl_ptr<MainWindowPrivate> impl;
66 69 };
67 70
71 inline void init_resources()
72 {
73 #ifdef QT_STATICPLUGIN
74 #ifndef SQP_NO_PLUGINS
75 Q_IMPORT_PLUGIN(PythonProviders)
76 Q_INIT_RESOURCE(python_providers);
77 #endif
78 #endif
79 Q_INIT_RESOURCE(sqpguiresources);
80 SqpApplication::setOrganizationName("LPP");
81 SqpApplication::setOrganizationDomain("lpp.fr");
82 SqpApplication::setApplicationName("SciQLop");
83
84 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
85 }
86
87 inline void load_plugins(const SqpApplication& a)
88 {
89 // Loads plugins
90 auto pluginDir = QDir { a.applicationDirPath() };
91 auto pluginLookupPath = {
92 #if _WIN32 || _WIN64
93 a.applicationDirPath() + "/SciQLop"
94 #else
95 a.applicationDirPath() + "/../lib64/SciQLop",
96 a.applicationDirPath() + "/../lib64/sciqlop",
97 a.applicationDirPath() + "/../lib/SciQLop",
98 a.applicationDirPath() + "/../lib/sciqlop",
99 #endif
100 };
101
102 #if _WIN32 || _WIN64
103 pluginDir.mkdir(PLUGIN_DIRECTORY_NAME);
104 pluginDir.cd(PLUGIN_DIRECTORY_NAME);
105 #endif
106
107 PluginManager pluginManager {};
108
109 for (auto&& path : pluginLookupPath)
110 {
111 QDir directory { path };
112 if (directory.exists())
113 {
114 pluginManager.loadPlugins(directory);
115 }
116 }
117 pluginManager.loadStaticPlugins();
118 }
119
68 120 #endif // SCIQLOP_MAINWINDOW_H
@@ -1,98 +1,51
1 1 /*------------------------------------------------------------------------------
2 2 -- This file is a part of the QLop Software
3 3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
4 4 --
5 5 -- This program is free software; you can redistribute it and/or modify
6 6 -- it under the terms of the GNU General Public License as published by
7 7 -- the Free Software Foundation; either version 2 of the License, or
8 8 -- (at your option) any later version.
9 9 --
10 10 -- This program is distributed in the hope that it will be useful,
11 11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 -- GNU General Public License for more details.
14 14 --
15 15 -- You should have received a copy of the GNU General Public License
16 16 -- along with this program; if not, write to the Free Software
17 17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18 -------------------------------------------------------------------------------*/
19 19 /*-- Author : Alexis Jeandet
20 20 -- Mail : alexis.jeandet@member.fsf.org
21 21 ----------------------------------------------------------------------------*/
22 22 #include "MainWindow.h"
23 23 #include <QProcessEnvironment>
24 24 #include <QThread>
25 25 #include <SqpApplication.h>
26 26 #include <qglobal.h>
27 27
28 28 #include <PluginManager/PluginManager.h>
29 29 #include <QDir>
30 30 #include <QtPlugin>
31 31
32 32 #include <QLoggingCategory>
33 33
34 Q_LOGGING_CATEGORY(LOG_Main, "Main")
35 34
36 35 namespace
37 36 {
38 37
39 38 const auto PLUGIN_DIRECTORY_NAME = QStringLiteral("plugins");
40 39
41 40
42 41 } // namespace
43 42
44 43 int main(int argc, char* argv[])
45 44 {
46 #ifdef QT_STATICPLUGIN
47 #ifndef SQP_NO_PLUGINS
48 Q_IMPORT_PLUGIN(PythonProviders)
49 Q_INIT_RESOURCE(python_providers);
50 #endif
51 #endif
52 Q_INIT_RESOURCE(sqpguiresources);
53
54 SqpApplication::setOrganizationName("LPP");
55 SqpApplication::setOrganizationDomain("lpp.fr");
56 SqpApplication::setApplicationName("SciQLop");
57
58 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
59
45 init_resources();
60 46 SqpApplication a { argc, argv };
61
47 load_plugins(a);
62 48 MainWindow w;
63 49 w.show();
64
65 // Loads plugins
66 auto pluginDir = QDir { a.applicationDirPath() };
67 auto pluginLookupPath = {
68 #if _WIN32 || _WIN64
69 a.applicationDirPath() + "/SciQLop"
70 #else
71 a.applicationDirPath() + "/../lib64/SciQLop",
72 a.applicationDirPath() + "/../lib64/sciqlop",
73 a.applicationDirPath() + "/../lib/SciQLop",
74 a.applicationDirPath() + "/../lib/sciqlop",
75 #endif
76 };
77
78 #if _WIN32 || _WIN64
79 pluginDir.mkdir(PLUGIN_DIRECTORY_NAME);
80 pluginDir.cd(PLUGIN_DIRECTORY_NAME);
81 #endif
82
83 PluginManager pluginManager {};
84
85 for (auto&& path : pluginLookupPath)
86 {
87 QDir directory { path };
88 if (directory.exists())
89 {
90 qCDebug(LOG_Main())
91 << QObject::tr("Plugin directory: %1").arg(directory.absolutePath());
92 pluginManager.loadPlugins(directory);
93 }
94 }
95 pluginManager.loadStaticPlugins();
96
97 50 return a.exec();
98 51 }
@@ -1,113 +1,120
1 1 #ifndef SCIQLOP_SQPAPPLICATION_H
2 2 #define SCIQLOP_SQPAPPLICATION_H
3 3
4 4 #include "SqpApplication.h"
5 5
6 6 #include <QAction>
7 7 #include <QApplication>
8 8 #include <QLoggingCategory>
9 9 #include <QMenuBar>
10 10 #include <QProxyStyle>
11 11 #include <QStyleOption>
12 12 #include <QWidget>
13 13 #include <QWidgetAction>
14 14
15 15 #include <Common/spimpl.h>
16 16
17 17 Q_DECLARE_LOGGING_CATEGORY(LOG_SqpApplication)
18 18
19 19 #if defined(sqpApp)
20 20 #undef sqpApp
21 21 #endif
22 22 #define sqpApp (static_cast<SqpApplication*>(QCoreApplication::instance()))
23 23
24 24 class DataSourceController;
25 25 class NetworkController;
26 26 class TimeController;
27 27 class VariableController;
28 28 class VariableController2;
29 29 class VariableModel2;
30 30 class DragDropGuiController;
31 31 class ActionsGuiController;
32 32 class CatalogueController;
33 33
34 34 /* stolen from here https://forum.qt.io/topic/90403/show-tooltip-immediatly/6 */
35 35 class MyProxyStyle : public QProxyStyle
36 36 {
37 37 public:
38 38 using QProxyStyle::QProxyStyle;
39 39
40 40 int styleHint(StyleHint hint, const QStyleOption* option = nullptr,
41 41 const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override
42 42 {
43 43 if (widget)
44 44 auto cname = widget->metaObject()->className();
45 45 if (hint == QStyle::SH_ToolButton_PopupDelay && widget
46 46 /*&& widget->inherits(QWidgetAction::staticMetaObject.className())*/)
47 47 {
48 48 return 0;
49 49 }
50 50
51 51 return QProxyStyle::styleHint(hint, option, widget, returnData);
52 52 }
53 53 };
54 54
55 55 /**
56 56 * @brief The SqpApplication class aims to make the link between SciQlop
57 57 * and its plugins. This is the intermediate class that SciQlop has to use
58 58 * in the way to connect a data source. Please first use load method to initialize
59 59 * a plugin specified by its metadata name (JSON plugin source) then others specifics
60 60 * method will be able to access it.
61 61 * You can load a data source driver plugin then create a data source.
62 62 */
63 63
64 64 class SqpApplication : public QApplication
65 65 {
66 66 Q_OBJECT
67 67 public:
68 68 explicit SqpApplication(int& argc, char** argv);
69 69 ~SqpApplication() override;
70 70 void initialize();
71 71
72 72 /// Accessors for the differents sciqlop controllers
73 73 DataSourceController& dataSourceController() noexcept;
74 74 NetworkController& networkController() noexcept;
75 75 TimeController& timeController() noexcept;
76 76 VariableController2& variableController() noexcept;
77 77 std::shared_ptr<VariableController2> variableControllerOwner() noexcept;
78 78 CatalogueController& catalogueController() noexcept;
79 79
80 80 /// Accessors for the differents sciqlop helpers, these helpers classes are like controllers but
81 81 /// doesn't live in a thread and access gui
82 82 DragDropGuiController& dragDropGuiController() noexcept;
83 83 ActionsGuiController& actionsGuiController() noexcept;
84 84
85 85 enum class PlotsInteractionMode
86 86 {
87 87 None,
88 88 ZoomBox,
89 89 DragAndDrop,
90 90 SelectionZones
91 91 };
92 92
93 93 enum class PlotsCursorMode
94 94 {
95 95 NoCursor,
96 96 Vertical,
97 97 Temporal,
98 98 Horizontal,
99 99 Cross
100 100 };
101 101
102 102 PlotsInteractionMode plotsInteractionMode() const;
103 103 void setPlotsInteractionMode(PlotsInteractionMode mode);
104 104
105 105 PlotsCursorMode plotsCursorMode() const;
106 106 void setPlotsCursorMode(PlotsCursorMode mode);
107 107
108 108 private:
109 109 class SqpApplicationPrivate;
110 110 spimpl::unique_impl_ptr<SqpApplicationPrivate> impl;
111 111 };
112 112
113 inline SqpApplication* SqpApplication_ctor()
114 {
115 static int argc;
116 static char** argv;
117 return new SqpApplication(argc, argv);
118 }
119
113 120 #endif // SCIQLOP_SQPAPPLICATION_H
@@ -1,194 +1,152
1 1 /*
2 2 This file is part of SciQLop.
3 3
4 4 SciQLop is free software: you can redistribute it and/or modify
5 5 it under the terms of the GNU General Public License as published by
6 6 the Free Software Foundation, either version 3 of the License, or
7 7 (at your option) any later version.
8 8
9 9 SciQLop is distributed in the hope that it will be useful,
10 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 GNU General Public License for more details.
13 13
14 14 You should have received a copy of the GNU General Public License
15 15 along with SciQLop. If not, see <https://www.gnu.org/licenses/>.
16 16 */
17 17 #include "Catalogue2/eventsmodel.h"
18 18 #include <Common/containers.h>
19 19 #include <SqpApplication.h>
20 20
21 21 EventsModel::EventsModel(QObject* parent) : QAbstractItemModel(parent) {}
22 22
23 23 EventsModel::ItemType EventsModel::type(const QModelIndex& index) const
24 24 {
25 25 if (EventsModelItem* item = to_item(index))
26 26 {
27 27 return item->type;
28 28 }
29 29 return ItemType::None;
30 30 }
31 31
32 32 QVariant EventsModel::data(const QModelIndex& index, int role) const
33 33 {
34 34 if (index.isValid())
35 35 {
36 36 return to_item(index)->data(index.column(), role);
37 37 }
38 38 return QVariant {};
39 39 }
40 40
41 41 QModelIndex EventsModel::index(int row, int column, const QModelIndex& parent) const
42 42 {
43 43 if (!hasIndex(row, column, parent))
44 44 {
45 45 return QModelIndex();
46 46 }
47 47
48 48 switch (type(parent))
49 49 {
50 50 case ItemType::None: // is an event
51 51 return createIndex(row, column, _items[row].get());
52 52 case ItemType::Event: // is a product
53 53 return createIndex(row, column, to_item(parent)->children[row].get());
54 54 case ItemType::Product:
55 55 QModelIndex();
56 56 }
57 57
58 58 return QModelIndex();
59 59 }
60 60
61 61 QModelIndex EventsModel::parent(const QModelIndex& index) const
62 62 {
63 63 auto item = to_item(index);
64 64 if (item->type == ItemType::Product)
65 65 {
66 66 auto repoIndex = SciQLop::containers::index_of(_items, item->parent);
67 67 return createIndex(repoIndex, 0, item->parent);
68 68 }
69 69 return QModelIndex();
70 70 }
71 71
72 72 int EventsModel::rowCount(const QModelIndex& parent) const
73 73 {
74 74 if (parent.column() > 0)
75 75 {
76 76 return 0;
77 77 }
78 78 switch (type(parent))
79 79 {
80 80 case ItemType::None:
81 81 return _items.size();
82 82 case ItemType::Event:
83 83 return to_item(parent)->children.size();
84 84 case ItemType::Product:
85 85 break;
86 86 }
87 87 return 0;
88 88 }
89 89
90 90 int EventsModel::columnCount(const QModelIndex& parent) const
91 91 {
92 92 return static_cast<int>(EventsModel::Columns::NbColumn);
93 93 }
94 94
95 95 QVariant EventsModel::headerData(int section, Qt::Orientation orientation, int role) const
96 96 {
97 97 if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section < ColumnsNames.size())
98 98 {
99 99 return ColumnsNames[section];
100 100 }
101 101
102 102 return QVariant();
103 103 }
104 104
105 105 void EventsModel::sort(int column, Qt::SortOrder order)
106 106 {
107 107 beginResetModel();
108 108 switch (static_cast<Columns>(column))
109 109 {
110 110 case EventsModel::Columns::Name:
111 111 std::sort(std::begin(_items), std::end(_items),
112 112 [inverse = order != Qt::SortOrder::AscendingOrder](
113 113 const std::unique_ptr<EventsModelItem>& a,
114 114 const std::unique_ptr<EventsModelItem>& b) {
115 static int i = 0;
116 i++;
117 if (!a->event())
118 {
119 throw;
120 }
121 if (!b->event())
122 {
123 throw;
124 }
125 115 return (a->event()->name < b->event()->name) xor inverse;
126 116 });
127 117 break;
128 118 case EventsModel::Columns::TStart:
129 119 std::sort(std::begin(_items), std::end(_items),
130 120 [inverse = order != Qt::SortOrder::AscendingOrder](
131 121 const std::unique_ptr<EventsModelItem>& a,
132 122 const std::unique_ptr<EventsModelItem>& b) {
133 static int i = 0;
134 i++;
135 if (!a)
136 {
137 throw;
138 }
139 if (!b)
140 {
141 throw;
142 }
143 if (!a->event())
144 {
145 throw;
146 }
147 if (!b->event())
123 if (auto t1 = a->event()->startTime(); auto t2 = b->event()->startTime())
148 124 {
149 throw;
125 if (t1 and t2)
126 return bool((t1.value() < t2.value()) xor inverse);
150 127 }
151 return (a->event()->name < b->event()->name) xor inverse;
128 return true;
152 129 });
153 // std::sort(std::begin(_items), std::end(_items),
154 // [inverse = order != Qt::SortOrder::AscendingOrder](
155 // const std::unique_ptr<EventsModelItem>& a,
156 // const std::unique_ptr<EventsModelItem>& b) {
157 // static int i = 0;
158 // i++;
159 // if (a and b)
160 // {
161 // if (a->type == ItemType::Event and b->type == ItemType::Event)
162 // {
163 // if (auto e1 = a->event(); auto e2 = b->event())
164 // {
165 // return bool((e1->startTime() < e2->startTime()) xor
166 // inverse);
167 // }
168 // }
169 // }
170 // return false;
171 // });
172 130 break;
173 131 case EventsModel::Columns::TEnd:
174 132 std::sort(std::begin(_items), std::end(_items),
175 133 [inverse = order != Qt::SortOrder::AscendingOrder](
176 134 const std::unique_ptr<EventsModelItem>& a,
177 135 const std::unique_ptr<EventsModelItem>& b) {
178 136 if (auto t1 = a->event()->stopTime(); auto t2 = b->event()->stopTime())
179 137 {
180 138 if (t1 and t2)
181 139 return bool((t1.value() < t2.value()) xor inverse);
182 140 }
183 141 return true;
184 142 });
185 143 break;
186 144 case EventsModel::Columns::Product:
187 145 break;
188 146 case EventsModel::Columns::Tags:
189 147 break;
190 148 default:
191 149 break;
192 150 }
193 151 endResetModel();
194 152 }
@@ -1,10 +1,10
1 1 include(sciqlop_tests)
2 2 subdirs(GUITestUtils)
3 3 declare_test(simple_graph simple_graph simple_graph/main.cpp "sciqlopgui;TestUtils;GUITestUtils;Qt5::Test")
4 4 declare_test(multiple_sync_graph multiple_sync_graph multiple_sync_graph/main.cpp "sciqlopgui;TestUtils;GUITestUtils;Qt5::Test")
5
5 declare_test(catalogue_browser catalogue_browser catalogue/browser/main.cpp "sciqlopgui;TestUtils;GUITestUtils;Qt5::Test")
6 6 if(NOT WIN32)
7 7 declare_manual_test(event_list event_list catalogue/event_list/main.cpp "sciqlopgui;TestUtils;GUITestUtils;Qt5::Test")
8 8 declare_manual_test(repository_list repository_list catalogue/repository_list/main.cpp "sciqlopgui;TestUtils;GUITestUtils;Qt5::Test")
9 declare_manual_test(catalogue_browser catalogue_browser catalogue/browser/main.cpp "sciqlopgui;TestUtils;GUITestUtils;Qt5::Test")
10 endif() No newline at end of file
9 declare_manual_test(catalogue_browser_m catalogue_browser_m catalogue/browser/main.cpp "sciqlopgui;TestUtils;GUITestUtils;Qt5::Test")
10 endif()
@@ -1,69 +1,85
1 1 #include <QMainWindow>
2 2 #include <QObject>
3 3 #include <QScreen>
4 4 #include <QString>
5 5 #include <QWheelEvent>
6 6 #include <QtTest>
7 #include <cstdlib>
7 8
8 9
9 10 #include <Common/cpp_utils.h>
10 11 #include <SqpApplication.h>
11 12
12 13 #include <GUITestUtils.h>
13 14
14 15 #include <Catalogue/CatalogueController.h>
15 16 #include <Catalogue2/browser.h>
16 17
18 template <int EventsCount = 1000>
19 auto build_CatalogueBrowser_test()
20 {
21 sqpApp->catalogueController().add("test");
22 sqpApp->catalogueController().add("stuff");
23 sqpApp->catalogueController().add("default");
24 sqpApp->catalogueController().add("new catalogue", "default");
25 auto catalogue = sqpApp->catalogueController().add("new catalogue2", "default");
26 for (auto _ : std::array<char, EventsCount>())
27 {
28 static int i = 0;
29 auto event = CatalogueController::make_event_ptr();
30 event->name = std::string("Event ") + std::to_string(i++);
31 event->tags = { "tag1", "tag2" };
32 event->products = { CatalogueController::Event_t::Product_t {
33 std::string("Product2") + std::to_string(rand() % 30),
34 static_cast<double>(1532357932 + rand() % 100),
35 static_cast<double>(1532358932 + rand() % 100) },
36 CatalogueController::Event_t::Product_t {
37 std::string("Product2") + std::to_string(rand() % 30),
38 static_cast<double>(1532357932 + rand() % 200),
39 static_cast<double>(1532358932 + rand() % 200) },
40 CatalogueController::Event_t::Product_t {
41 std::string("Product2") + std::to_string(rand() % 30),
42 static_cast<double>(1532357932 + rand() % 70),
43 static_cast<double>(1532358932 + rand() % 70) } };
44 catalogue->add(event);
45 }
46 return std::make_unique<CataloguesBrowser>();
47 }
17 48
18 49 class A_CatalogueBrowser : public QObject
19 50 {
20 51 Q_OBJECT
21 52 public:
22 53 explicit A_CatalogueBrowser(QObject* parent = Q_NULLPTR) : QObject(parent) {}
23 54
24 55 private slots:
56 void can_sort_events()
57 {
58 auto w = build_CatalogueBrowser_test();
59 QVERIFY(prepare_gui_test(w.get()));
60 // GET_CHILD_WIDGET_FOR_GUI_TESTS((*w.get()),,,)
61 for (int i = 0; i < 1000000; i++)
62 {
63 QThread::usleep(100);
64 QCoreApplication::processEvents();
65 }
66 }
25 67 };
26 68
27 // QT_BEGIN_NAMESPACE
28 // QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS
29 // QT_END_NAMESPACE
30 // int main(int argc, char* argv[])
31 //{
32 // SqpApplication app { argc, argv };
33 // app.setAttribute(Qt::AA_Use96Dpi, true);
34 // QTEST_DISABLE_KEYPAD_NAVIGATION;
35 // QTEST_ADD_GPU_BLACKLIST_SUPPORT;
36 // An_EventList tc;
37 // QTEST_SET_MAIN_SOURCE_PATH;
38 // return QTest::qExec(&tc, argc, argv);
39 //}
40
41 #include "main.moc"
42
43
69 QT_BEGIN_NAMESPACE
70 QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS
71 QT_END_NAMESPACE
44 72 int main(int argc, char* argv[])
45 73 {
46 74 Q_INIT_RESOURCE(sqpguiresources);
47 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
48 75
49 SqpApplication a { argc, argv };
50 CataloguesBrowser w;
51 sqpApp->catalogueController().add("test");
52 sqpApp->catalogueController().add("stuff");
53 sqpApp->catalogueController().add("default");
54 sqpApp->catalogueController().add("new catalogue", "default");
55 auto catalogue = sqpApp->catalogueController().add("new catalogue2", "default");
56 for (auto _ : std::array<char, 1000>())
57 {
58 static int i = 0;
59 auto event = CatalogueController::make_event_ptr();
60 event->name = std::string("Event ") + std::to_string(i++);
61 event->tags = {"tag1", "tag2"};
62 event->products = { CatalogueController::Event_t::Product_t { "Product1", 10., 11. },
63 CatalogueController::Event_t::Product_t { "Product2", 11., 12. },
64 CatalogueController::Event_t::Product_t { "Product3", 10.2, 11. } };
65 catalogue->add(event);
66 }
67 w.show();
68 return a.exec();
76 SqpApplication app { argc, argv };
77 app.setAttribute(Qt::AA_Use96Dpi, true);
78 QTEST_DISABLE_KEYPAD_NAVIGATION;
79 QTEST_ADD_GPU_BLACKLIST_SUPPORT;
80 A_CatalogueBrowser tc;
81 QTEST_SET_MAIN_SOURCE_PATH;
82 return QTest::qExec(&tc, argc, argv);
69 83 }
84
85 #include "main.moc"
@@ -1,168 +1,168
1 1 #include "python_providers.h"
2 2 #include <Data/DataProviderParameters.h>
3 3 #include <Data/DateTimeRange.h>
4 4 #include <Data/IDataProvider.h>
5 5 #include <Data/ScalarTimeSerie.h>
6 6 #include <Data/SpectrogramTimeSerie.h>
7 7 #include <Data/TimeSeriesUtils.h>
8 8 #include <Data/VectorTimeSerie.h>
9 9 #include <DataSource/DataSourceController.h>
10 10 #include <DataSource/DataSourceItem.h>
11 11 #include <DataSource/DataSourceItemAction.h>
12 12 #include <QDir>
13 13 #include <QStandardPaths>
14 14 #include <QStringList>
15 15 #include <SqpApplication.h>
16 16 #include <TimeSeries.h>
17 17 #include <functional>
18 18 #include <iostream>
19 19
20 20
21 21 const auto DATA_SOURCE_NAME = QStringLiteral("PythonProviders");
22 22
23 23 class PythonProvider : public IDataProvider
24 24 {
25 25 public:
26 26 explicit PythonProvider(PythonInterpreter::provider_funct_t f) : _pythonFunction { f } {}
27 27
28 28 PythonProvider(const PythonProvider& other) : _pythonFunction { other._pythonFunction } {}
29 29
30 std::shared_ptr<IDataProvider> clone() const override
31 {
32 return std::make_shared<PythonProvider>(*this);
33 }
30 // std::shared_ptr<IDataProvider> clone() const override
31 // {
32 // return std::make_shared<PythonProvider>(*this);
33 // }
34 34 virtual TimeSeries::ITimeSerie* getData(const DataProviderParameters& parameters) override
35 35 {
36 36 auto product = parameters.m_Data.value("PRODUCT", "").toString().toStdString();
37 37 auto range = parameters.m_Range;
38 38 std::vector<std::tuple<std::string, std::string>> metadata;
39 39 std::transform(parameters.m_Data.constKeyValueBegin(), parameters.m_Data.constKeyValueEnd(),
40 40 std::back_inserter(metadata), [](const auto& item) {
41 41 return std::tuple<std::string, std::string> { item.first.toStdString(),
42 42 item.second.toString().toStdString() };
43 43 });
44 44 auto result = _pythonFunction(metadata, range.m_TStart, range.m_TEnd);
45 45 return TimeSeriesUtils::copy(result);
46 46 }
47 47
48 48 private:
49 49 PythonInterpreter::provider_funct_t _pythonFunction;
50 50 };
51 51
52 52
53 53 void PythonProviders::initialize()
54 54 {
55 55 auto app_path = sqpApp->applicationDirPath();
56 56 _interpreter.eval_str("import sys");
57 57 for(const auto& path:{"/../lib","/../lib64","/../core","/../../lib"})
58 58 {
59 59 QDir d{app_path+path};
60 60 if(d.exists())
61 61 {
62 62 _interpreter.eval_str("sys.path.append(\""+d.path().toStdString()+"\")");
63 63 }
64 64 }
65 65
66 66 _interpreter.add_register_callback(
67 67 [this](const std::vector<PythonInterpreter::product_t>& product_list,
68 68 PythonInterpreter::provider_funct_t f) { this->register_product(product_list, f); });
69 69
70 70 for (const auto& path : QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation))
71 71 {
72 72 auto dir = QDir(path + "/python");
73 73 if (dir.exists())
74 74 {
75 75 for (const auto& entry :
76 76 dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name))
77 77 {
78 78 if (entry.isFile() && entry.suffix() == "py")
79 79 {
80 80 _interpreter.eval(entry.absoluteFilePath().toStdString());
81 81 }
82 82 }
83 83 }
84 84 }
85 85 for (const auto& embed_file : { ":/test.py", ":/amda.py", ":/cdaweb.py"})
86 86 {
87 87 QFile file(embed_file);
88 88 file.open(QFile::ReadOnly);
89 89 if(file.isOpen())
90 90 _interpreter.eval_str(file.readAll().toStdString());
91 91 }
92 92 _interpreter.release();
93 93 }
94 94
95 95 PythonProviders::~PythonProviders() {}
96 96
97 97 std::unique_ptr<DataSourceItem> make_folder_item(const QString& name)
98 98 {
99 99 return std::make_unique<DataSourceItem>(DataSourceItemType::NODE, name);
100 100 }
101 101
102 102 template <typename T>
103 103 DataSourceItem* make_path_items(
104 104 const T& path_list_begin, const T& path_list_end, DataSourceItem* root)
105 105 {
106 106 std::for_each(path_list_begin, path_list_end, [&root](const auto& folder_name) mutable {
107 107 auto folder_ptr = root->findItem(folder_name);
108 108 if (folder_ptr == nullptr)
109 109 {
110 110 auto folder = make_folder_item(folder_name);
111 111 folder_ptr = folder.get();
112 112 root->appendChild(std::move(folder));
113 113 }
114 114 root = folder_ptr;
115 115 });
116 116 return root;
117 117 }
118 118
119 119 std::unique_ptr<DataSourceItem> make_product_item(
120 120 const QVariantHash& metaData, const QUuid& dataSourceUid)
121 121 {
122 122 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, metaData);
123 123
124 124 // Adds plugin name to product metadata
125 125 result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
126 126 result->setData(DataSourceItem::ID_DATA_KEY, metaData.value(DataSourceItem::NAME_DATA_KEY));
127 127
128 128 auto productName = metaData.value(DataSourceItem::NAME_DATA_KEY).toString();
129 129
130 130 // Add action to load product from DataSourceController
131 131 result->addAction(
132 132 std::make_unique<DataSourceItemAction>(QObject::tr("Load %1 product").arg(productName),
133 133 [productName, dataSourceUid](DataSourceItem& item) {
134 134 if (auto app = sqpApp)
135 135 {
136 136 app->dataSourceController().loadProductItem(dataSourceUid, item);
137 137 }
138 138 }));
139 139
140 140 return result;
141 141 }
142 142
143 143 void PythonProviders::register_product(
144 144 const std::vector<PythonInterpreter::product_t>& product_list,
145 145 PythonInterpreter::provider_funct_t f)
146 146 {
147 147 auto& dataSourceController = sqpApp->dataSourceController();
148 148 QString test = DATA_SOURCE_NAME + QUuid::createUuid().toString();
149 149 auto id = dataSourceController.registerDataSource(test);
150 150 auto root = make_folder_item(test);
151 151 std::for_each(std::cbegin(product_list), std::cend(product_list),
152 152 [id, f, root = root.get()](const auto& product) {
153 153 const auto& path = std::get<0>(product);
154 154 auto path_list = QString::fromStdString(path).split('/', QString::SkipEmptyParts);
155 155 auto name = *(std::cend(path_list) - 1);
156 156 auto path_item
157 157 = make_path_items(std::cbegin(path_list), std::cend(path_list) - 1, root);
158 158 QVariantHash metaData { { DataSourceItem::NAME_DATA_KEY, name } };
159 159 std::for_each(std::cbegin(std::get<2>(product)), std::cend(std::get<2>(product)),
160 160 [&metaData](const auto& mdata) {
161 161 metaData[QString::fromStdString(mdata.first)]
162 162 = QString::fromStdString(mdata.second);
163 163 });
164 164 path_item->appendChild(make_product_item(metaData, id));
165 165 });
166 166 dataSourceController.setDataSourceItem(id, std::move(root));
167 167 dataSourceController.setDataProvider(id, std::make_unique<PythonProvider>(f));
168 168 }
General Comments 0
You need to be logged in to leave comments. Login now