##// END OF EJS Templates
Merge pull request 340 from SciQLop-fork develop...
leroux -
r932:16999d8139e2 merge
parent child
Show More
@@ -0,0 +1,18
1 #ifndef SCIQLOP_MACSCROLLBARSTYLE_H
2 #define SCIQLOP_MACSCROLLBARSTYLE_H
3
4 #include <QProxyStyle>
5
6 /**
7 * @brief Special style to always display the scrollbars on MAC.
8 */
9 class MacScrollBarStyle : public QProxyStyle {
10
11 public:
12 int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
13 QStyleHintReturn *returnData) const;
14
15 void selfInstallOn(QWidget *widget, bool installOnSubWidgets);
16 };
17
18 #endif // SCIQLOP_MACSCROLLBARSTYLE_H
@@ -0,0 +1,40
1 #include "Visualization/MacScrollBarStyle.h"
2
3 #include <QWidget>
4
5 int MacScrollBarStyle::styleHint(QStyle::StyleHint hint, const QStyleOption *option,
6 const QWidget *widget, QStyleHintReturn *returnData) const
7 {
8 switch (hint) {
9 case SH_ScrollBar_Transient:
10 return false; // Makes the scrollbar always visible
11 case SH_ScrollView_FrameOnlyAroundContents:
12 return true; // Avoid that the scrollbar is drawn on top of the widget
13 default:
14 break;
15 }
16
17 return QProxyStyle::styleHint(hint, option, widget, returnData);
18 }
19
20 void MacScrollBarStyle::selfInstallOn(QWidget *widget, bool installOnSubWidgets)
21 {
22 // Note: a style can be installed on a particular widget but it is not automatically applied its
23 // children widgets.
24
25 QList<QWidget *> widgetsToStyle{widget};
26 while (!widgetsToStyle.isEmpty()) {
27
28 auto widget = widgetsToStyle.takeFirst();
29 widget->setStyle(this);
30
31 if (installOnSubWidgets) {
32 for (auto child : widget->children()) {
33 auto childWidget = qobject_cast<QWidget *>(child);
34 if (childWidget) {
35 widgetsToStyle << childWidget;
36 }
37 }
38 }
39 }
40 }
@@ -1,34 +1,37
1 1 #ifndef SCIQLOP_AXISRENDERINGUTILS_H
2 2 #define SCIQLOP_AXISRENDERINGUTILS_H
3 3
4 4 #include <memory>
5 5
6 #include <QtCore/QLoggingCategory>
6 7 #include <QtCore/QString>
7 8
9 Q_DECLARE_LOGGING_CATEGORY(LOG_AxisRenderingUtils)
10
8 11 class IDataSeries;
9 12 class QCPAxis;
10 13 class QCPColorScale;
11 14 class QCustomPlot;
12 15
13 16 /// Formats a data value according to the axis on which it is present
14 17 QString formatValue(double value, const QCPAxis &axis);
15 18
16 19 /**
17 20 * Helper used to handle axes rendering
18 21 */
19 22 struct IAxisHelper {
20 23 virtual ~IAxisHelper() noexcept = default;
21 24
22 25 /// Set properties of the plot's axes and the color scale associated to plot passed as
23 26 /// parameters
24 27 /// @param plot the plot for which to set axe properties
25 28 /// @param colorScale the color scale for which to set properties
26 29 virtual void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) = 0;
27 30 };
28 31
29 32 struct IAxisHelperFactory {
30 33 /// Creates IAxisHelper according to a data series
31 34 static std::unique_ptr<IAxisHelper> create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
32 35 };
33 36
34 37 #endif // SCIQLOP_AXISRENDERINGUTILS_H
@@ -1,29 +1,33
1 1 #ifndef SCIQLOP_PLOTTABLESRENDERINGUTILS_H
2 2 #define SCIQLOP_PLOTTABLESRENDERINGUTILS_H
3 3
4 4 #include <Visualization/VisualizationDefs.h>
5 5
6 6 #include <memory>
7 7
8 #include <QtCore/QLoggingCategory>
9
10 Q_DECLARE_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils)
11
8 12 class IDataSeries;
9 13 class QCPColorScale;
10 14 class QCustomPlot;
11 15
12 16 /**
13 17 * Helper used to handle plottables rendering
14 18 */
15 19 struct IPlottablesHelper {
16 20 virtual ~IPlottablesHelper() noexcept = default;
17 21
18 22 /// Set properties of the plottables passed as parameter
19 23 /// @param plottables the plottables for which to set properties
20 24 virtual void setProperties(PlottablesMap &plottables) = 0;
21 25 };
22 26
23 27 struct IPlottablesHelperFactory {
24 28 /// Creates IPlottablesHelper according to a data series
25 29 static std::unique_ptr<IPlottablesHelper>
26 30 create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
27 31 };
28 32
29 33 #endif // SCIQLOP_PLOTTABLESRENDERINGUTILS_H
@@ -1,97 +1,98
1 1
2 2 gui_moc_headers = [
3 3 'include/DataSource/DataSourceWidget.h',
4 4 'include/DataSource/DataSourceTreeWidget.h',
5 5 'include/Settings/SqpSettingsDialog.h',
6 6 'include/Settings/SqpSettingsGeneralWidget.h',
7 7 'include/SidePane/SqpSidePane.h',
8 8 'include/SqpApplication.h',
9 9 'include/DragAndDrop/DragDropHelper.h',
10 10 'include/DragAndDrop/DragDropScroller.h',
11 11 'include/DragAndDrop/DragDropTabSwitcher.h',
12 12 'include/TimeWidget/TimeWidget.h',
13 13 'include/Variable/VariableInspectorWidget.h',
14 14 'include/Variable/VariableInspectorTableView.h',
15 15 'include/Variable/RenameVariableDialog.h',
16 16 'include/Visualization/qcustomplot.h',
17 17 'include/Visualization/VisualizationGraphWidget.h',
18 18 'include/Visualization/VisualizationTabWidget.h',
19 19 'include/Visualization/VisualizationWidget.h',
20 20 'include/Visualization/VisualizationZoneWidget.h',
21 21 'include/Visualization/VisualizationDragDropContainer.h',
22 22 'include/Visualization/VisualizationDragWidget.h'
23 23 ]
24 24
25 25 gui_ui_files = [
26 26 'ui/DataSource/DataSourceWidget.ui',
27 27 'ui/Settings/SqpSettingsDialog.ui',
28 28 'ui/Settings/SqpSettingsGeneralWidget.ui',
29 29 'ui/SidePane/SqpSidePane.ui',
30 30 'ui/TimeWidget/TimeWidget.ui',
31 31 'ui/Variable/VariableInspectorWidget.ui',
32 32 'ui/Variable/RenameVariableDialog.ui',
33 33 'ui/Variable/VariableMenuHeaderWidget.ui',
34 34 'ui/Visualization/VisualizationGraphWidget.ui',
35 35 'ui/Visualization/VisualizationTabWidget.ui',
36 36 'ui/Visualization/VisualizationWidget.ui',
37 37 'ui/Visualization/VisualizationZoneWidget.ui'
38 38 ]
39 39
40 40 gui_qresources = ['resources/sqpguiresources.qrc']
41 41
42 42 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
43 43 ui_files : gui_ui_files,
44 44 qresources : gui_qresources)
45 45
46 46 gui_sources = [
47 47 'src/SqpApplication.cpp',
48 48 'src/DragAndDrop/DragDropHelper.cpp',
49 49 'src/DragAndDrop/DragDropScroller.cpp',
50 50 'src/DragAndDrop/DragDropTabSwitcher.cpp',
51 51 'src/Common/ColorUtils.cpp',
52 52 'src/Common/VisualizationDef.cpp',
53 53 'src/DataSource/DataSourceTreeWidgetItem.cpp',
54 54 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
55 55 'src/DataSource/DataSourceWidget.cpp',
56 56 'src/DataSource/DataSourceTreeWidget.cpp',
57 57 'src/Settings/SqpSettingsDialog.cpp',
58 58 'src/Settings/SqpSettingsGeneralWidget.cpp',
59 59 'src/SidePane/SqpSidePane.cpp',
60 60 'src/TimeWidget/TimeWidget.cpp',
61 61 'src/Variable/VariableInspectorWidget.cpp',
62 62 'src/Variable/VariableInspectorTableView.cpp',
63 63 'src/Variable/VariableMenuHeaderWidget.cpp',
64 64 'src/Variable/RenameVariableDialog.cpp',
65 65 'src/Visualization/VisualizationGraphHelper.cpp',
66 66 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
67 67 'src/Visualization/VisualizationGraphWidget.cpp',
68 68 'src/Visualization/VisualizationTabWidget.cpp',
69 69 'src/Visualization/VisualizationWidget.cpp',
70 70 'src/Visualization/VisualizationZoneWidget.cpp',
71 71 'src/Visualization/qcustomplot.cpp',
72 72 'src/Visualization/QCustomPlotSynchronizer.cpp',
73 73 'src/Visualization/operations/FindVariableOperation.cpp',
74 74 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
75 75 'src/Visualization/operations/MenuBuilder.cpp',
76 76 'src/Visualization/operations/RemoveVariableOperation.cpp',
77 77 'src/Visualization/operations/RescaleAxeOperation.cpp',
78 78 'src/Visualization/VisualizationDragDropContainer.cpp',
79 'src/Visualization/VisualizationDragWidget.cpp'
79 'src/Visualization/VisualizationDragWidget.cpp',
80 80 'src/Visualization/AxisRenderingUtils.cpp',
81 'src/Visualization/PlottablesRenderingUtils.cpp'
81 'src/Visualization/PlottablesRenderingUtils.cpp',
82 'src/Visualization/MacScrollBarStyle.cpp'
82 83 ]
83 84
84 85 gui_inc = include_directories(['include'])
85 86
86 87 sciqlop_gui_lib = library('sciqlopgui',
87 88 gui_sources,
88 89 gui_moc_files,
89 90 include_directories : [gui_inc],
90 91 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
91 92 install : true
92 93 )
93 94
94 95 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
95 96 include_directories : gui_inc,
96 97 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
97 98
@@ -1,163 +1,173
1 1 #include "Visualization/AxisRenderingUtils.h"
2 2
3 3 #include <Data/ScalarSeries.h>
4 4 #include <Data/SpectrogramSeries.h>
5 5 #include <Data/VectorSeries.h>
6 6
7 7 #include <Visualization/qcustomplot.h>
8 8
9 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
10
9 11 namespace {
10 12
11 13 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
12 14
13 15 /// Format for datetimes on a axis
14 16 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
15 17
16 18 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
17 19 /// non-time data
18 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
20 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
19 21 {
20 22 if (isTimeAxis) {
21 23 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
22 24 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
23 25 dateTicker->setDateTimeSpec(Qt::UTC);
24 26
25 27 return dateTicker;
26 28 }
29 else if (scaleType == QCPAxis::stLogarithmic) {
30 return QSharedPointer<QCPAxisTickerLog>::create();
31 }
27 32 else {
28 33 // default ticker
29 34 return QSharedPointer<QCPAxisTicker>::create();
30 35 }
31 36 }
32 37
33 38 /**
34 39 * Sets properties of the axis passed as parameter
35 40 * @param axis the axis to set
36 41 * @param unit the unit to set for the axis
37 42 * @param scaleType the scale type to set for the axis
38 43 */
39 44 void setAxisProperties(QCPAxis &axis, const Unit &unit,
40 45 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
41 46 {
42 47 // label (unit name)
43 48 axis.setLabel(unit.m_Name);
44 49
45 50 // scale type
46 51 axis.setScaleType(scaleType);
52 if (scaleType == QCPAxis::stLogarithmic) {
53 // Scientific notation
54 axis.setNumberPrecision(0);
55 axis.setNumberFormat("eb");
56 }
47 57
48 58 // ticker (depending on the type of unit)
49 axis.setTicker(axisTicker(unit.m_TimeUnit));
59 axis.setTicker(axisTicker(unit.m_TimeUnit, scaleType));
50 60 }
51 61
52 62 /**
53 63 * Delegate used to set axes properties
54 64 */
55 65 template <typename T, typename Enabled = void>
56 66 struct AxisSetter {
57 67 static void setProperties(T &, QCustomPlot &, QCPColorScale &)
58 68 {
59 69 // Default implementation does nothing
70 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
60 71 }
61 72 };
62 73
63 74 /**
64 75 * Specialization of AxisSetter for scalars and vectors
65 76 * @sa ScalarSeries
66 77 * @sa VectorSeries
67 78 */
68 79 template <typename T>
69 80 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
70 81 or std::is_base_of<VectorSeries, T>::value> > {
71 82 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &)
72 83 {
73 84 dataSeries.lockRead();
74 85 auto xAxisUnit = dataSeries.xAxisUnit();
75 86 auto valuesUnit = dataSeries.valuesUnit();
76 87 dataSeries.unlock();
77 88
78 89 setAxisProperties(*plot.xAxis, xAxisUnit);
79 90 setAxisProperties(*plot.yAxis, valuesUnit);
80 91 }
81 92 };
82 93
83 94 /**
84 95 * Specialization of AxisSetter for spectrograms
85 96 * @sa SpectrogramSeries
86 97 */
87 98 template <typename T>
88 99 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
89 100 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &colorScale)
90 101 {
91 102 dataSeries.lockRead();
92 103 auto xAxisUnit = dataSeries.xAxisUnit();
93 104 /// @todo ALX: use iterators here
94 105 auto yAxisUnit = dataSeries.yAxis().unit();
95 106 auto valuesUnit = dataSeries.valuesUnit();
96 107 dataSeries.unlock();
97 108
98 109 setAxisProperties(*plot.xAxis, xAxisUnit);
99 setAxisProperties(*plot.yAxis, yAxisUnit);
110 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
100 111
101 112 // Displays color scale in plot
102 113 plot.plotLayout()->insertRow(0);
103 114 plot.plotLayout()->addElement(0, 0, &colorScale);
104 115 colorScale.setType(QCPAxis::atTop);
105 116 colorScale.setMinimumMargins(QMargins{0, 0, 0, 0});
106 117
107 118 // Aligns color scale with axes
108 119 auto marginGroups = plot.axisRect()->marginGroups();
109 120 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
110 121 colorScale.setMarginGroup(it.key(), it.value());
111 122 }
112 123
113 124 // Set color scale properties
114 colorScale.setLabel(valuesUnit.m_Name);
115 colorScale.setDataScaleType(QCPAxis::stLogarithmic); // Logarithmic scale
125 setAxisProperties(*colorScale.axis(), valuesUnit, QCPAxis::stLogarithmic);
116 126 }
117 127 };
118 128
119 129 /**
120 130 * Default implementation of IAxisHelper, which takes data series to set axes properties
121 131 * @tparam T the data series' type
122 132 */
123 133 template <typename T>
124 134 struct AxisHelper : public IAxisHelper {
125 135 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
126 136
127 137 void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override
128 138 {
129 139 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
130 140 }
131 141
132 142 T &m_DataSeries;
133 143 };
134 144
135 145 } // namespace
136 146
137 147 QString formatValue(double value, const QCPAxis &axis)
138 148 {
139 149 // If the axis is a time axis, formats the value as a date
140 150 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
141 151 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
142 152 }
143 153 else {
144 154 return QString::number(value);
145 155 }
146 156 }
147 157
148 158 std::unique_ptr<IAxisHelper>
149 159 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
150 160 {
151 161 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
152 162 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
153 163 }
154 164 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
155 165 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
156 166 }
157 167 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
158 168 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
159 169 }
160 170 else {
161 171 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
162 172 }
163 173 }
@@ -1,120 +1,127
1 1 #include "Visualization/PlottablesRenderingUtils.h"
2 2
3 3 #include <Common/ColorUtils.h>
4 4
5 5 #include <Data/ScalarSeries.h>
6 6 #include <Data/SpectrogramSeries.h>
7 7 #include <Data/VectorSeries.h>
8 8
9 9 #include <Visualization/qcustomplot.h>
10 10
11 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
12
11 13 namespace {
12 14
13 15 /// Default gradient used for colormap
14 16 const auto DEFAULT_COLORMAP_GRADIENT = QCPColorGradient::gpJet;
15 17
16 18 /**
17 19 * Delegate used to set plottables properties
18 20 */
19 21 template <typename T, typename Enabled = void>
20 22 struct PlottablesSetter {
21 23 static void setProperties(T &, PlottablesMap &)
22 24 {
23 25 // Default implementation does nothing
26 qCCritical(LOG_PlottablesRenderingUtils())
27 << "Can't set plottables properties: unmanaged type of data";
24 28 }
25 29 };
26 30
27 31 /**
28 32 * Specialization of PlottablesSetter for scalars and vectors
29 33 * @sa ScalarSeries
30 34 * @sa VectorSeries
31 35 */
32 36 template <typename T>
33 37 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
34 38 or std::is_base_of<VectorSeries, T>::value> > {
35 39 static void setProperties(T &dataSeries, PlottablesMap &plottables)
36 40 {
37 41 // Gets the number of components of the data series
38 42 dataSeries.lockRead();
39 43 auto componentCount = dataSeries.valuesData()->componentCount();
40 44 dataSeries.unlock();
41 45
42 46 // Generates colors for each component
43 47 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
44 48
45 49 // For each component of the data series, creates a QCPGraph to add to the plot
46 50 for (auto i = 0; i < componentCount; ++i) {
47 51 auto graph = plottables.at(i);
48 52 graph->setPen(QPen{colors.at(i)});
49 53 }
50 54 }
51 55 };
52 56
53 57 /**
54 58 * Specialization of PlottablesSetter for spectrograms
55 59 * @sa SpectrogramSeries
56 60 */
57 61 template <typename T>
58 62 struct PlottablesSetter<T,
59 63 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
60 64 static void setProperties(T &, PlottablesMap &plottables)
61 65 {
62 66 // Checks that for a spectrogram there is only one plottable, that is a colormap
63 67 if (plottables.size() != 1) {
64 68 return;
65 69 }
66 70
67 71 if (auto colormap = dynamic_cast<QCPColorMap *>(plottables.begin()->second)) {
68 72 colormap->setInterpolate(false); // No value interpolation
69 73 colormap->setTightBoundary(true);
70 74
71 75 // Finds color scale in the colormap's plot to associate with it
72 76 auto plot = colormap->parentPlot();
73 77 auto plotElements = plot->plotLayout()->elements(false);
74 78 for (auto plotElement : plotElements) {
75 79 if (auto colorScale = dynamic_cast<QCPColorScale *>(plotElement)) {
76 80 colormap->setColorScale(colorScale);
77 81 }
78 82 }
79 83
80 84 // Sets gradient used for color scale
81 85 colormap->setGradient(DEFAULT_COLORMAP_GRADIENT);
82 86 colormap->rescaleDataRange();
83 87 }
88 else {
89 qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram";
90 }
84 91 }
85 92 };
86 93
87 94 /**
88 95 * Default implementation of IPlottablesHelper, which takes data series to set plottables properties
89 96 * @tparam T the data series' type
90 97 */
91 98 template <typename T>
92 99 struct PlottablesHelper : public IPlottablesHelper {
93 100 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
94 101
95 102 void setProperties(PlottablesMap &plottables) override
96 103 {
97 104 PlottablesSetter<T>::setProperties(m_DataSeries, plottables);
98 105 }
99 106
100 107 T &m_DataSeries;
101 108 };
102 109
103 110 } // namespace
104 111
105 112 std::unique_ptr<IPlottablesHelper>
106 113 IPlottablesHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
107 114 {
108 115 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
109 116 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
110 117 }
111 118 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
112 119 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
113 120 }
114 121 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
115 122 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
116 123 }
117 124 else {
118 125 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
119 126 }
120 127 }
@@ -1,309 +1,319
1 1 #include "Visualization/VisualizationTabWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "ui_VisualizationTabWidget.h"
4 4
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7
8 #include "Visualization/MacScrollBarStyle.h"
9
8 10 #include "Variable/VariableController.h"
9 11
10 12 #include "Common/MimeTypesDef.h"
11 13
12 14 #include "DragAndDrop/DragDropHelper.h"
13 15 #include "SqpApplication.h"
14 16
15 17 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
16 18
17 19 namespace {
18 20
19 21 /// Generates a default name for a new zone, according to the number of zones already displayed in
20 22 /// the tab
21 23 QString defaultZoneName(const QLayout &layout)
22 24 {
23 25 auto count = 0;
24 26 for (auto i = 0; i < layout.count(); ++i) {
25 27 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
26 28 count++;
27 29 }
28 30 }
29 31
30 32 return QObject::tr("Zone %1").arg(count + 1);
31 33 }
32 34
33 35 /**
34 36 * Applies a function to all zones of the tab represented by its layout
35 37 * @param layout the layout that contains zones
36 38 * @param fun the function to apply to each zone
37 39 */
38 40 template <typename Fun>
39 41 void processZones(QLayout &layout, Fun fun)
40 42 {
41 43 for (auto i = 0; i < layout.count(); ++i) {
42 44 if (auto item = layout.itemAt(i)) {
43 45 if (auto visualizationZoneWidget
44 46 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
45 47 fun(*visualizationZoneWidget);
46 48 }
47 49 }
48 50 }
49 51 }
50 52
51 53 } // namespace
52 54
53 55 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
54 56 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
55 57
56 58 QString m_Name;
57 59
60 #ifdef Q_OS_MAC
61 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
62 #endif
63
58 64 void dropGraph(int index, VisualizationTabWidget *tabWidget);
59 65 void dropZone(int index, VisualizationTabWidget *tabWidget);
60 66 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
61 67 VisualizationTabWidget *tabWidget);
62 68 };
63 69
64 70 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
65 71 : QWidget{parent},
66 72 ui{new Ui::VisualizationTabWidget},
67 73 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
68 74 {
69 75 ui->setupUi(this);
70 76
77 #ifdef Q_OS_MAC
78 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
79 #endif
80
71 81 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone");
72 82 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 5);
73 83 ui->dragDropContainer->addAcceptedMimeType(
74 84 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
75 85 ui->dragDropContainer->addAcceptedMimeType(
76 86 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
77 87 ui->dragDropContainer->addAcceptedMimeType(
78 88 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
79 89
80 90 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
81 91 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
82 92 ui->dragDropContainer);
83 93 });
84 94
85 95 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
86 96 &VisualizationTabWidget::dropMimeData);
87 97
88 98 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
89 99
90 100 // Widget is deleted when closed
91 101 setAttribute(Qt::WA_DeleteOnClose);
92 102 }
93 103
94 104 VisualizationTabWidget::~VisualizationTabWidget()
95 105 {
96 106 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
97 107 delete ui;
98 108 }
99 109
100 110 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
101 111 {
102 112 ui->dragDropContainer->addDragWidget(zoneWidget);
103 113 }
104 114
105 115 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
106 116 {
107 117 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
108 118 }
109 119
110 120 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
111 121 {
112 122 return createZone({variable}, -1);
113 123 }
114 124
115 125 VisualizationZoneWidget *
116 126 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
117 127 {
118 128 auto zoneWidget = createEmptyZone(index);
119 129
120 130 // Creates a new graph into the zone
121 131 zoneWidget->createGraph(variables, index);
122 132
123 133 return zoneWidget;
124 134 }
125 135
126 136 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
127 137 {
128 138 auto zoneWidget
129 139 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
130 140 this->insertZone(index, zoneWidget);
131 141
132 142 return zoneWidget;
133 143 }
134 144
135 145 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
136 146 {
137 147 if (visitor) {
138 148 visitor->visitEnter(this);
139 149
140 150 // Apply visitor to zone children: widgets different from zones are not visited (no action)
141 151 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
142 152 zoneWidget.accept(visitor);
143 153 });
144 154
145 155 visitor->visitLeave(this);
146 156 }
147 157 else {
148 158 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
149 159 }
150 160 }
151 161
152 162 bool VisualizationTabWidget::canDrop(const Variable &variable) const
153 163 {
154 164 // A tab can always accomodate a variable
155 165 Q_UNUSED(variable);
156 166 return true;
157 167 }
158 168
159 169 bool VisualizationTabWidget::contains(const Variable &variable) const
160 170 {
161 171 Q_UNUSED(variable);
162 172 return false;
163 173 }
164 174
165 175 QString VisualizationTabWidget::name() const
166 176 {
167 177 return impl->m_Name;
168 178 }
169 179
170 180 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
171 181 {
172 182 // Closes zones in the tab
173 183 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
174 184
175 185 QWidget::closeEvent(event);
176 186 }
177 187
178 188 QLayout &VisualizationTabWidget::tabLayout() const noexcept
179 189 {
180 190 return *ui->dragDropContainer->layout();
181 191 }
182 192
183 193 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
184 194 {
185 195 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
186 196 impl->dropGraph(index, this);
187 197 }
188 198 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
189 199 impl->dropZone(index, this);
190 200 }
191 201 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
192 202 auto variables = sqpApp->variableController().variablesForMimeData(
193 203 mimeData->data(MIME_TYPE_VARIABLE_LIST));
194 204 impl->dropVariables(variables, index, this);
195 205 }
196 206 else {
197 207 qCWarning(LOG_VisualizationZoneWidget())
198 208 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
199 209 }
200 210 }
201 211
202 212 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
203 213 int index, VisualizationTabWidget *tabWidget)
204 214 {
205 215 auto &helper = sqpApp->dragDropHelper();
206 216
207 217 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
208 218 if (!graphWidget) {
209 219 qCWarning(LOG_VisualizationZoneWidget())
210 220 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
211 221 "found or invalid.");
212 222 Q_ASSERT(false);
213 223 return;
214 224 }
215 225
216 226 auto parentDragDropContainer
217 227 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
218 228 if (!parentDragDropContainer) {
219 229 qCWarning(LOG_VisualizationZoneWidget())
220 230 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
221 231 "the dropped graph is not found.");
222 232 Q_ASSERT(false);
223 233 return;
224 234 }
225 235
226 236 auto nbGraph = parentDragDropContainer->countDragWidget();
227 237
228 238 const auto &variables = graphWidget->variables();
229 239
230 240 if (!variables.isEmpty()) {
231 241 // Abort the requests for the variables (if any)
232 242 // Commented, because it's not sure if it's needed or not
233 243 // for (const auto& var : variables)
234 244 //{
235 245 // sqpApp->variableController().onAbortProgressRequested(var);
236 246 //}
237 247
238 248 if (nbGraph == 1) {
239 249 // This is the only graph in the previous zone, close the zone
240 250 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
241 251 }
242 252 else {
243 253 // Close the graph
244 254 helper.delayedCloseWidget(graphWidget);
245 255 }
246 256
247 257 tabWidget->createZone(variables, index);
248 258 }
249 259 else {
250 260 // The graph is empty, create an empty zone and move the graph inside
251 261
252 262 auto parentZoneWidget = graphWidget->parentZoneWidget();
253 263
254 264 parentDragDropContainer->layout()->removeWidget(graphWidget);
255 265
256 266 auto zoneWidget = tabWidget->createEmptyZone(index);
257 267 zoneWidget->addGraph(graphWidget);
258 268
259 269 // Close the old zone if it was the only graph inside
260 270 if (nbGraph == 1) {
261 271 helper.delayedCloseWidget(parentZoneWidget);
262 272 }
263 273 }
264 274 }
265 275
266 276 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
267 277 int index, VisualizationTabWidget *tabWidget)
268 278 {
269 279 auto &helper = sqpApp->dragDropHelper();
270 280
271 281 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
272 282 if (!zoneWidget) {
273 283 qCWarning(LOG_VisualizationZoneWidget())
274 284 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
275 285 "found or invalid.");
276 286 Q_ASSERT(false);
277 287 return;
278 288 }
279 289
280 290 auto parentDragDropContainer
281 291 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
282 292 if (!parentDragDropContainer) {
283 293 qCWarning(LOG_VisualizationZoneWidget())
284 294 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
285 295 "the dropped zone is not found.");
286 296 Q_ASSERT(false);
287 297 return;
288 298 }
289 299
290 300 // Simple move of the zone, no variable operation associated
291 301 parentDragDropContainer->layout()->removeWidget(zoneWidget);
292 302 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
293 303 }
294 304
295 305 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
296 306 const QList<std::shared_ptr<Variable> > &variables, int index,
297 307 VisualizationTabWidget *tabWidget)
298 308 {
299 309 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
300 310 // compatible variable here
301 311 if (variables.count() > 1) {
302 312 qCWarning(LOG_VisualizationZoneWidget())
303 313 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
304 314 "aborted.");
305 315 return;
306 316 }
307 317
308 318 tabWidget->createZone(variables, index);
309 319 }
General Comments 0
You need to be logged in to leave comments. Login now