##// END OF EJS Templates
Merge branch 'feature/MacDragDropBug' into develop
trabillard -
r914:c27e75f2f261 merge
parent child
Show More
@@ -1,151 +1,151
1 #include <Data/ArrayData.h>
1 #include <Data/ArrayData.h>
2 #include <Data/OptionalAxis.h>
2 #include <Data/OptionalAxis.h>
3
3
4 #include <QObject>
4 #include <QObject>
5 #include <QtTest>
5 #include <QtTest>
6
6
7 Q_DECLARE_METATYPE(OptionalAxis)
7 Q_DECLARE_METATYPE(OptionalAxis)
8 Q_DECLARE_METATYPE(Unit)
8 Q_DECLARE_METATYPE(Unit)
9
9
10 class TestOptionalAxis : public QObject {
10 class TestOptionalAxis : public QObject {
11 Q_OBJECT
11 Q_OBJECT
12
12
13 private slots:
13 private slots:
14 /// Tests the creation of a undefined axis
14 /// Tests the creation of a undefined axis
15 void testNotDefinedAxisCtor();
15 void testNotDefinedAxisCtor();
16
16
17 /// Tests the creation of a undefined axis
17 /// Tests the creation of a undefined axis
18 void testDefinedAxisCtor_data();
18 void testDefinedAxisCtor_data();
19 void testDefinedAxisCtor();
19 void testDefinedAxisCtor();
20
20
21 /// Tests @sa OptionalAxis::at() method
21 /// Tests @sa OptionalAxis::at() method
22 void testAt_data();
22 void testAt_data();
23 void testAt();
23 void testAt();
24
24
25 /// Tests @sa OptionalAxis::size() method
25 /// Tests @sa OptionalAxis::size() method
26 void testSize_data();
26 void testSize_data();
27 void testSize();
27 void testSize();
28
28
29 /// Tests @sa OptionalAxis::unit() method
29 /// Tests @sa OptionalAxis::unit() method
30 void testUnit_data();
30 void testUnit_data();
31 void testUnit();
31 void testUnit();
32 };
32 };
33
33
34 void TestOptionalAxis::testNotDefinedAxisCtor()
34 void TestOptionalAxis::testNotDefinedAxisCtor()
35 {
35 {
36 OptionalAxis notDefinedAxis{};
36 OptionalAxis notDefinedAxis{};
37 QVERIFY(!notDefinedAxis.isDefined());
37 QVERIFY(!notDefinedAxis.isDefined());
38 }
38 }
39
39
40 void TestOptionalAxis::testDefinedAxisCtor_data()
40 void TestOptionalAxis::testDefinedAxisCtor_data()
41 {
41 {
42 QTest::addColumn<bool>("noData"); // If set to true, nullptr is passed as data of the axis
42 QTest::addColumn<bool>("noData"); // If set to true, nullptr is passed as data of the axis
43 QTest::addColumn<std::vector<double> >(
43 QTest::addColumn<std::vector<double> >(
44 "data"); // Values assigned to the axis when 'noData' flag is set to false
44 "data"); // Values assigned to the axis when 'noData' flag is set to false
45 QTest::addColumn<Unit>("unit"); // Unit assigned to the axis
45 QTest::addColumn<Unit>("unit"); // Unit assigned to the axis
46
46
47 QTest::newRow("validData") << false << std::vector<double>{1, 2, 3} << Unit{"Hz"};
47 QTest::newRow("validData") << false << std::vector<double>{1, 2, 3} << Unit{"Hz"};
48 QTest::newRow("invalidData") << true << std::vector<double>{} << Unit{"Hz"};
48 QTest::newRow("invalidData") << true << std::vector<double>{} << Unit{"Hz"};
49 }
49 }
50
50
51 void TestOptionalAxis::testDefinedAxisCtor()
51 void TestOptionalAxis::testDefinedAxisCtor()
52 {
52 {
53 QFETCH(bool, noData);
53 QFETCH(bool, noData);
54 QFETCH(Unit, unit);
54 QFETCH(Unit, unit);
55
55
56 // When there is no data, we expect that the constructor returns exception
56 // When there is no data, we expect that the constructor returns exception
57 if (noData) {
57 if (noData) {
58 QVERIFY_EXCEPTION_THROWN(OptionalAxis(nullptr, unit), std::invalid_argument);
58 QVERIFY_EXCEPTION_THROWN(OptionalAxis(nullptr, unit), std::invalid_argument);
59 }
59 }
60 else {
60 else {
61 QFETCH(std::vector<double>, data);
61 QFETCH(std::vector<double>, data);
62
62
63 OptionalAxis axis{std::make_shared<ArrayData<1> >(data), unit};
63 OptionalAxis axis{std::make_shared<ArrayData<1> >(data), unit};
64 QVERIFY(axis.isDefined());
64 QVERIFY(axis.isDefined());
65 }
65 }
66 }
66 }
67
67
68 void TestOptionalAxis::testAt_data()
68 void TestOptionalAxis::testAt_data()
69 {
69 {
70 QTest::addColumn<OptionalAxis>("axis"); // Axis used for test case (defined or not)
70 QTest::addColumn<OptionalAxis>("axis"); // Axis used for test case (defined or not)
71 QTest::addColumn<int>("index"); // Index to test in the axis
71 QTest::addColumn<int>("index"); // Index to test in the axis
72 QTest::addColumn<double>("expectedValue"); // Expected axis value for the index
72 QTest::addColumn<double>("expectedValue"); // Expected axis value for the index
73
73
74 OptionalAxis definedAxis{std::make_shared<ArrayData<1> >(std::vector<double>{1, 2, 3}),
74 OptionalAxis definedAxis{std::make_shared<ArrayData<1> >(std::vector<double>{1, 2, 3}),
75 Unit{"Hz"}};
75 Unit{"Hz"}};
76
76
77 QTest::newRow("data1") << definedAxis << 0 << 1.;
77 QTest::newRow("data1") << definedAxis << 0 << 1.;
78 QTest::newRow("data2") << definedAxis << 1 << 2.;
78 QTest::newRow("data2") << definedAxis << 1 << 2.;
79 QTest::newRow("data3") << definedAxis << 2 << 3.;
79 QTest::newRow("data3") << definedAxis << 2 << 3.;
80 QTest::newRow("data4 (index out of bounds)")
80 QTest::newRow("data4 (index out of bounds)")
81 << definedAxis << 3
81 << definedAxis << 3
82 << std::numeric_limits<double>::quiet_NaN(); // Expects NaN for out of bounds index
82 << std::numeric_limits<double>::quiet_NaN(); // Expects NaN for out of bounds index
83 QTest::newRow("data5 (index out of bounds)")
83 QTest::newRow("data5 (index out of bounds)")
84 << definedAxis << -1
84 << definedAxis << -1
85 << std::numeric_limits<double>::quiet_NaN(); // Expects NaN for out of bounds index
85 << std::numeric_limits<double>::quiet_NaN(); // Expects NaN for out of bounds index
86 QTest::newRow("data6 (axis not defined)")
86 QTest::newRow("data6 (axis not defined)")
87 << OptionalAxis{} << 0
87 << OptionalAxis{} << 0
88 << std::numeric_limits<double>::quiet_NaN(); // Expects NaN for undefined axis
88 << std::numeric_limits<double>::quiet_NaN(); // Expects NaN for undefined axis
89 }
89 }
90
90
91 void TestOptionalAxis::testAt()
91 void TestOptionalAxis::testAt()
92 {
92 {
93 QFETCH(OptionalAxis, axis);
93 QFETCH(OptionalAxis, axis);
94 QFETCH(int, index);
94 QFETCH(int, index);
95 QFETCH(double, expectedValue);
95 QFETCH(double, expectedValue);
96
96
97 auto value = axis.at(index);
97 auto value = axis.at(index);
98 QVERIFY((std::isnan(value) && std::isnan(expectedValue)) || value == expectedValue);
98 QVERIFY((std::isnan(value) && std::isnan(expectedValue)) || value == expectedValue);
99 }
99 }
100
100
101 void TestOptionalAxis::testSize_data()
101 void TestOptionalAxis::testSize_data()
102 {
102 {
103 QTest::addColumn<OptionalAxis>("axis"); // Axis used for test case (defined or not)
103 QTest::addColumn<OptionalAxis>("axis"); // Axis used for test case (defined or not)
104 QTest::addColumn<int>("expectedSize"); // Expected number of data in the axis
104 QTest::addColumn<int>("expectedSize"); // Expected number of data in the axis
105
105
106 // Lambda that creates default defined axis (with the values passed in parameter)
106 // Lambda that creates default defined axis (with the values passed in parameter)
107 auto axis = [](std::vector<double> values) {
107 auto axis = [](std::vector<double> values) {
108 return OptionalAxis{std::make_shared<ArrayData<1> >(std::move(values)), Unit{"Hz"}};
108 return OptionalAxis{std::make_shared<ArrayData<1> >(std::move(values)), Unit{"Hz"}};
109 };
109 };
110
110
111 QTest::newRow("data1") << axis({}) << 0;
111 QTest::newRow("data1") << axis({}) << 0;
112 QTest::newRow("data2") << axis({1, 2, 3}) << 3;
112 QTest::newRow("data2") << axis({1, 2, 3}) << 3;
113 QTest::newRow("data3") << axis({1, 2, 3, 4}) << 4;
113 QTest::newRow("data3") << axis({1, 2, 3, 4}) << 4;
114 QTest::newRow("data4 (axis not defined)")
114 QTest::newRow("data4 (axis not defined)") << OptionalAxis{}
115 << OptionalAxis{} << 0; // Expects 0 for undefined axis
115 << 0; // Expects 0 for undefined axis
116 }
116 }
117
117
118 void TestOptionalAxis::testSize()
118 void TestOptionalAxis::testSize()
119 {
119 {
120 QFETCH(OptionalAxis, axis);
120 QFETCH(OptionalAxis, axis);
121 QFETCH(int, expectedSize);
121 QFETCH(int, expectedSize);
122
122
123 QCOMPARE(axis.size(), expectedSize);
123 QCOMPARE(axis.size(), expectedSize);
124 }
124 }
125
125
126 void TestOptionalAxis::testUnit_data()
126 void TestOptionalAxis::testUnit_data()
127 {
127 {
128 QTest::addColumn<OptionalAxis>("axis"); // Axis used for test case (defined or not)
128 QTest::addColumn<OptionalAxis>("axis"); // Axis used for test case (defined or not)
129 QTest::addColumn<Unit>("expectedUnit"); // Expected unit for the axis
129 QTest::addColumn<Unit>("expectedUnit"); // Expected unit for the axis
130
130
131 // Lambda that creates default defined axis (with the unit passed in parameter)
131 // Lambda that creates default defined axis (with the unit passed in parameter)
132 auto axis = [](Unit unit) {
132 auto axis = [](Unit unit) {
133 return OptionalAxis{std::make_shared<ArrayData<1> >(std::vector<double>{1, 2, 3}), unit};
133 return OptionalAxis{std::make_shared<ArrayData<1> >(std::vector<double>{1, 2, 3}), unit};
134 };
134 };
135
135
136 QTest::newRow("data1") << axis(Unit{"Hz"}) << Unit{"Hz"};
136 QTest::newRow("data1") << axis(Unit{"Hz"}) << Unit{"Hz"};
137 QTest::newRow("data2") << axis(Unit{"t", true}) << Unit{"t", true};
137 QTest::newRow("data2") << axis(Unit{"t", true}) << Unit{"t", true};
138 QTest::newRow("data3 (axis not defined)")
138 QTest::newRow("data3 (axis not defined)") << OptionalAxis{}
139 << OptionalAxis{} << Unit{}; // Expects default unit for undefined axis
139 << Unit{}; // Expects default unit for undefined axis
140 }
140 }
141
141
142 void TestOptionalAxis::testUnit()
142 void TestOptionalAxis::testUnit()
143 {
143 {
144 QFETCH(OptionalAxis, axis);
144 QFETCH(OptionalAxis, axis);
145 QFETCH(Unit, expectedUnit);
145 QFETCH(Unit, expectedUnit);
146
146
147 QCOMPARE(axis.unit(), expectedUnit);
147 QCOMPARE(axis.unit(), expectedUnit);
148 }
148 }
149
149
150 QTEST_MAIN(TestOptionalAxis)
150 QTEST_MAIN(TestOptionalAxis)
151 #include "TestOptionalAxis.moc"
151 #include "TestOptionalAxis.moc"
@@ -1,426 +1,426
1 #include "Data/ScalarSeries.h"
1 #include "Data/ScalarSeries.h"
2
2
3 #include "DataSeriesBuilders.h"
3 #include "DataSeriesBuilders.h"
4 #include "DataSeriesUtils.h"
4 #include "DataSeriesUtils.h"
5
5
6 #include <QObject>
6 #include <QObject>
7 #include <QtTest>
7 #include <QtTest>
8
8
9 /**
9 /**
10 * @brief The TestScalarSeries class defines unit tests on scalar series.
10 * @brief The TestScalarSeries class defines unit tests on scalar series.
11 *
11 *
12 * Most of these unit tests use generic tests defined for DataSeries (@sa DataSeriesUtils)
12 * Most of these unit tests use generic tests defined for DataSeries (@sa DataSeriesUtils)
13 */
13 */
14 class TestScalarSeries : public QObject {
14 class TestScalarSeries : public QObject {
15 Q_OBJECT
15 Q_OBJECT
16 private slots:
16 private slots:
17 /// Tests construction of a scalar series
17 /// Tests construction of a scalar series
18 void testCtor_data();
18 void testCtor_data();
19 void testCtor();
19 void testCtor();
20
20
21 /// Tests merge of two scalar series
21 /// Tests merge of two scalar series
22 void testMerge_data();
22 void testMerge_data();
23 void testMerge();
23 void testMerge();
24
24
25 /// Tests merge of a vector series in a scalar series
25 /// Tests merge of a vector series in a scalar series
26 void testMergeWithVector_data();
26 void testMergeWithVector_data();
27 void testMergeWithVector();
27 void testMergeWithVector();
28
28
29 /// Tests get min x-axis data of a scalar series
29 /// Tests get min x-axis data of a scalar series
30 void testMinXAxisData_data();
30 void testMinXAxisData_data();
31 void testMinXAxisData();
31 void testMinXAxisData();
32
32
33 /// Tests get max x-axis data of a scalar series
33 /// Tests get max x-axis data of a scalar series
34 void testMaxXAxisData_data();
34 void testMaxXAxisData_data();
35 void testMaxXAxisData();
35 void testMaxXAxisData();
36
36
37 /// Tests purge of a scalar series
37 /// Tests purge of a scalar series
38 void testPurge_data();
38 void testPurge_data();
39 void testPurge();
39 void testPurge();
40
40
41 /// Tests get x-axis range of a scalar series
41 /// Tests get x-axis range of a scalar series
42 void testXAxisRange_data();
42 void testXAxisRange_data();
43 void testXAxisRange();
43 void testXAxisRange();
44
44
45 /// Tests get values bounds of a scalar series
45 /// Tests get values bounds of a scalar series
46 void testValuesBounds_data();
46 void testValuesBounds_data();
47 void testValuesBounds();
47 void testValuesBounds();
48 };
48 };
49
49
50 void TestScalarSeries::testCtor_data()
50 void TestScalarSeries::testCtor_data()
51 {
51 {
52 // x-axis data
52 // x-axis data
53 QTest::addColumn<DataContainer>("xAxisData");
53 QTest::addColumn<DataContainer>("xAxisData");
54 // values data
54 // values data
55 QTest::addColumn<DataContainer>("valuesData");
55 QTest::addColumn<DataContainer>("valuesData");
56
56
57 // construction expected to be valid
57 // construction expected to be valid
58 QTest::addColumn<bool>("expectOK");
58 QTest::addColumn<bool>("expectOK");
59 // expected x-axis data (when construction is valid)
59 // expected x-axis data (when construction is valid)
60 QTest::addColumn<DataContainer>("expectedXAxisData");
60 QTest::addColumn<DataContainer>("expectedXAxisData");
61 // expected values data (when construction is valid)
61 // expected values data (when construction is valid)
62 QTest::addColumn<DataContainer>("expectedValuesData");
62 QTest::addColumn<DataContainer>("expectedValuesData");
63
63
64 QTest::newRow("invalidData (different sizes of vectors)")
64 QTest::newRow("invalidData (different sizes of vectors)")
65 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << false
65 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << false
66 << DataContainer{} << DataContainer{};
66 << DataContainer{} << DataContainer{};
67
67
68 QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.}
68 QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.}
69 << DataContainer{100., 200., 300., 400., 500.} << true
69 << DataContainer{100., 200., 300., 400., 500.} << true
70 << DataContainer{1., 2., 3., 4., 5.}
70 << DataContainer{1., 2., 3., 4., 5.}
71 << DataContainer{100., 200., 300., 400., 500.};
71 << DataContainer{100., 200., 300., 400., 500.};
72
72
73 QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.}
73 QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.}
74 << DataContainer{100., 200., 300., 400., 500.} << true
74 << DataContainer{100., 200., 300., 400., 500.} << true
75 << DataContainer{1., 2., 3., 4., 5.}
75 << DataContainer{1., 2., 3., 4., 5.}
76 << DataContainer{500., 400., 300., 200., 100.};
76 << DataContainer{500., 400., 300., 200., 100.};
77
77
78 QTest::newRow("unsortedData2")
78 QTest::newRow("unsortedData2")
79 << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.} << true
79 << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.} << true
80 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.};
80 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.};
81 }
81 }
82
82
83 void TestScalarSeries::testCtor()
83 void TestScalarSeries::testCtor()
84 {
84 {
85 // Creates series
85 // Creates series
86 QFETCH(DataContainer, xAxisData);
86 QFETCH(DataContainer, xAxisData);
87 QFETCH(DataContainer, valuesData);
87 QFETCH(DataContainer, valuesData);
88 QFETCH(bool, expectOK);
88 QFETCH(bool, expectOK);
89
89
90 if (expectOK) {
90 if (expectOK) {
91 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
91 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
92 Unit{}, Unit{});
92 Unit{}, Unit{});
93
93
94 // Validates results : we check that the data series is sorted on its x-axis data
94 // Validates results : we check that the data series is sorted on its x-axis data
95 QFETCH(DataContainer, expectedXAxisData);
95 QFETCH(DataContainer, expectedXAxisData);
96 QFETCH(DataContainer, expectedValuesData);
96 QFETCH(DataContainer, expectedValuesData);
97
97
98 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
98 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
99 }
99 }
100 else {
100 else {
101 QVERIFY_EXCEPTION_THROWN(std::make_shared<ScalarSeries>(
101 QVERIFY_EXCEPTION_THROWN(std::make_shared<ScalarSeries>(
102 std::move(xAxisData), std::move(valuesData), Unit{}, Unit{}),
102 std::move(xAxisData), std::move(valuesData), Unit{}, Unit{}),
103 std::invalid_argument);
103 std::invalid_argument);
104 }
104 }
105 }
105 }
106
106
107 void TestScalarSeries::testMerge_data()
107 void TestScalarSeries::testMerge_data()
108 {
108 {
109 testMerge_struct<ScalarSeries, DataContainer>();
109 testMerge_struct<ScalarSeries, DataContainer>();
110
110
111 QTest::newRow("sortedMerge") << ScalarBuilder{}
111 QTest::newRow("sortedMerge") << ScalarBuilder{}
112 .setX({1., 2., 3., 4., 5.})
112 .setX({1., 2., 3., 4., 5.})
113 .setValues({100., 200., 300., 400., 500.})
113 .setValues({100., 200., 300., 400., 500.})
114 .build()
114 .build()
115 << ScalarBuilder{}
115 << ScalarBuilder{}
116 .setX({6., 7., 8., 9., 10.})
116 .setX({6., 7., 8., 9., 10.})
117 .setValues({600., 700., 800., 900., 1000.})
117 .setValues({600., 700., 800., 900., 1000.})
118 .build()
118 .build()
119 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
119 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
120 << DataContainer{100., 200., 300., 400., 500.,
120 << DataContainer{100., 200., 300., 400., 500.,
121 600., 700., 800., 900., 1000.};
121 600., 700., 800., 900., 1000.};
122
122
123 QTest::newRow("unsortedMerge")
123 QTest::newRow("unsortedMerge")
124 << ScalarBuilder{}
124 << ScalarBuilder{}
125 .setX({6., 7., 8., 9., 10.})
125 .setX({6., 7., 8., 9., 10.})
126 .setValues({600., 700., 800., 900., 1000.})
126 .setValues({600., 700., 800., 900., 1000.})
127 .build()
127 .build()
128 << ScalarBuilder{}
128 << ScalarBuilder{}
129 .setX({1., 2., 3., 4., 5.})
129 .setX({1., 2., 3., 4., 5.})
130 .setValues({100., 200., 300., 400., 500.})
130 .setValues({100., 200., 300., 400., 500.})
131 .build()
131 .build()
132 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
132 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
133 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
133 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
134
134
135 QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)")
135 QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)")
136 << ScalarBuilder{}
136 << ScalarBuilder{}
137 .setX({1., 2., 8., 9., 10})
137 .setX({1., 2., 8., 9., 10})
138 .setValues({100., 200., 800., 900., 1000.})
138 .setValues({100., 200., 800., 900., 1000.})
139 .build()
139 .build()
140 << ScalarBuilder{}
140 << ScalarBuilder{}
141 .setX({3., 4., 5., 6., 7.})
141 .setX({3., 4., 5., 6., 7.})
142 .setValues({300., 400., 500., 600., 700.})
142 .setValues({300., 400., 500., 600., 700.})
143 .build()
143 .build()
144 << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.};
144 << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.};
145
145
146 QTest::newRow("unsortedMerge3")
146 QTest::newRow("unsortedMerge3")
147 << ScalarBuilder{}
147 << ScalarBuilder{}
148 .setX({3., 4., 5., 7., 8})
148 .setX({3., 4., 5., 7., 8})
149 .setValues({300., 400., 500., 700., 800.})
149 .setValues({300., 400., 500., 700., 800.})
150 .build()
150 .build()
151 << ScalarBuilder{}
151 << ScalarBuilder{}
152 .setX({1., 2., 3., 7., 10.})
152 .setX({1., 2., 3., 7., 10.})
153 .setValues({100., 200., 333., 777., 1000.})
153 .setValues({100., 200., 333., 777., 1000.})
154 .build()
154 .build()
155 << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.}
155 << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.}
156 << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.};
156 << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.};
157
157
158 QTest::newRow("emptySource") << ScalarBuilder{}
158 QTest::newRow("emptySource") << ScalarBuilder{}
159 .setX({3., 4., 5., 7., 8})
159 .setX({3., 4., 5., 7., 8})
160 .setValues({300., 400., 500., 700., 800.})
160 .setValues({300., 400., 500., 700., 800.})
161 .build()
161 .build()
162 << ScalarBuilder{}.setX({}).setValues({}).build()
162 << ScalarBuilder{}.setX({}).setValues({}).build()
163 << DataContainer{3., 4., 5., 7., 8.}
163 << DataContainer{3., 4., 5., 7., 8.}
164 << DataContainer{300., 400., 500., 700., 800.};
164 << DataContainer{300., 400., 500., 700., 800.};
165 }
165 }
166
166
167 void TestScalarSeries::testMerge()
167 void TestScalarSeries::testMerge()
168 {
168 {
169 testMerge_t<ScalarSeries, DataContainer>();
169 testMerge_t<ScalarSeries, DataContainer>();
170 }
170 }
171
171
172 void TestScalarSeries::testMergeWithVector_data()
172 void TestScalarSeries::testMergeWithVector_data()
173 {
173 {
174 testMergeDifferentTypes_struct<VectorSeries, ScalarSeries>();
174 testMergeDifferentTypes_struct<VectorSeries, ScalarSeries>();
175
175
176 QTest::newRow("mergeVectorInScalar")
176 QTest::newRow("mergeVectorInScalar") << ScalarBuilder{}
177 << ScalarBuilder{}
177 .setX({1., 2., 3., 4., 5.})
178 .setX({1., 2., 3., 4., 5.})
178 .setValues({100., 200., 300., 400., 500.})
179 .setValues({100., 200., 300., 400., 500.})
179 .build()
180 .build()
180 << VectorBuilder{}
181 << VectorBuilder{}
181 .setX({6., 7., 8., 9., 10.})
182 .setX({6., 7., 8., 9., 10.})
182 .setXValues({600., 700., 800., 900., 1000.})
183 .setXValues({600., 700., 800., 900., 1000.})
183 .setYValues({610., 710., 810., 910., 1010.})
184 .setYValues({610., 710., 810., 910., 1010.})
184 .setZValues({620., 720., 820., 920., 1020.})
185 .setZValues({620., 720., 820., 920., 1020.})
185 .build()
186 .build()
186 << DataContainer{1., 2., 3., 4., 5.}
187 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300., 400., 500.};
187 << DataContainer{100., 200., 300., 400., 500.};
188 }
188 }
189
189
190 void TestScalarSeries::testMergeWithVector()
190 void TestScalarSeries::testMergeWithVector()
191 {
191 {
192 testMergeDifferentTypes_t<VectorSeries, ScalarSeries>();
192 testMergeDifferentTypes_t<VectorSeries, ScalarSeries>();
193 }
193 }
194
194
195 void TestScalarSeries::testMinXAxisData_data()
195 void TestScalarSeries::testMinXAxisData_data()
196 {
196 {
197 testMinXAxisData_struct<ScalarSeries>();
197 testMinXAxisData_struct<ScalarSeries>();
198
198
199 QTest::newRow("minData1") << ScalarBuilder{}
199 QTest::newRow("minData1") << ScalarBuilder{}
200 .setX({1., 2., 3., 4., 5.})
200 .setX({1., 2., 3., 4., 5.})
201 .setValues({100., 200., 300., 400., 500.})
201 .setValues({100., 200., 300., 400., 500.})
202 .build()
202 .build()
203 << 0. << true << 1.;
203 << 0. << true << 1.;
204 QTest::newRow("minData2") << ScalarBuilder{}
204 QTest::newRow("minData2") << ScalarBuilder{}
205 .setX({1., 2., 3., 4., 5.})
205 .setX({1., 2., 3., 4., 5.})
206 .setValues({100., 200., 300., 400., 500.})
206 .setValues({100., 200., 300., 400., 500.})
207 .build()
207 .build()
208 << 1. << true << 1.;
208 << 1. << true << 1.;
209 QTest::newRow("minData3") << ScalarBuilder{}
209 QTest::newRow("minData3") << ScalarBuilder{}
210 .setX({1., 2., 3., 4., 5.})
210 .setX({1., 2., 3., 4., 5.})
211 .setValues({100., 200., 300., 400., 500.})
211 .setValues({100., 200., 300., 400., 500.})
212 .build()
212 .build()
213 << 1.1 << true << 2.;
213 << 1.1 << true << 2.;
214 QTest::newRow("minData4") << ScalarBuilder{}
214 QTest::newRow("minData4") << ScalarBuilder{}
215 .setX({1., 2., 3., 4., 5.})
215 .setX({1., 2., 3., 4., 5.})
216 .setValues({100., 200., 300., 400., 500.})
216 .setValues({100., 200., 300., 400., 500.})
217 .build()
217 .build()
218 << 5. << true << 5.;
218 << 5. << true << 5.;
219 QTest::newRow("minData5") << ScalarBuilder{}
219 QTest::newRow("minData5") << ScalarBuilder{}
220 .setX({1., 2., 3., 4., 5.})
220 .setX({1., 2., 3., 4., 5.})
221 .setValues({100., 200., 300., 400., 500.})
221 .setValues({100., 200., 300., 400., 500.})
222 .build()
222 .build()
223 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
223 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
224 QTest::newRow("minData6") << ScalarBuilder{}.setX({}).setValues({}).build() << 1.1 << false
224 QTest::newRow("minData6") << ScalarBuilder{}.setX({}).setValues({}).build() << 1.1 << false
225 << std::numeric_limits<double>::quiet_NaN();
225 << std::numeric_limits<double>::quiet_NaN();
226 }
226 }
227
227
228 void TestScalarSeries::testMinXAxisData()
228 void TestScalarSeries::testMinXAxisData()
229 {
229 {
230 testMinXAxisData_t<ScalarSeries>();
230 testMinXAxisData_t<ScalarSeries>();
231 }
231 }
232
232
233 void TestScalarSeries::testMaxXAxisData_data()
233 void TestScalarSeries::testMaxXAxisData_data()
234 {
234 {
235 testMaxXAxisData_struct<ScalarSeries>();
235 testMaxXAxisData_struct<ScalarSeries>();
236
236
237 QTest::newRow("maxData1") << ScalarBuilder{}
237 QTest::newRow("maxData1") << ScalarBuilder{}
238 .setX({1., 2., 3., 4., 5.})
238 .setX({1., 2., 3., 4., 5.})
239 .setValues({100., 200., 300., 400., 500.})
239 .setValues({100., 200., 300., 400., 500.})
240 .build()
240 .build()
241 << 6. << true << 5.;
241 << 6. << true << 5.;
242 QTest::newRow("maxData2") << ScalarBuilder{}
242 QTest::newRow("maxData2") << ScalarBuilder{}
243 .setX({1., 2., 3., 4., 5.})
243 .setX({1., 2., 3., 4., 5.})
244 .setValues({100., 200., 300., 400., 500.})
244 .setValues({100., 200., 300., 400., 500.})
245 .build()
245 .build()
246 << 5. << true << 5.;
246 << 5. << true << 5.;
247 QTest::newRow("maxData3") << ScalarBuilder{}
247 QTest::newRow("maxData3") << ScalarBuilder{}
248 .setX({1., 2., 3., 4., 5.})
248 .setX({1., 2., 3., 4., 5.})
249 .setValues({100., 200., 300., 400., 500.})
249 .setValues({100., 200., 300., 400., 500.})
250 .build()
250 .build()
251 << 4.9 << true << 4.;
251 << 4.9 << true << 4.;
252 QTest::newRow("maxData4") << ScalarBuilder{}
252 QTest::newRow("maxData4") << ScalarBuilder{}
253 .setX({1., 2., 3., 4., 5.})
253 .setX({1., 2., 3., 4., 5.})
254 .setValues({100., 200., 300., 400., 500.})
254 .setValues({100., 200., 300., 400., 500.})
255 .build()
255 .build()
256 << 1.1 << true << 1.;
256 << 1.1 << true << 1.;
257 QTest::newRow("maxData5") << ScalarBuilder{}
257 QTest::newRow("maxData5") << ScalarBuilder{}
258 .setX({1., 2., 3., 4., 5.})
258 .setX({1., 2., 3., 4., 5.})
259 .setValues({100., 200., 300., 400., 500.})
259 .setValues({100., 200., 300., 400., 500.})
260 .build()
260 .build()
261 << 1. << true << 1.;
261 << 1. << true << 1.;
262 QTest::newRow("maxData6") << ScalarBuilder{}.setX({}).setValues({}).build() << 1.1 << false
262 QTest::newRow("maxData6") << ScalarBuilder{}.setX({}).setValues({}).build() << 1.1 << false
263 << std::numeric_limits<double>::quiet_NaN();
263 << std::numeric_limits<double>::quiet_NaN();
264 }
264 }
265
265
266 void TestScalarSeries::testMaxXAxisData()
266 void TestScalarSeries::testMaxXAxisData()
267 {
267 {
268 testMaxXAxisData_t<ScalarSeries>();
268 testMaxXAxisData_t<ScalarSeries>();
269 }
269 }
270
270
271 void TestScalarSeries::testPurge_data()
271 void TestScalarSeries::testPurge_data()
272 {
272 {
273 testPurge_struct<ScalarSeries>();
273 testPurge_struct<ScalarSeries>();
274
274
275 QTest::newRow("purgeScalar") << ScalarBuilder{}
275 QTest::newRow("purgeScalar") << ScalarBuilder{}
276 .setX({1., 2., 3., 4., 5.})
276 .setX({1., 2., 3., 4., 5.})
277 .setValues({100., 200., 300., 400., 500.})
277 .setValues({100., 200., 300., 400., 500.})
278 .build()
278 .build()
279 << 2. << 4. << DataContainer{2., 3., 4.}
279 << 2. << 4. << DataContainer{2., 3., 4.}
280 << std::vector<DataContainer>{{200., 300., 400.}};
280 << std::vector<DataContainer>{{200., 300., 400.}};
281 QTest::newRow("purgeScalar1 (min/max swap)")
281 QTest::newRow("purgeScalar1 (min/max swap)") << ScalarBuilder{}
282 << ScalarBuilder{}
282 .setX({1., 2., 3., 4., 5.})
283 .setX({1., 2., 3., 4., 5.})
283 .setValues({100., 200., 300., 400., 500.})
284 .setValues({100., 200., 300., 400., 500.})
284 .build()
285 .build()
285 << 4. << 2. << DataContainer{2., 3., 4.}
286 << 4. << 2. << DataContainer{2., 3., 4.} << std::vector<DataContainer>{{200., 300., 400.}};
286 << std::vector<DataContainer>{{200., 300., 400.}};
287 QTest::newRow("purgeScalar2") << ScalarBuilder{}
287 QTest::newRow("purgeScalar2") << ScalarBuilder{}
288 .setX({1., 2., 3., 4., 5.})
288 .setX({1., 2., 3., 4., 5.})
289 .setValues({100., 200., 300., 400., 500.})
289 .setValues({100., 200., 300., 400., 500.})
290 .build()
290 .build()
291 << 0. << 2.5 << DataContainer{1., 2.}
291 << 0. << 2.5 << DataContainer{1., 2.}
292 << std::vector<DataContainer>{{100., 200.}};
292 << std::vector<DataContainer>{{100., 200.}};
293 QTest::newRow("purgeScalar3") << ScalarBuilder{}
293 QTest::newRow("purgeScalar3") << ScalarBuilder{}
294 .setX({1., 2., 3., 4., 5.})
294 .setX({1., 2., 3., 4., 5.})
295 .setValues({100., 200., 300., 400., 500.})
295 .setValues({100., 200., 300., 400., 500.})
296 .build()
296 .build()
297 << 3.5 << 7. << DataContainer{4., 5.}
297 << 3.5 << 7. << DataContainer{4., 5.}
298 << std::vector<DataContainer>{{400., 500.}};
298 << std::vector<DataContainer>{{400., 500.}};
299 QTest::newRow("purgeScalar4") << ScalarBuilder{}
299 QTest::newRow("purgeScalar4") << ScalarBuilder{}
300 .setX({1., 2., 3., 4., 5.})
300 .setX({1., 2., 3., 4., 5.})
301 .setValues({100., 200., 300., 400., 500.})
301 .setValues({100., 200., 300., 400., 500.})
302 .build()
302 .build()
303 << 0. << 7. << DataContainer{1., 2., 3., 4., 5.}
303 << 0. << 7. << DataContainer{1., 2., 3., 4., 5.}
304 << std::vector<DataContainer>{{100., 200., 300., 400., 500.}};
304 << std::vector<DataContainer>{{100., 200., 300., 400., 500.}};
305 QTest::newRow("purgeScalar5") << ScalarBuilder{}
305 QTest::newRow("purgeScalar5") << ScalarBuilder{}
306 .setX({1., 2., 3., 4., 5.})
306 .setX({1., 2., 3., 4., 5.})
307 .setValues({100., 200., 300., 400., 500.})
307 .setValues({100., 200., 300., 400., 500.})
308 .build()
308 .build()
309 << 5.5 << 7. << DataContainer{} << std::vector<DataContainer>{{}};
309 << 5.5 << 7. << DataContainer{} << std::vector<DataContainer>{{}};
310 }
310 }
311
311
312 void TestScalarSeries::testPurge()
312 void TestScalarSeries::testPurge()
313 {
313 {
314 testPurge_t<ScalarSeries>();
314 testPurge_t<ScalarSeries>();
315 }
315 }
316
316
317 void TestScalarSeries::testXAxisRange_data()
317 void TestScalarSeries::testXAxisRange_data()
318 {
318 {
319 testXAxisRange_struct<ScalarSeries>();
319 testXAxisRange_struct<ScalarSeries>();
320
320
321 QTest::newRow("xAxisRange") << ScalarBuilder{}
321 QTest::newRow("xAxisRange") << ScalarBuilder{}
322 .setX({1., 2., 3., 4., 5.})
322 .setX({1., 2., 3., 4., 5.})
323 .setValues({100., 200., 300., 400., 500.})
323 .setValues({100., 200., 300., 400., 500.})
324 .build()
324 .build()
325 << -1. << 3.2 << DataContainer{1., 2., 3.}
325 << -1. << 3.2 << DataContainer{1., 2., 3.}
326 << DataContainer{100., 200., 300.};
326 << DataContainer{100., 200., 300.};
327 QTest::newRow("xAxisRange1 (min/max swap)")
327 QTest::newRow("xAxisRange1 (min/max swap)") << ScalarBuilder{}
328 << ScalarBuilder{}
328 .setX({1., 2., 3., 4., 5.})
329 .setX({1., 2., 3., 4., 5.})
329 .setValues({100., 200., 300., 400., 500.})
330 .setValues({100., 200., 300., 400., 500.})
330 .build()
331 .build()
331 << 3.2 << -1. << DataContainer{1., 2., 3.}
332 << 3.2 << -1. << DataContainer{1., 2., 3.} << DataContainer{100., 200., 300.};
332 << DataContainer{100., 200., 300.};
333 QTest::newRow("xAxisRange2") << ScalarBuilder{}
333 QTest::newRow("xAxisRange2") << ScalarBuilder{}
334 .setX({1., 2., 3., 4., 5.})
334 .setX({1., 2., 3., 4., 5.})
335 .setValues({100., 200., 300., 400., 500.})
335 .setValues({100., 200., 300., 400., 500.})
336 .build()
336 .build()
337 << 1. << 4. << DataContainer{1., 2., 3., 4.}
337 << 1. << 4. << DataContainer{1., 2., 3., 4.}
338 << DataContainer{100., 200., 300., 400.};
338 << DataContainer{100., 200., 300., 400.};
339 QTest::newRow("xAxisRange3") << ScalarBuilder{}
339 QTest::newRow("xAxisRange3") << ScalarBuilder{}
340 .setX({1., 2., 3., 4., 5.})
340 .setX({1., 2., 3., 4., 5.})
341 .setValues({100., 200., 300., 400., 500.})
341 .setValues({100., 200., 300., 400., 500.})
342 .build()
342 .build()
343 << 1. << 3.9 << DataContainer{1., 2., 3.}
343 << 1. << 3.9 << DataContainer{1., 2., 3.}
344 << DataContainer{100., 200., 300.};
344 << DataContainer{100., 200., 300.};
345 QTest::newRow("xAxisRange4") << ScalarBuilder{}
345 QTest::newRow("xAxisRange4") << ScalarBuilder{}
346 .setX({1., 2., 3., 4., 5.})
346 .setX({1., 2., 3., 4., 5.})
347 .setValues({100., 200., 300., 400., 500.})
347 .setValues({100., 200., 300., 400., 500.})
348 .build()
348 .build()
349 << 0. << 0.9 << DataContainer{} << DataContainer{};
349 << 0. << 0.9 << DataContainer{} << DataContainer{};
350 QTest::newRow("xAxisRange5") << ScalarBuilder{}
350 QTest::newRow("xAxisRange5") << ScalarBuilder{}
351 .setX({1., 2., 3., 4., 5.})
351 .setX({1., 2., 3., 4., 5.})
352 .setValues({100., 200., 300., 400., 500.})
352 .setValues({100., 200., 300., 400., 500.})
353 .build()
353 .build()
354 << 0. << 1. << DataContainer{1.} << DataContainer{100.};
354 << 0. << 1. << DataContainer{1.} << DataContainer{100.};
355 QTest::newRow("xAxisRange6") << ScalarBuilder{}
355 QTest::newRow("xAxisRange6") << ScalarBuilder{}
356 .setX({1., 2., 3., 4., 5.})
356 .setX({1., 2., 3., 4., 5.})
357 .setValues({100., 200., 300., 400., 500.})
357 .setValues({100., 200., 300., 400., 500.})
358 .build()
358 .build()
359 << 2.1 << 6. << DataContainer{3., 4., 5.}
359 << 2.1 << 6. << DataContainer{3., 4., 5.}
360 << DataContainer{300., 400., 500.};
360 << DataContainer{300., 400., 500.};
361 QTest::newRow("xAxisRange7") << ScalarBuilder{}
361 QTest::newRow("xAxisRange7") << ScalarBuilder{}
362 .setX({1., 2., 3., 4., 5.})
362 .setX({1., 2., 3., 4., 5.})
363 .setValues({100., 200., 300., 400., 500.})
363 .setValues({100., 200., 300., 400., 500.})
364 .build()
364 .build()
365 << 6. << 9. << DataContainer{} << DataContainer{};
365 << 6. << 9. << DataContainer{} << DataContainer{};
366 QTest::newRow("xAxisRange8") << ScalarBuilder{}
366 QTest::newRow("xAxisRange8") << ScalarBuilder{}
367 .setX({1., 2., 3., 4., 5.})
367 .setX({1., 2., 3., 4., 5.})
368 .setValues({100., 200., 300., 400., 500.})
368 .setValues({100., 200., 300., 400., 500.})
369 .build()
369 .build()
370 << 5. << 9. << DataContainer{5.} << DataContainer{500.};
370 << 5. << 9. << DataContainer{5.} << DataContainer{500.};
371 }
371 }
372
372
373 void TestScalarSeries::testXAxisRange()
373 void TestScalarSeries::testXAxisRange()
374 {
374 {
375 testXAxisRange_t<ScalarSeries>();
375 testXAxisRange_t<ScalarSeries>();
376 }
376 }
377
377
378 void TestScalarSeries::testValuesBounds_data()
378 void TestScalarSeries::testValuesBounds_data()
379 {
379 {
380 testValuesBounds_struct<ScalarSeries>();
380 testValuesBounds_struct<ScalarSeries>();
381
381
382 auto nan = std::numeric_limits<double>::quiet_NaN();
382 auto nan = std::numeric_limits<double>::quiet_NaN();
383
383
384 QTest::newRow("scalarBounds1") << ScalarBuilder{}
384 QTest::newRow("scalarBounds1") << ScalarBuilder{}
385 .setX({1., 2., 3., 4., 5.})
385 .setX({1., 2., 3., 4., 5.})
386 .setValues({100., 200., 300., 400., 500.})
386 .setValues({100., 200., 300., 400., 500.})
387 .build()
387 .build()
388 << 0. << 6. << true << 100. << 500.;
388 << 0. << 6. << true << 100. << 500.;
389 QTest::newRow("scalarBounds2") << ScalarBuilder{}
389 QTest::newRow("scalarBounds2") << ScalarBuilder{}
390 .setX({1., 2., 3., 4., 5.})
390 .setX({1., 2., 3., 4., 5.})
391 .setValues({100., 200., 300., 400., 500.})
391 .setValues({100., 200., 300., 400., 500.})
392 .build()
392 .build()
393 << 2. << 4. << true << 200. << 400.;
393 << 2. << 4. << true << 200. << 400.;
394 QTest::newRow("scalarBounds3") << ScalarBuilder{}
394 QTest::newRow("scalarBounds3") << ScalarBuilder{}
395 .setX({1., 2., 3., 4., 5.})
395 .setX({1., 2., 3., 4., 5.})
396 .setValues({100., 200., 300., 400., 500.})
396 .setValues({100., 200., 300., 400., 500.})
397 .build()
397 .build()
398 << 0. << 0.5 << false << nan << nan;
398 << 0. << 0.5 << false << nan << nan;
399 QTest::newRow("scalarBounds4") << ScalarBuilder{}
399 QTest::newRow("scalarBounds4") << ScalarBuilder{}
400 .setX({1., 2., 3., 4., 5.})
400 .setX({1., 2., 3., 4., 5.})
401 .setValues({100., 200., 300., 400., 500.})
401 .setValues({100., 200., 300., 400., 500.})
402 .build()
402 .build()
403 << 5.1 << 6. << false << nan << nan;
403 << 5.1 << 6. << false << nan << nan;
404 QTest::newRow("scalarBounds5")
404 QTest::newRow("scalarBounds5") << ScalarBuilder{}.setX({1.}).setValues({100.}).build() << 0.
405 << ScalarBuilder{}.setX({1.}).setValues({100.}).build() << 0. << 2. << true << 100. << 100.;
405 << 2. << true << 100. << 100.;
406 QTest::newRow("scalarBounds6")
406 QTest::newRow("scalarBounds6") << ScalarBuilder{}.setX({}).setValues({}).build() << 0. << 2.
407 << ScalarBuilder{}.setX({}).setValues({}).build() << 0. << 2. << false << nan << nan;
407 << false << nan << nan;
408
408
409 // Tests with NaN values: NaN values are not included in min/max search
409 // Tests with NaN values: NaN values are not included in min/max search
410 QTest::newRow("scalarBounds7") << ScalarBuilder{}
410 QTest::newRow("scalarBounds7") << ScalarBuilder{}
411 .setX({1., 2., 3., 4., 5.})
411 .setX({1., 2., 3., 4., 5.})
412 .setValues({nan, 200., 300., 400., nan})
412 .setValues({nan, 200., 300., 400., nan})
413 .build()
413 .build()
414 << 0. << 6. << true << 200. << 400.;
414 << 0. << 6. << true << 200. << 400.;
415 QTest::newRow("scalarBounds8")
415 QTest::newRow("scalarBounds8")
416 << ScalarBuilder{}.setX({1., 2., 3., 4., 5.}).setValues({nan, nan, nan, nan, nan}).build()
416 << ScalarBuilder{}.setX({1., 2., 3., 4., 5.}).setValues({nan, nan, nan, nan, nan}).build()
417 << 0. << 6. << true << nan << nan;
417 << 0. << 6. << true << nan << nan;
418 }
418 }
419
419
420 void TestScalarSeries::testValuesBounds()
420 void TestScalarSeries::testValuesBounds()
421 {
421 {
422 testValuesBounds_t<ScalarSeries>();
422 testValuesBounds_t<ScalarSeries>();
423 }
423 }
424
424
425 QTEST_MAIN(TestScalarSeries)
425 QTEST_MAIN(TestScalarSeries)
426 #include "TestScalarSeries.moc"
426 #include "TestScalarSeries.moc"
@@ -1,71 +1,75
1 #ifndef SCIQLOP_DRAGDROPHELPER_H
1 #ifndef SCIQLOP_DRAGDROPHELPER_H
2 #define SCIQLOP_DRAGDROPHELPER_H
2 #define SCIQLOP_DRAGDROPHELPER_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QLoggingCategory>
5 #include <QLoggingCategory>
6 #include <QWidget>
6 #include <QWidget>
7
7
8 class QVBoxLayout;
8 class QVBoxLayout;
9 class QScrollArea;
9 class QScrollArea;
10 class QTabBar;
10 class QTabBar;
11 class VisualizationDragWidget;
11 class VisualizationDragWidget;
12 class VisualizationDragDropContainer;
12 class VisualizationDragDropContainer;
13 class QMimeData;
13 class QMimeData;
14
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropHelper)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropHelper)
16
16
17 /**
17 /**
18 * @brief Helper class for drag&drop operations.
18 * @brief Helper class for drag&drop operations.
19 * @note The helper is accessible from the sqpApp singleton and has the same life as the whole
19 * @note The helper is accessible from the sqpApp singleton and has the same life as the whole
20 * application (like a controller). But contrary to a controller, it doesn't live in a thread and
20 * application (like a controller). But contrary to a controller, it doesn't live in a thread and
21 * can interect with the gui.
21 * can interect with the gui.
22 * @see SqpApplication
22 * @see SqpApplication
23 */
23 */
24 class DragDropHelper {
24 class DragDropHelper {
25 public:
25 public:
26 static const QString MIME_TYPE_GRAPH;
26 static const QString MIME_TYPE_GRAPH;
27 static const QString MIME_TYPE_ZONE;
27 static const QString MIME_TYPE_ZONE;
28
28
29 enum class PlaceHolderType { Default, Graph, Zone };
29 enum class PlaceHolderType { Default, Graph, Zone };
30
30
31 DragDropHelper();
31 DragDropHelper();
32 virtual ~DragDropHelper();
32 virtual ~DragDropHelper();
33
33
34 /// Resets some internal variables. Must be called before any new drag&drop operation.
34 /// Resets some internal variables. Must be called before any new drag&drop operation.
35 void resetDragAndDrop();
35 void resetDragAndDrop();
36
36
37 /// Sets the visualization widget currently being drag on the visualization.
37 /// Sets the visualization widget currently being drag on the visualization.
38 void setCurrentDragWidget(VisualizationDragWidget *dragWidget);
38 void setCurrentDragWidget(VisualizationDragWidget *dragWidget);
39
39
40 /// Returns the visualization widget currently being drag on the visualization.
40 /// Returns the visualization widget currently being drag on the visualization.
41 /// Can be null if a new visualization widget is intended to be created by the drag&drop
41 /// Can be null if a new visualization widget is intended to be created by the drag&drop
42 /// operation.
42 /// operation.
43 VisualizationDragWidget *getCurrentDragWidget() const;
43 VisualizationDragWidget *getCurrentDragWidget() const;
44
44
45 QWidget &placeHolder() const;
45 QWidget &placeHolder() const;
46 void insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
46 void insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
47 const QString &topLabelText);
47 const QString &topLabelText);
48 void removePlaceHolder();
48 void removePlaceHolder();
49 bool isPlaceHolderSet() const;
49 bool isPlaceHolderSet() const;
50
50
51 /// Checks if the specified mime data is valid for a drop in the visualization
51 /// Checks if the specified mime data is valid for a drop in the visualization
52 bool checkMimeDataForVisualization(const QMimeData *mimeData,
52 bool checkMimeDataForVisualization(const QMimeData *mimeData,
53 VisualizationDragDropContainer *dropContainer);
53 VisualizationDragDropContainer *dropContainer);
54
54
55 void addDragDropScrollArea(QScrollArea *scrollArea);
55 void addDragDropScrollArea(QScrollArea *scrollArea);
56 void removeDragDropScrollArea(QScrollArea *scrollArea);
56 void removeDragDropScrollArea(QScrollArea *scrollArea);
57
57
58 void addDragDropTabBar(QTabBar *tabBar);
58 void addDragDropTabBar(QTabBar *tabBar);
59 void removeDragDropTabBar(QTabBar *tabBar);
59 void removeDragDropTabBar(QTabBar *tabBar);
60
60
61 QUrl imageTemporaryUrl(const QImage &image) const;
61 QUrl imageTemporaryUrl(const QImage &image) const;
62
62
63 void setHightlightedDragWidget(VisualizationDragWidget *dragWidget);
63 void setHightlightedDragWidget(VisualizationDragWidget *dragWidget);
64 VisualizationDragWidget *getHightlightedDragWidget() const;
64 VisualizationDragWidget *getHightlightedDragWidget() const;
65
65
66 /// Delays the closing of a widget during a drag&drop operation
67 void delayedCloseWidget(QWidget *widget);
68 void doCloseWidgets();
69
66 private:
70 private:
67 class DragDropHelperPrivate;
71 class DragDropHelperPrivate;
68 spimpl::unique_impl_ptr<DragDropHelperPrivate> impl;
72 spimpl::unique_impl_ptr<DragDropHelperPrivate> impl;
69 };
73 };
70
74
71 #endif // SCIQLOP_DRAGDROPHELPER_H
75 #endif // SCIQLOP_DRAGDROPHELPER_H
@@ -1,45 +1,47
1 #include "DataSource/DataSourceTreeWidget.h"
1 #include "DataSource/DataSourceTreeWidget.h"
2 #include "Common/MimeTypesDef.h"
2 #include "Common/MimeTypesDef.h"
3 #include "DataSource/DataSourceController.h"
3 #include "DataSource/DataSourceController.h"
4 #include "DataSource/DataSourceItem.h"
4 #include "DataSource/DataSourceItem.h"
5 #include "DataSource/DataSourceTreeWidgetItem.h"
5 #include "DataSource/DataSourceTreeWidgetItem.h"
6
6
7 #include "DragAndDrop/DragDropHelper.h"
7 #include "DragAndDrop/DragDropHelper.h"
8 #include "SqpApplication.h"
8 #include "SqpApplication.h"
9
9
10 #include <QMimeData>
10 #include <QMimeData>
11
11
12 DataSourceTreeWidget::DataSourceTreeWidget(QWidget *parent) : QTreeWidget(parent) {}
12 DataSourceTreeWidget::DataSourceTreeWidget(QWidget *parent) : QTreeWidget(parent)
13 {
14 }
13
15
14 QMimeData *DataSourceTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) const
16 QMimeData *DataSourceTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) const
15 {
17 {
16 auto mimeData = new QMimeData;
18 auto mimeData = new QMimeData;
17
19
18 // Basic check to ensure the item are correctly typed
20 // Basic check to ensure the item are correctly typed
19 Q_ASSERT(items.isEmpty() || dynamic_cast<DataSourceTreeWidgetItem *>(items.first()) != nullptr);
21 Q_ASSERT(items.isEmpty() || dynamic_cast<DataSourceTreeWidgetItem *>(items.first()) != nullptr);
20
22
21 QVariantList productData;
23 QVariantList productData;
22
24
23 for (auto item : items) {
25 for (auto item : items) {
24 auto dataSourceTreeItem = static_cast<DataSourceTreeWidgetItem *>(item);
26 auto dataSourceTreeItem = static_cast<DataSourceTreeWidgetItem *>(item);
25 auto dataSource = dataSourceTreeItem->data();
27 auto dataSource = dataSourceTreeItem->data();
26
28
27 if (dataSource->type() == DataSourceItemType::COMPONENT
29 if (dataSource->type() == DataSourceItemType::COMPONENT
28 || dataSource->type() == DataSourceItemType::PRODUCT) {
30 || dataSource->type() == DataSourceItemType::PRODUCT) {
29 auto metaData = dataSource->data();
31 auto metaData = dataSource->data();
30 productData << metaData;
32 productData << metaData;
31 }
33 }
32 }
34 }
33
35
34 auto encodedData = sqpApp->dataSourceController().mimeDataForProductsData(productData);
36 auto encodedData = sqpApp->dataSourceController().mimeDataForProductsData(productData);
35 mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData);
37 mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData);
36
38
37 return mimeData;
39 return mimeData;
38 }
40 }
39
41
40 void DataSourceTreeWidget::startDrag(Qt::DropActions supportedActions)
42 void DataSourceTreeWidget::startDrag(Qt::DropActions supportedActions)
41 {
43 {
42 // Resets the drag&drop operations before it's starting
44 // Resets the drag&drop operations before it's starting
43 sqpApp->dragDropHelper().resetDragAndDrop();
45 sqpApp->dragDropHelper().resetDragAndDrop();
44 QTreeWidget::startDrag(supportedActions);
46 QTreeWidget::startDrag(supportedActions);
45 }
47 }
@@ -1,275 +1,294
1 #include "DragAndDrop/DragDropHelper.h"
1 #include "DragAndDrop/DragDropHelper.h"
2 #include "DragAndDrop/DragDropScroller.h"
2 #include "DragAndDrop/DragDropScroller.h"
3 #include "DragAndDrop/DragDropTabSwitcher.h"
3 #include "DragAndDrop/DragDropTabSwitcher.h"
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5 #include "Visualization/VisualizationDragDropContainer.h"
5 #include "Visualization/VisualizationDragDropContainer.h"
6 #include "Visualization/VisualizationDragWidget.h"
6 #include "Visualization/VisualizationDragWidget.h"
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 "Variable/Variable.h"
10 #include "Variable/Variable.h"
11 #include "Variable/VariableController.h"
11 #include "Variable/VariableController.h"
12
12
13 #include "Common/MimeTypesDef.h"
13 #include "Common/MimeTypesDef.h"
14 #include "Common/VisualizationDef.h"
14 #include "Common/VisualizationDef.h"
15
15
16 #include <QDir>
16 #include <QDir>
17 #include <QLabel>
17 #include <QLabel>
18 #include <QUrl>
18 #include <QUrl>
19 #include <QVBoxLayout>
19 #include <QVBoxLayout>
20
20
21
21
22 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDropHelper")
22 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDropHelper")
23
23
24
24
25 struct DragDropHelper::DragDropHelperPrivate {
25 struct DragDropHelper::DragDropHelperPrivate {
26
26
27 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
27 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
28 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
28 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
29 QLabel *m_PlaceHolderLabel;
29 QLabel *m_PlaceHolderLabel;
30 QWidget *m_PlaceBackground;
30 QWidget *m_PlaceBackground;
31 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
31 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
32 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
32 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
33 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
33 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
34 // QTemporaryFile to have a name which is not generated.
34 // QTemporaryFile to have a name which is not generated.
35
35
36 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
36 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
37
37
38 QMetaObject::Connection m_DragWidgetDestroyedConnection;
38 QMetaObject::Connection m_DragWidgetDestroyedConnection;
39 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
39 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
40
40
41 QList<QWidget *> m_WidgetToClose;
42
41 explicit DragDropHelperPrivate()
43 explicit DragDropHelperPrivate()
42 : m_PlaceHolder{std::make_unique<QWidget>()},
44 : m_PlaceHolder{std::make_unique<QWidget>()},
43 m_DragDropScroller{std::make_unique<DragDropScroller>()},
45 m_DragDropScroller{std::make_unique<DragDropScroller>()},
44 m_DragDropTabSwitcher{std::make_unique<DragDropTabSwitcher>()}
46 m_DragDropTabSwitcher{std::make_unique<DragDropTabSwitcher>()}
45 {
47 {
46
48
47 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
49 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
48 layout->setSpacing(0);
50 layout->setSpacing(0);
49 layout->setContentsMargins(0, 0, 0, 0);
51 layout->setContentsMargins(0, 0, 0, 0);
50
52
51 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
53 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
52 m_PlaceHolderLabel->setMinimumHeight(25);
54 m_PlaceHolderLabel->setMinimumHeight(25);
53 layout->addWidget(m_PlaceHolderLabel);
55 layout->addWidget(m_PlaceHolderLabel);
54
56
55 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
57 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
56 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
58 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
57 layout->addWidget(m_PlaceBackground);
59 layout->addWidget(m_PlaceBackground);
58
60
59 sqpApp->installEventFilter(m_DragDropScroller.get());
61 sqpApp->installEventFilter(m_DragDropScroller.get());
60 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
62 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
61
63
62 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
64 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
63 }
65 }
64
66
65 void preparePlaceHolder(DragDropHelper::PlaceHolderType type, const QString &topLabelText) const
67 void preparePlaceHolder(DragDropHelper::PlaceHolderType type, const QString &topLabelText) const
66 {
68 {
67 if (m_CurrentDragWidget) {
69 if (m_CurrentDragWidget) {
68 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
70 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
69 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
71 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
70 }
72 }
71 else {
73 else {
72 // Configuration of the placeHolder when there is no dragWidget
74 // Configuration of the placeHolder when there is no dragWidget
73 // (for instance with a drag from a variable)
75 // (for instance with a drag from a variable)
74
76
75 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
77 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
76 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
78 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
77 }
79 }
78
80
79 switch (type) {
81 switch (type) {
80 case DragDropHelper::PlaceHolderType::Graph:
82 case DragDropHelper::PlaceHolderType::Graph:
81 m_PlaceBackground->setStyleSheet(
83 m_PlaceBackground->setStyleSheet(
82 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
84 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
83 break;
85 break;
84 case DragDropHelper::PlaceHolderType::Zone:
86 case DragDropHelper::PlaceHolderType::Zone:
85 case DragDropHelper::PlaceHolderType::Default:
87 case DragDropHelper::PlaceHolderType::Default:
86 m_PlaceBackground->setStyleSheet(
88 m_PlaceBackground->setStyleSheet(
87 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
89 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
88 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
90 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
89 break;
91 break;
90 }
92 }
91
93
92 m_PlaceHolderLabel->setText(topLabelText);
94 m_PlaceHolderLabel->setText(topLabelText);
93 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
95 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
94 }
96 }
95 };
97 };
96
98
97
99
98 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()} {}
100 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
101 {
102 }
99
103
100 DragDropHelper::~DragDropHelper()
104 DragDropHelper::~DragDropHelper()
101 {
105 {
102 QFile::remove(impl->m_ImageTempUrl);
106 QFile::remove(impl->m_ImageTempUrl);
103 }
107 }
104
108
105 void DragDropHelper::resetDragAndDrop()
109 void DragDropHelper::resetDragAndDrop()
106 {
110 {
107 setCurrentDragWidget(nullptr);
111 setCurrentDragWidget(nullptr);
108 impl->m_HighlightedDragWidget = nullptr;
112 impl->m_HighlightedDragWidget = nullptr;
109 }
113 }
110
114
111 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
115 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
112 {
116 {
113 if (impl->m_CurrentDragWidget) {
117 if (impl->m_CurrentDragWidget) {
114
118
115 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
119 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
116 }
120 }
117
121
118 if (dragWidget) {
122 if (dragWidget) {
119 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
123 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
120 impl->m_DragWidgetDestroyedConnection
124 impl->m_DragWidgetDestroyedConnection
121 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
125 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
122 [this]() { impl->m_CurrentDragWidget = nullptr; });
126 [this]() { impl->m_CurrentDragWidget = nullptr; });
123 }
127 }
124
128
125 impl->m_CurrentDragWidget = dragWidget;
129 impl->m_CurrentDragWidget = dragWidget;
126 }
130 }
127
131
128 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
132 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
129 {
133 {
130 return impl->m_CurrentDragWidget;
134 return impl->m_CurrentDragWidget;
131 }
135 }
132
136
133 QWidget &DragDropHelper::placeHolder() const
137 QWidget &DragDropHelper::placeHolder() const
134 {
138 {
135 return *impl->m_PlaceHolder;
139 return *impl->m_PlaceHolder;
136 }
140 }
137
141
138 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
142 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
139 const QString &topLabelText)
143 const QString &topLabelText)
140 {
144 {
141 removePlaceHolder();
145 removePlaceHolder();
142 impl->preparePlaceHolder(type, topLabelText);
146 impl->preparePlaceHolder(type, topLabelText);
143 layout->insertWidget(index, impl->m_PlaceHolder.get());
147 layout->insertWidget(index, impl->m_PlaceHolder.get());
144 impl->m_PlaceHolder->show();
148 impl->m_PlaceHolder->show();
145 }
149 }
146
150
147 void DragDropHelper::removePlaceHolder()
151 void DragDropHelper::removePlaceHolder()
148 {
152 {
149 auto parentWidget = impl->m_PlaceHolder->parentWidget();
153 auto parentWidget = impl->m_PlaceHolder->parentWidget();
150 if (parentWidget) {
154 if (parentWidget) {
151 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
155 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
152 impl->m_PlaceHolder->setParent(nullptr);
156 impl->m_PlaceHolder->setParent(nullptr);
153 impl->m_PlaceHolder->hide();
157 impl->m_PlaceHolder->hide();
154 }
158 }
155 }
159 }
156
160
157 bool DragDropHelper::isPlaceHolderSet() const
161 bool DragDropHelper::isPlaceHolderSet() const
158 {
162 {
159 return impl->m_PlaceHolder->parentWidget();
163 return impl->m_PlaceHolder->parentWidget();
160 }
164 }
161
165
162 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
166 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
163 {
167 {
164 impl->m_DragDropScroller->addScrollArea(scrollArea);
168 impl->m_DragDropScroller->addScrollArea(scrollArea);
165 }
169 }
166
170
167 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
171 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
168 {
172 {
169 impl->m_DragDropScroller->removeScrollArea(scrollArea);
173 impl->m_DragDropScroller->removeScrollArea(scrollArea);
170 }
174 }
171
175
172 void DragDropHelper::addDragDropTabBar(QTabBar *tabBar)
176 void DragDropHelper::addDragDropTabBar(QTabBar *tabBar)
173 {
177 {
174 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
178 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
175 }
179 }
176
180
177 void DragDropHelper::removeDragDropTabBar(QTabBar *tabBar)
181 void DragDropHelper::removeDragDropTabBar(QTabBar *tabBar)
178 {
182 {
179 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
183 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
180 }
184 }
181
185
182 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
186 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
183 {
187 {
184 image.save(impl->m_ImageTempUrl);
188 image.save(impl->m_ImageTempUrl);
185 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
189 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
186 }
190 }
187
191
188 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
192 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
189 {
193 {
190 if (impl->m_HighlightedDragWidget) {
194 if (impl->m_HighlightedDragWidget) {
191 impl->m_HighlightedDragWidget->highlightForMerge(false);
195 impl->m_HighlightedDragWidget->highlightForMerge(false);
192 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
196 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
193 }
197 }
194
198
195 if (dragWidget) {
199 if (dragWidget) {
196 dragWidget->highlightForMerge(true);
200 dragWidget->highlightForMerge(true);
197
201
198 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
202 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
199 impl->m_DragWidgetDestroyedConnection
203 impl->m_DragWidgetDestroyedConnection
200 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
204 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
201 [this]() { impl->m_HighlightedDragWidget = nullptr; });
205 [this]() { impl->m_HighlightedDragWidget = nullptr; });
202 }
206 }
203
207
204 impl->m_HighlightedDragWidget = dragWidget;
208 impl->m_HighlightedDragWidget = dragWidget;
205 }
209 }
206
210
207 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
211 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
208 {
212 {
209 return impl->m_HighlightedDragWidget;
213 return impl->m_HighlightedDragWidget;
210 }
214 }
211
215
216 void DragDropHelper::delayedCloseWidget(QWidget *widget)
217 {
218 widget->hide();
219 impl->m_WidgetToClose << widget;
220 }
221
222 void DragDropHelper::doCloseWidgets()
223 {
224 for (auto widget : impl->m_WidgetToClose) {
225 widget->close();
226 }
227
228 impl->m_WidgetToClose.clear();
229 }
230
212 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
231 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
213 VisualizationDragDropContainer *dropContainer)
232 VisualizationDragDropContainer *dropContainer)
214 {
233 {
215 if (!mimeData || !dropContainer) {
234 if (!mimeData || !dropContainer) {
216 qCWarning(LOG_DragDropHelper()) << QObject::tr(
235 qCWarning(LOG_DragDropHelper()) << QObject::tr(
217 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
236 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
218 Q_ASSERT(false);
237 Q_ASSERT(false);
219 return false;
238 return false;
220 }
239 }
221
240
222 auto result = false;
241 auto result = false;
223
242
224 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
243 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
225 auto variables = sqpApp->variableController().variablesForMimeData(
244 auto variables = sqpApp->variableController().variablesForMimeData(
226 mimeData->data(MIME_TYPE_VARIABLE_LIST));
245 mimeData->data(MIME_TYPE_VARIABLE_LIST));
227
246
228 if (variables.count() == 1) {
247 if (variables.count() == 1) {
229
248
230 auto variable = variables.first();
249 auto variable = variables.first();
231 if (variable->dataSeries() != nullptr) {
250 if (variable->dataSeries() != nullptr) {
232
251
233 // Check that the variable is not already in a graph
252 // Check that the variable is not already in a graph
234
253
235 auto parent = dropContainer->parentWidget();
254 auto parent = dropContainer->parentWidget();
236 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
255 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
237 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
256 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
238 }
257 }
239
258
240 if (parent) {
259 if (parent) {
241 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
260 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
242
261
243 FindVariableOperation findVariableOperation{variable};
262 FindVariableOperation findVariableOperation{variable};
244 visualizationWidget->accept(&findVariableOperation);
263 visualizationWidget->accept(&findVariableOperation);
245 auto variableContainers = findVariableOperation.result();
264 auto variableContainers = findVariableOperation.result();
246 if (variableContainers.empty()) {
265 if (variableContainers.empty()) {
247 result = true;
266 result = true;
248 }
267 }
249 else {
268 else {
250 // result = false: the variable already exist in the visualisation
269 // result = false: the variable already exist in the visualisation
251 }
270 }
252 }
271 }
253 else {
272 else {
254 qCWarning(LOG_DragDropHelper()) << QObject::tr(
273 qCWarning(LOG_DragDropHelper()) << QObject::tr(
255 "DragDropHelper::checkMimeDataForVisualization, the parent "
274 "DragDropHelper::checkMimeDataForVisualization, the parent "
256 "VisualizationWidget cannot be found. Cannot check if the variable is "
275 "VisualizationWidget cannot be found. Cannot check if the variable is "
257 "already used or not.");
276 "already used or not.");
258 }
277 }
259 }
278 }
260 else {
279 else {
261 // result = false: the variable is not fully loaded
280 // result = false: the variable is not fully loaded
262 }
281 }
263 }
282 }
264 else {
283 else {
265 // result = false: cannot drop multiple variables in the visualisation
284 // result = false: cannot drop multiple variables in the visualisation
266 }
285 }
267 }
286 }
268 else {
287 else {
269 // Other MIME data
288 // Other MIME data
270 // no special rules, accepted by default
289 // no special rules, accepted by default
271 result = true;
290 result = true;
272 }
291 }
273
292
274 return result;
293 return result;
275 }
294 }
@@ -1,13 +1,15
1 #include "Variable/VariableInspectorTableView.h"
1 #include "Variable/VariableInspectorTableView.h"
2
2
3 #include "DragAndDrop/DragDropHelper.h"
3 #include "DragAndDrop/DragDropHelper.h"
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5
5
6 VariableInspectorTableView::VariableInspectorTableView(QWidget *parent) : QTableView(parent) {}
6 VariableInspectorTableView::VariableInspectorTableView(QWidget *parent) : QTableView(parent)
7 {
8 }
7
9
8 void VariableInspectorTableView::startDrag(Qt::DropActions supportedActions)
10 void VariableInspectorTableView::startDrag(Qt::DropActions supportedActions)
9 {
11 {
10 // Resets the drag&drop operations before it's starting
12 // Resets the drag&drop operations before it's starting
11 sqpApp->dragDropHelper().resetDragAndDrop();
13 sqpApp->dragDropHelper().resetDragAndDrop();
12 QTableView::startDrag(supportedActions);
14 QTableView::startDrag(supportedActions);
13 }
15 }
@@ -1,452 +1,453
1 #include "Visualization/VisualizationDragDropContainer.h"
1 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "DragAndDrop/DragDropHelper.h"
2 #include "DragAndDrop/DragDropHelper.h"
3 #include "SqpApplication.h"
3 #include "SqpApplication.h"
4 #include "Visualization/VisualizationDragWidget.h"
4 #include "Visualization/VisualizationDragWidget.h"
5
5
6 #include "Common/VisualizationDef.h"
6 #include "Common/VisualizationDef.h"
7
7
8 #include <QDrag>
8 #include <QDrag>
9 #include <QDragEnterEvent>
9 #include <QDragEnterEvent>
10 #include <QVBoxLayout>
10 #include <QVBoxLayout>
11
11
12 #include <cmath>
12 #include <cmath>
13 #include <memory>
13 #include <memory>
14
14
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
16
16
17 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
17 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
18
18
19 QVBoxLayout *m_Layout;
19 QVBoxLayout *m_Layout;
20 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
20 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
21 QString m_PlaceHolderText;
21 QString m_PlaceHolderText;
22 DragDropHelper::PlaceHolderType m_PlaceHolderType = DragDropHelper::PlaceHolderType::Graph;
22 DragDropHelper::PlaceHolderType m_PlaceHolderType = DragDropHelper::PlaceHolderType::Graph;
23
23
24 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
24 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
25 = [](auto mimeData) { return true; };
25 = [](auto mimeData) { return true; };
26
26
27 int m_MinContainerHeight = 0;
27 int m_MinContainerHeight = 0;
28
28
29 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
29 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
30 {
30 {
31 m_Layout = new QVBoxLayout(widget);
31 m_Layout = new QVBoxLayout(widget);
32 m_Layout->setContentsMargins(0, 0, 0, 0);
32 m_Layout->setContentsMargins(0, 0, 0, 0);
33 }
33 }
34
34
35 bool acceptMimeData(const QMimeData *data) const
35 bool acceptMimeData(const QMimeData *data) const
36 {
36 {
37 for (const auto &type : m_AcceptedMimeTypes.keys()) {
37 for (const auto &type : m_AcceptedMimeTypes.keys()) {
38 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
38 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
39 return true;
39 return true;
40 }
40 }
41 }
41 }
42
42
43 return false;
43 return false;
44 }
44 }
45
45
46 bool allowMergeForMimeData(const QMimeData *data) const
46 bool allowMergeForMimeData(const QMimeData *data) const
47 {
47 {
48 bool result = false;
48 bool result = false;
49 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
49 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
50 ++it) {
50 ++it) {
51
51
52 if (data->hasFormat(it.key())
52 if (data->hasFormat(it.key())
53 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
53 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
54 || it.value()
54 || it.value()
55 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
55 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
56 result = true;
56 result = true;
57 }
57 }
58 else if (data->hasFormat(it.key())
58 else if (data->hasFormat(it.key())
59 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
59 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
60 // Merge is forbidden if the mime data contain an acceptable type which cannot be
60 // Merge is forbidden if the mime data contain an acceptable type which cannot be
61 // merged
61 // merged
62 result = false;
62 result = false;
63 break;
63 break;
64 }
64 }
65 }
65 }
66
66
67 return result;
67 return result;
68 }
68 }
69
69
70 bool allowInsertForMimeData(const QMimeData *data) const
70 bool allowInsertForMimeData(const QMimeData *data) const
71 {
71 {
72 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
72 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
73 ++it) {
73 ++it) {
74 if (data->hasFormat(it.key())
74 if (data->hasFormat(it.key())
75 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
75 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
76 || it.value()
76 || it.value()
77 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
77 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
78 return true;
78 return true;
79 }
79 }
80 }
80 }
81
81
82 return false;
82 return false;
83 }
83 }
84
84
85 bool hasPlaceHolder() const
85 bool hasPlaceHolder() const
86 {
86 {
87 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
87 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
88 }
88 }
89
89
90 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
90 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
91 {
91 {
92 VisualizationDragWidget *dragWidget = nullptr;
92 VisualizationDragWidget *dragWidget = nullptr;
93
93
94 for (auto child : parent->children()) {
94 for (auto child : parent->children()) {
95 auto widget = qobject_cast<VisualizationDragWidget *>(child);
95 auto widget = qobject_cast<VisualizationDragWidget *>(child);
96 if (widget && widget->isVisible()) {
96 if (widget && widget->isVisible()) {
97 if (widget->frameGeometry().contains(pos)) {
97 if (widget->frameGeometry().contains(pos)) {
98 dragWidget = widget;
98 dragWidget = widget;
99 break;
99 break;
100 }
100 }
101 }
101 }
102 }
102 }
103
103
104 return dragWidget;
104 return dragWidget;
105 }
105 }
106
106
107 bool cursorIsInContainer(QWidget *container) const
107 bool cursorIsInContainer(QWidget *container) const
108 {
108 {
109 return container->isAncestorOf(sqpApp->widgetAt(QCursor::pos()));
109 return container->isAncestorOf(sqpApp->widgetAt(QCursor::pos()));
110 }
110 }
111
111
112 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
112 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
113 {
113 {
114 auto nbGraph = 0;
114 auto nbGraph = 0;
115 for (auto child : parent->children()) {
115 for (auto child : parent->children()) {
116 if (qobject_cast<VisualizationDragWidget *>(child)) {
116 if (qobject_cast<VisualizationDragWidget *>(child)) {
117 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
117 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
118 nbGraph += 1;
118 nbGraph += 1;
119 }
119 }
120 }
120 }
121 }
121 }
122
122
123 return nbGraph;
123 return nbGraph;
124 }
124 }
125
125
126 void findPlaceHolderPosition(const QPoint &pos, bool canInsert, bool canMerge,
126 void findPlaceHolderPosition(const QPoint &pos, bool canInsert, bool canMerge,
127 const VisualizationDragDropContainer *container);
127 const VisualizationDragDropContainer *container);
128 };
128 };
129
129
130 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
130 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
131 : QFrame{parent},
131 : QFrame{parent},
132 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
132 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
133 {
133 {
134 setAcceptDrops(true);
134 setAcceptDrops(true);
135 }
135 }
136
136
137 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
137 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
138 {
138 {
139 impl->m_Layout->addWidget(dragWidget);
139 impl->m_Layout->addWidget(dragWidget);
140 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
140 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
141 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
141 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
142 &VisualizationDragDropContainer::startDrag);
142 &VisualizationDragDropContainer::startDrag);
143 }
143 }
144
144
145 void VisualizationDragDropContainer::insertDragWidget(int index,
145 void VisualizationDragDropContainer::insertDragWidget(int index,
146 VisualizationDragWidget *dragWidget)
146 VisualizationDragWidget *dragWidget)
147 {
147 {
148 impl->m_Layout->insertWidget(index, dragWidget);
148 impl->m_Layout->insertWidget(index, dragWidget);
149 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
149 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
150 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
150 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
151 &VisualizationDragDropContainer::startDrag);
151 &VisualizationDragDropContainer::startDrag);
152 }
152 }
153
153
154 void VisualizationDragDropContainer::addAcceptedMimeType(
154 void VisualizationDragDropContainer::addAcceptedMimeType(
155 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
155 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
156 {
156 {
157 impl->m_AcceptedMimeTypes[mimeType] = behavior;
157 impl->m_AcceptedMimeTypes[mimeType] = behavior;
158 }
158 }
159
159
160 int VisualizationDragDropContainer::countDragWidget() const
160 int VisualizationDragDropContainer::countDragWidget() const
161 {
161 {
162 return impl->countDragWidget(this);
162 return impl->countDragWidget(this);
163 }
163 }
164
164
165 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
165 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
166 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
166 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
167 {
167 {
168 impl->m_AcceptMimeDataFun = fun;
168 impl->m_AcceptMimeDataFun = fun;
169 }
169 }
170
170
171 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
171 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
172 const QString &placeHolderText)
172 const QString &placeHolderText)
173 {
173 {
174 impl->m_PlaceHolderType = type;
174 impl->m_PlaceHolderType = type;
175 impl->m_PlaceHolderText = placeHolderText;
175 impl->m_PlaceHolderText = placeHolderText;
176 }
176 }
177
177
178 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
178 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
179 const QPoint &dragPosition)
179 const QPoint &dragPosition)
180 {
180 {
181 auto &helper = sqpApp->dragDropHelper();
181 auto &helper = sqpApp->dragDropHelper();
182 helper.resetDragAndDrop();
182 helper.resetDragAndDrop();
183
183
184 // Note: The management of the drag object is done by Qt
184 // Note: The management of the drag object is done by Qt
185 auto drag = new QDrag{dragWidget};
185 auto drag = new QDrag{dragWidget};
186 drag->setHotSpot(dragPosition);
186 drag->setHotSpot(dragPosition);
187
187
188 auto mimeData = dragWidget->mimeData();
188 auto mimeData = dragWidget->mimeData();
189 drag->setMimeData(mimeData);
189 drag->setMimeData(mimeData);
190
190
191 auto pixmap = QPixmap(dragWidget->size());
191 auto pixmap = QPixmap(dragWidget->size());
192 dragWidget->render(&pixmap);
192 dragWidget->render(&pixmap);
193 drag->setPixmap(pixmap);
193 drag->setPixmap(pixmap);
194
194
195 auto image = pixmap.toImage();
195 auto image = pixmap.toImage();
196 mimeData->setImageData(image);
196 mimeData->setImageData(image);
197 mimeData->setUrls({helper.imageTemporaryUrl(image)});
197 mimeData->setUrls({helper.imageTemporaryUrl(image)});
198
198
199 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
199 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
200 helper.setCurrentDragWidget(dragWidget);
200 helper.setCurrentDragWidget(dragWidget);
201
201
202 if (impl->cursorIsInContainer(this)) {
202 if (impl->cursorIsInContainer(this)) {
203 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
203 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
204 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
204 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
205 impl->m_PlaceHolderText);
205 impl->m_PlaceHolderText);
206 dragWidget->setVisible(false);
206 dragWidget->setVisible(false);
207 }
207 }
208 else {
208 else {
209 // The drag starts directly outside the drop zone
209 // The drag starts directly outside the drop zone
210 // do not add the placeHolder
210 // do not add the placeHolder
211 }
211 }
212
212
213 // Note: The exec() is blocking on windows but not on linux and macOS
213 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
214 drag->exec(Qt::MoveAction | Qt::CopyAction);
214
215 helper.doCloseWidgets();
215 }
216 }
216 else {
217 else {
217 qCWarning(LOG_VisualizationDragDropContainer())
218 qCWarning(LOG_VisualizationDragDropContainer())
218 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
219 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
219 "VisualizationDragWidget is not found in this container.");
220 "VisualizationDragWidget is not found in this container.");
220 }
221 }
221 }
222 }
222
223
223 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
224 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
224 {
225 {
225 if (impl->acceptMimeData(event->mimeData())) {
226 if (impl->acceptMimeData(event->mimeData())) {
226 event->acceptProposedAction();
227 event->acceptProposedAction();
227
228
228 auto &helper = sqpApp->dragDropHelper();
229 auto &helper = sqpApp->dragDropHelper();
229
230
230 if (!impl->hasPlaceHolder()) {
231 if (!impl->hasPlaceHolder()) {
231 auto dragWidget = helper.getCurrentDragWidget();
232 auto dragWidget = helper.getCurrentDragWidget();
232
233
233 if (dragWidget) {
234 if (dragWidget) {
234 // If the drag&drop is internal to the visualization, entering the container hide
235 // If the drag&drop is internal to the visualization, entering the container hide
235 // the dragWidget which was made visible by the dragLeaveEvent
236 // the dragWidget which was made visible by the dragLeaveEvent
236 auto parentWidget
237 auto parentWidget
237 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
238 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
238 if (parentWidget) {
239 if (parentWidget) {
239 dragWidget->setVisible(false);
240 dragWidget->setVisible(false);
240 }
241 }
241 }
242 }
242
243
243 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
244 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
244 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
245 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
245 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
246 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
246 }
247 }
247 else {
248 else {
248 // do nothing
249 // do nothing
249 }
250 }
250 }
251 }
251 else {
252 else {
252 event->ignore();
253 event->ignore();
253 }
254 }
254
255
255 QWidget::dragEnterEvent(event);
256 QWidget::dragEnterEvent(event);
256 }
257 }
257
258
258 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
259 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
259 {
260 {
260 Q_UNUSED(event);
261 Q_UNUSED(event);
261
262
262 auto &helper = sqpApp->dragDropHelper();
263 auto &helper = sqpApp->dragDropHelper();
263
264
264 if (!impl->cursorIsInContainer(this)) {
265 if (!impl->cursorIsInContainer(this)) {
265 helper.removePlaceHolder();
266 helper.removePlaceHolder();
266 helper.setHightlightedDragWidget(nullptr);
267 helper.setHightlightedDragWidget(nullptr);
267 impl->m_MinContainerHeight = 0;
268 impl->m_MinContainerHeight = 0;
268
269
269 auto dragWidget = helper.getCurrentDragWidget();
270 auto dragWidget = helper.getCurrentDragWidget();
270 if (dragWidget) {
271 if (dragWidget) {
271 // dragWidget has a value only if the drag is started from the visualization
272 // dragWidget has a value only if the drag is started from the visualization
272 // In that case, shows the drag widget at its original place
273 // In that case, shows the drag widget at its original place
273 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
274 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
274 // drop zone (It is not possible to catch a drop event outside of the application)
275 // drop zone (It is not possible to catch a drop event outside of the application)
275
276
276 if (dragWidget) {
277 if (dragWidget) {
277 dragWidget->setVisible(true);
278 dragWidget->setVisible(true);
278 }
279 }
279 }
280 }
280 }
281 }
281 else {
282 else {
282 // Leave event probably received for a child widget.
283 // Leave event probably received for a child widget.
283 // Do nothing.
284 // Do nothing.
284 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
285 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
285 }
286 }
286
287
287 QWidget::dragLeaveEvent(event);
288 QWidget::dragLeaveEvent(event);
288 }
289 }
289
290
290 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
291 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
291 {
292 {
292 if (impl->acceptMimeData(event->mimeData())) {
293 if (impl->acceptMimeData(event->mimeData())) {
293 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
294 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
294 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
295 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
295 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
296 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
296 }
297 }
297 else {
298 else {
298 event->ignore();
299 event->ignore();
299 }
300 }
300
301
301 QWidget::dragMoveEvent(event);
302 QWidget::dragMoveEvent(event);
302 }
303 }
303
304
304 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
305 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
305 {
306 {
306 auto &helper = sqpApp->dragDropHelper();
307 auto &helper = sqpApp->dragDropHelper();
307
308
308 if (impl->acceptMimeData(event->mimeData())) {
309 if (impl->acceptMimeData(event->mimeData())) {
309 auto dragWidget = helper.getCurrentDragWidget();
310 auto dragWidget = helper.getCurrentDragWidget();
310 if (impl->hasPlaceHolder()) {
311 if (impl->hasPlaceHolder()) {
311 // drop where the placeHolder is located
312 // drop where the placeHolder is located
312
313
313 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
314 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
314 if (canInsert) {
315 if (canInsert) {
315 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
316 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
316
317
317 if (dragWidget) {
318 if (dragWidget) {
318 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
319 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
319 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
320 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
320 // Correction of the index if the drop occurs in the same container
321 // Correction of the index if the drop occurs in the same container
321 // and if the drag is started from the visualization (in that case, the
322 // and if the drag is started from the visualization (in that case, the
322 // dragWidget is hidden)
323 // dragWidget is hidden)
323 droppedIndex -= 1;
324 droppedIndex -= 1;
324 }
325 }
325
326
326 dragWidget->setVisible(true);
327 dragWidget->setVisible(true);
327 }
328 }
328
329
329 event->acceptProposedAction();
330 event->acceptProposedAction();
330
331
331 helper.removePlaceHolder();
332 helper.removePlaceHolder();
332
333
333 emit dropOccuredInContainer(droppedIndex, event->mimeData());
334 emit dropOccuredInContainer(droppedIndex, event->mimeData());
334 }
335 }
335 else {
336 else {
336 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
337 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
337 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
338 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
338 "the insertion is forbidden.");
339 "the insertion is forbidden.");
339 Q_ASSERT(false);
340 Q_ASSERT(false);
340 }
341 }
341 }
342 }
342 else if (helper.getHightlightedDragWidget()) {
343 else if (helper.getHightlightedDragWidget()) {
343 // drop on the highlighted widget
344 // drop on the highlighted widget
344
345
345 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
346 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
346 if (canMerge) {
347 if (canMerge) {
347 event->acceptProposedAction();
348 event->acceptProposedAction();
348 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
349 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
349 }
350 }
350 else {
351 else {
351 qCWarning(LOG_VisualizationDragDropContainer())
352 qCWarning(LOG_VisualizationDragDropContainer())
352 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
353 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
353 "the merge is forbidden.");
354 "the merge is forbidden.");
354 Q_ASSERT(false);
355 Q_ASSERT(false);
355 }
356 }
356 }
357 }
357 }
358 }
358 else {
359 else {
359 event->ignore();
360 event->ignore();
360 }
361 }
361
362
362 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
363 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
363 impl->m_MinContainerHeight = 0;
364 impl->m_MinContainerHeight = 0;
364
365
365 QWidget::dropEvent(event);
366 QWidget::dropEvent(event);
366 }
367 }
367
368
368
369
369 void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
370 void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
370 const QPoint &pos, bool canInsert, bool canMerge,
371 const QPoint &pos, bool canInsert, bool canMerge,
371 const VisualizationDragDropContainer *container)
372 const VisualizationDragDropContainer *container)
372 {
373 {
373 auto &helper = sqpApp->dragDropHelper();
374 auto &helper = sqpApp->dragDropHelper();
374
375
375 auto absPos = container->mapToGlobal(pos);
376 auto absPos = container->mapToGlobal(pos);
376 auto isOnPlaceHolder = sqpApp->widgetAt(absPos) == &(helper.placeHolder());
377 auto isOnPlaceHolder = sqpApp->widgetAt(absPos) == &(helper.placeHolder());
377
378
378 if (countDragWidget(container, true) == 0) {
379 if (countDragWidget(container, true) == 0) {
379 // Drop on an empty container, just add the placeHolder at the top
380 // Drop on an empty container, just add the placeHolder at the top
380 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
381 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
381 }
382 }
382 else if (!isOnPlaceHolder) {
383 else if (!isOnPlaceHolder) {
383 auto nbDragWidget = countDragWidget(container);
384 auto nbDragWidget = countDragWidget(container);
384 if (nbDragWidget > 0) {
385 if (nbDragWidget > 0) {
385
386
386 if (m_MinContainerHeight == 0) {
387 if (m_MinContainerHeight == 0) {
387 m_MinContainerHeight = container->size().height();
388 m_MinContainerHeight = container->size().height();
388 }
389 }
389
390
390 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
391 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
391 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
392 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
392
393
393 auto posY = pos.y();
394 auto posY = pos.y();
394 auto dropIndex = floor(posY / graphHeight);
395 auto dropIndex = floor(posY / graphHeight);
395 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
396 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
396
397
397
398
398 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
399 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
399 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
400 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
400
401
401 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
402 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
402
403
403 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
404 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
404
405
405 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
406 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
406 if (isOnBottom) {
407 if (isOnBottom) {
407 dropIndex += 1;
408 dropIndex += 1;
408 }
409 }
409
410
410 if (helper.getCurrentDragWidget()) {
411 if (helper.getCurrentDragWidget()) {
411 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
412 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
412 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
413 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
413 // Correction of the index if the drop occurs in the same container
414 // Correction of the index if the drop occurs in the same container
414 // and if the drag is started from the visualization (in that case, the
415 // and if the drag is started from the visualization (in that case, the
415 // dragWidget is hidden)
416 // dragWidget is hidden)
416 dropIndex += 1;
417 dropIndex += 1;
417 }
418 }
418 }
419 }
419
420
420 if (dropIndex != placeHolderIndex) {
421 if (dropIndex != placeHolderIndex) {
421 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
422 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
422 m_PlaceHolderText);
423 m_PlaceHolderText);
423 }
424 }
424
425
425 helper.setHightlightedDragWidget(nullptr);
426 helper.setHightlightedDragWidget(nullptr);
426 }
427 }
427 else if (canMerge && dragWidgetHovered) {
428 else if (canMerge && dragWidgetHovered) {
428 // drop on the middle -> merge
429 // drop on the middle -> merge
429 if (hasPlaceHolder()) {
430 if (hasPlaceHolder()) {
430 helper.removePlaceHolder();
431 helper.removePlaceHolder();
431 }
432 }
432
433
433 helper.setHightlightedDragWidget(dragWidgetHovered);
434 helper.setHightlightedDragWidget(dragWidgetHovered);
434 }
435 }
435 else {
436 else {
436 qCWarning(LOG_VisualizationDragDropContainer())
437 qCWarning(LOG_VisualizationDragDropContainer())
437 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
438 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
438 "action.");
439 "action.");
439 }
440 }
440 }
441 }
441 else {
442 else {
442 qCWarning(LOG_VisualizationDragDropContainer())
443 qCWarning(LOG_VisualizationDragDropContainer())
443 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
444 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
444 "found in the "
445 "found in the "
445 "container");
446 "container");
446 }
447 }
447 }
448 }
448 else {
449 else {
449 // the mouse is hover the placeHolder
450 // the mouse is hover the placeHolder
450 // Do nothing
451 // Do nothing
451 }
452 }
452 }
453 }
@@ -1,309 +1,309
1 #include "Visualization/VisualizationTabWidget.h"
1 #include "Visualization/VisualizationTabWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "ui_VisualizationTabWidget.h"
3 #include "ui_VisualizationTabWidget.h"
4
4
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7
7
8 #include "Variable/VariableController.h"
8 #include "Variable/VariableController.h"
9
9
10 #include "Common/MimeTypesDef.h"
10 #include "Common/MimeTypesDef.h"
11
11
12 #include "DragAndDrop/DragDropHelper.h"
12 #include "DragAndDrop/DragDropHelper.h"
13 #include "SqpApplication.h"
13 #include "SqpApplication.h"
14
14
15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
16
16
17 namespace {
17 namespace {
18
18
19 /// Generates a default name for a new zone, according to the number of zones already displayed in
19 /// Generates a default name for a new zone, according to the number of zones already displayed in
20 /// the tab
20 /// the tab
21 QString defaultZoneName(const QLayout &layout)
21 QString defaultZoneName(const QLayout &layout)
22 {
22 {
23 auto count = 0;
23 auto count = 0;
24 for (auto i = 0; i < layout.count(); ++i) {
24 for (auto i = 0; i < layout.count(); ++i) {
25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
26 count++;
26 count++;
27 }
27 }
28 }
28 }
29
29
30 return QObject::tr("Zone %1").arg(count + 1);
30 return QObject::tr("Zone %1").arg(count + 1);
31 }
31 }
32
32
33 /**
33 /**
34 * Applies a function to all zones of the tab represented by its layout
34 * Applies a function to all zones of the tab represented by its layout
35 * @param layout the layout that contains zones
35 * @param layout the layout that contains zones
36 * @param fun the function to apply to each zone
36 * @param fun the function to apply to each zone
37 */
37 */
38 template <typename Fun>
38 template <typename Fun>
39 void processZones(QLayout &layout, Fun fun)
39 void processZones(QLayout &layout, Fun fun)
40 {
40 {
41 for (auto i = 0; i < layout.count(); ++i) {
41 for (auto i = 0; i < layout.count(); ++i) {
42 if (auto item = layout.itemAt(i)) {
42 if (auto item = layout.itemAt(i)) {
43 if (auto visualizationZoneWidget
43 if (auto visualizationZoneWidget
44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
45 fun(*visualizationZoneWidget);
45 fun(*visualizationZoneWidget);
46 }
46 }
47 }
47 }
48 }
48 }
49 }
49 }
50
50
51 } // namespace
51 } // namespace
52
52
53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
55
55
56 QString m_Name;
56 QString m_Name;
57
57
58 void dropGraph(int index, VisualizationTabWidget *tabWidget);
58 void dropGraph(int index, VisualizationTabWidget *tabWidget);
59 void dropZone(int index, VisualizationTabWidget *tabWidget);
59 void dropZone(int index, VisualizationTabWidget *tabWidget);
60 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
60 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
61 VisualizationTabWidget *tabWidget);
61 VisualizationTabWidget *tabWidget);
62 };
62 };
63
63
64 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
64 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
65 : QWidget{parent},
65 : QWidget{parent},
66 ui{new Ui::VisualizationTabWidget},
66 ui{new Ui::VisualizationTabWidget},
67 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
67 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
68 {
68 {
69 ui->setupUi(this);
69 ui->setupUi(this);
70
70
71 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone");
71 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone");
72 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 5);
72 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 5);
73 ui->dragDropContainer->addAcceptedMimeType(
73 ui->dragDropContainer->addAcceptedMimeType(
74 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
74 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
75 ui->dragDropContainer->addAcceptedMimeType(
75 ui->dragDropContainer->addAcceptedMimeType(
76 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
76 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
77 ui->dragDropContainer->addAcceptedMimeType(
77 ui->dragDropContainer->addAcceptedMimeType(
78 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
78 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
79
79
80 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
80 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
81 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
81 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
82 ui->dragDropContainer);
82 ui->dragDropContainer);
83 });
83 });
84
84
85 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
85 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
86 &VisualizationTabWidget::dropMimeData);
86 &VisualizationTabWidget::dropMimeData);
87
87
88 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
88 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
89
89
90 // Widget is deleted when closed
90 // Widget is deleted when closed
91 setAttribute(Qt::WA_DeleteOnClose);
91 setAttribute(Qt::WA_DeleteOnClose);
92 }
92 }
93
93
94 VisualizationTabWidget::~VisualizationTabWidget()
94 VisualizationTabWidget::~VisualizationTabWidget()
95 {
95 {
96 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
96 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
97 delete ui;
97 delete ui;
98 }
98 }
99
99
100 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
100 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
101 {
101 {
102 ui->dragDropContainer->addDragWidget(zoneWidget);
102 ui->dragDropContainer->addDragWidget(zoneWidget);
103 }
103 }
104
104
105 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
105 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
106 {
106 {
107 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
107 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
108 }
108 }
109
109
110 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
110 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
111 {
111 {
112 return createZone({variable}, -1);
112 return createZone({variable}, -1);
113 }
113 }
114
114
115 VisualizationZoneWidget *
115 VisualizationZoneWidget *
116 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
116 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
117 {
117 {
118 auto zoneWidget = createEmptyZone(index);
118 auto zoneWidget = createEmptyZone(index);
119
119
120 // Creates a new graph into the zone
120 // Creates a new graph into the zone
121 zoneWidget->createGraph(variables, index);
121 zoneWidget->createGraph(variables, index);
122
122
123 return zoneWidget;
123 return zoneWidget;
124 }
124 }
125
125
126 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
126 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
127 {
127 {
128 auto zoneWidget
128 auto zoneWidget
129 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
129 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
130 this->insertZone(index, zoneWidget);
130 this->insertZone(index, zoneWidget);
131
131
132 return zoneWidget;
132 return zoneWidget;
133 }
133 }
134
134
135 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
135 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
136 {
136 {
137 if (visitor) {
137 if (visitor) {
138 visitor->visitEnter(this);
138 visitor->visitEnter(this);
139
139
140 // Apply visitor to zone children: widgets different from zones are not visited (no action)
140 // Apply visitor to zone children: widgets different from zones are not visited (no action)
141 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
141 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
142 zoneWidget.accept(visitor);
142 zoneWidget.accept(visitor);
143 });
143 });
144
144
145 visitor->visitLeave(this);
145 visitor->visitLeave(this);
146 }
146 }
147 else {
147 else {
148 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
148 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
149 }
149 }
150 }
150 }
151
151
152 bool VisualizationTabWidget::canDrop(const Variable &variable) const
152 bool VisualizationTabWidget::canDrop(const Variable &variable) const
153 {
153 {
154 // A tab can always accomodate a variable
154 // A tab can always accomodate a variable
155 Q_UNUSED(variable);
155 Q_UNUSED(variable);
156 return true;
156 return true;
157 }
157 }
158
158
159 bool VisualizationTabWidget::contains(const Variable &variable) const
159 bool VisualizationTabWidget::contains(const Variable &variable) const
160 {
160 {
161 Q_UNUSED(variable);
161 Q_UNUSED(variable);
162 return false;
162 return false;
163 }
163 }
164
164
165 QString VisualizationTabWidget::name() const
165 QString VisualizationTabWidget::name() const
166 {
166 {
167 return impl->m_Name;
167 return impl->m_Name;
168 }
168 }
169
169
170 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
170 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
171 {
171 {
172 // Closes zones in the tab
172 // Closes zones in the tab
173 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
173 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
174
174
175 QWidget::closeEvent(event);
175 QWidget::closeEvent(event);
176 }
176 }
177
177
178 QLayout &VisualizationTabWidget::tabLayout() const noexcept
178 QLayout &VisualizationTabWidget::tabLayout() const noexcept
179 {
179 {
180 return *ui->dragDropContainer->layout();
180 return *ui->dragDropContainer->layout();
181 }
181 }
182
182
183 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
183 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
184 {
184 {
185 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
185 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
186 impl->dropGraph(index, this);
186 impl->dropGraph(index, this);
187 }
187 }
188 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
188 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
189 impl->dropZone(index, this);
189 impl->dropZone(index, this);
190 }
190 }
191 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
191 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
192 auto variables = sqpApp->variableController().variablesForMimeData(
192 auto variables = sqpApp->variableController().variablesForMimeData(
193 mimeData->data(MIME_TYPE_VARIABLE_LIST));
193 mimeData->data(MIME_TYPE_VARIABLE_LIST));
194 impl->dropVariables(variables, index, this);
194 impl->dropVariables(variables, index, this);
195 }
195 }
196 else {
196 else {
197 qCWarning(LOG_VisualizationZoneWidget())
197 qCWarning(LOG_VisualizationZoneWidget())
198 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
198 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
199 }
199 }
200 }
200 }
201
201
202 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
202 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
203 int index, VisualizationTabWidget *tabWidget)
203 int index, VisualizationTabWidget *tabWidget)
204 {
204 {
205 auto &helper = sqpApp->dragDropHelper();
205 auto &helper = sqpApp->dragDropHelper();
206
206
207 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
207 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
208 if (!graphWidget) {
208 if (!graphWidget) {
209 qCWarning(LOG_VisualizationZoneWidget())
209 qCWarning(LOG_VisualizationZoneWidget())
210 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
210 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
211 "found or invalid.");
211 "found or invalid.");
212 Q_ASSERT(false);
212 Q_ASSERT(false);
213 return;
213 return;
214 }
214 }
215
215
216 auto parentDragDropContainer
216 auto parentDragDropContainer
217 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
217 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
218 if (!parentDragDropContainer) {
218 if (!parentDragDropContainer) {
219 qCWarning(LOG_VisualizationZoneWidget())
219 qCWarning(LOG_VisualizationZoneWidget())
220 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
220 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
221 "the dropped graph is not found.");
221 "the dropped graph is not found.");
222 Q_ASSERT(false);
222 Q_ASSERT(false);
223 return;
223 return;
224 }
224 }
225
225
226 auto nbGraph = parentDragDropContainer->countDragWidget();
226 auto nbGraph = parentDragDropContainer->countDragWidget();
227
227
228 const auto &variables = graphWidget->variables();
228 const auto &variables = graphWidget->variables();
229
229
230 if (!variables.isEmpty()) {
230 if (!variables.isEmpty()) {
231 // Abort the requests for the variables (if any)
231 // Abort the requests for the variables (if any)
232 // Commented, because it's not sure if it's needed or not
232 // Commented, because it's not sure if it's needed or not
233 // for (const auto& var : variables)
233 // for (const auto& var : variables)
234 //{
234 //{
235 // sqpApp->variableController().onAbortProgressRequested(var);
235 // sqpApp->variableController().onAbortProgressRequested(var);
236 //}
236 //}
237
237
238 if (nbGraph == 1) {
238 if (nbGraph == 1) {
239 // This is the only graph in the previous zone, close the zone
239 // This is the only graph in the previous zone, close the zone
240 graphWidget->parentZoneWidget()->close();
240 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
241 }
241 }
242 else {
242 else {
243 // Close the graph
243 // Close the graph
244 graphWidget->close();
244 helper.delayedCloseWidget(graphWidget);
245 }
245 }
246
246
247 tabWidget->createZone(variables, index);
247 tabWidget->createZone(variables, index);
248 }
248 }
249 else {
249 else {
250 // The graph is empty, create an empty zone and move the graph inside
250 // The graph is empty, create an empty zone and move the graph inside
251
251
252 auto parentZoneWidget = graphWidget->parentZoneWidget();
252 auto parentZoneWidget = graphWidget->parentZoneWidget();
253
253
254 parentDragDropContainer->layout()->removeWidget(graphWidget);
254 parentDragDropContainer->layout()->removeWidget(graphWidget);
255
255
256 auto zoneWidget = tabWidget->createEmptyZone(index);
256 auto zoneWidget = tabWidget->createEmptyZone(index);
257 zoneWidget->addGraph(graphWidget);
257 zoneWidget->addGraph(graphWidget);
258
258
259 // Close the old zone if it was the only graph inside
259 // Close the old zone if it was the only graph inside
260 if (nbGraph == 1) {
260 if (nbGraph == 1) {
261 parentZoneWidget->close();
261 helper.delayedCloseWidget(parentZoneWidget);
262 }
262 }
263 }
263 }
264 }
264 }
265
265
266 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
266 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
267 int index, VisualizationTabWidget *tabWidget)
267 int index, VisualizationTabWidget *tabWidget)
268 {
268 {
269 auto &helper = sqpApp->dragDropHelper();
269 auto &helper = sqpApp->dragDropHelper();
270
270
271 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
271 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
272 if (!zoneWidget) {
272 if (!zoneWidget) {
273 qCWarning(LOG_VisualizationZoneWidget())
273 qCWarning(LOG_VisualizationZoneWidget())
274 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
274 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
275 "found or invalid.");
275 "found or invalid.");
276 Q_ASSERT(false);
276 Q_ASSERT(false);
277 return;
277 return;
278 }
278 }
279
279
280 auto parentDragDropContainer
280 auto parentDragDropContainer
281 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
281 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
282 if (!parentDragDropContainer) {
282 if (!parentDragDropContainer) {
283 qCWarning(LOG_VisualizationZoneWidget())
283 qCWarning(LOG_VisualizationZoneWidget())
284 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
284 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
285 "the dropped zone is not found.");
285 "the dropped zone is not found.");
286 Q_ASSERT(false);
286 Q_ASSERT(false);
287 return;
287 return;
288 }
288 }
289
289
290 // Simple move of the zone, no variable operation associated
290 // Simple move of the zone, no variable operation associated
291 parentDragDropContainer->layout()->removeWidget(zoneWidget);
291 parentDragDropContainer->layout()->removeWidget(zoneWidget);
292 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
292 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
293 }
293 }
294
294
295 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
295 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
296 const QList<std::shared_ptr<Variable> > &variables, int index,
296 const QList<std::shared_ptr<Variable> > &variables, int index,
297 VisualizationTabWidget *tabWidget)
297 VisualizationTabWidget *tabWidget)
298 {
298 {
299 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
299 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
300 // compatible variable here
300 // compatible variable here
301 if (variables.count() > 1) {
301 if (variables.count() > 1) {
302 qCWarning(LOG_VisualizationZoneWidget())
302 qCWarning(LOG_VisualizationZoneWidget())
303 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
303 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
304 "aborted.");
304 "aborted.");
305 return;
305 return;
306 }
306 }
307
307
308 tabWidget->createZone(variables, index);
308 tabWidget->createZone(variables, index);
309 }
309 }
@@ -1,500 +1,500
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/VisualizationWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
8
8
9 #include "Common/MimeTypesDef.h"
9 #include "Common/MimeTypesDef.h"
10 #include "Common/VisualizationDef.h"
10 #include "Common/VisualizationDef.h"
11
11
12 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14 #include <Variable/Variable.h>
14 #include <Variable/Variable.h>
15 #include <Variable/VariableController.h>
15 #include <Variable/VariableController.h>
16
16
17 #include <Visualization/operations/FindVariableOperation.h>
17 #include <Visualization/operations/FindVariableOperation.h>
18
18
19 #include <DragAndDrop/DragDropHelper.h>
19 #include <DragAndDrop/DragDropHelper.h>
20 #include <QUuid>
20 #include <QUuid>
21 #include <SqpApplication.h>
21 #include <SqpApplication.h>
22 #include <cmath>
22 #include <cmath>
23
23
24 #include <QLayout>
24 #include <QLayout>
25
25
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27
27
28 namespace {
28 namespace {
29
29
30
30
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
32 /// the zone
32 /// the zone
33 QString defaultGraphName(const QLayout &layout)
33 QString defaultGraphName(const QLayout &layout)
34 {
34 {
35 auto count = 0;
35 auto count = 0;
36 for (auto i = 0; i < layout.count(); ++i) {
36 for (auto i = 0; i < layout.count(); ++i) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
38 count++;
38 count++;
39 }
39 }
40 }
40 }
41
41
42 return QObject::tr("Graph %1").arg(count + 1);
42 return QObject::tr("Graph %1").arg(count + 1);
43 }
43 }
44
44
45 /**
45 /**
46 * Applies a function to all graphs of the zone represented by its layout
46 * Applies a function to all graphs of the zone represented by its layout
47 * @param layout the layout that contains graphs
47 * @param layout the layout that contains graphs
48 * @param fun the function to apply to each graph
48 * @param fun the function to apply to each graph
49 */
49 */
50 template <typename Fun>
50 template <typename Fun>
51 void processGraphs(QLayout &layout, Fun fun)
51 void processGraphs(QLayout &layout, Fun fun)
52 {
52 {
53 for (auto i = 0; i < layout.count(); ++i) {
53 for (auto i = 0; i < layout.count(); ++i) {
54 if (auto item = layout.itemAt(i)) {
54 if (auto item = layout.itemAt(i)) {
55 if (auto visualizationGraphWidget
55 if (auto visualizationGraphWidget
56 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
56 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
57 fun(*visualizationGraphWidget);
57 fun(*visualizationGraphWidget);
58 }
58 }
59 }
59 }
60 }
60 }
61 }
61 }
62
62
63 } // namespace
63 } // namespace
64
64
65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
66
66
67 explicit VisualizationZoneWidgetPrivate()
67 explicit VisualizationZoneWidgetPrivate()
68 : m_SynchronisationGroupId{QUuid::createUuid()},
68 : m_SynchronisationGroupId{QUuid::createUuid()},
69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
70 {
70 {
71 }
71 }
72 QUuid m_SynchronisationGroupId;
72 QUuid m_SynchronisationGroupId;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
74
74
75 // Returns the first graph in the zone or nullptr if there is no graph inside
75 // Returns the first graph in the zone or nullptr if there is no graph inside
76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
77 {
77 {
78 VisualizationGraphWidget *firstGraph = nullptr;
78 VisualizationGraphWidget *firstGraph = nullptr;
79 auto layout = zoneWidget->ui->dragDropContainer->layout();
79 auto layout = zoneWidget->ui->dragDropContainer->layout();
80 if (layout->count() > 0) {
80 if (layout->count() > 0) {
81 if (auto visualizationGraphWidget
81 if (auto visualizationGraphWidget
82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
83 firstGraph = visualizationGraphWidget;
83 firstGraph = visualizationGraphWidget;
84 }
84 }
85 }
85 }
86
86
87 return firstGraph;
87 return firstGraph;
88 }
88 }
89
89
90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
92 VisualizationZoneWidget *zoneWidget);
92 VisualizationZoneWidget *zoneWidget);
93 };
93 };
94
94
95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
96 : VisualizationDragWidget{parent},
96 : VisualizationDragWidget{parent},
97 ui{new Ui::VisualizationZoneWidget},
97 ui{new Ui::VisualizationZoneWidget},
98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
99 {
99 {
100 ui->setupUi(this);
100 ui->setupUi(this);
101
101
102 ui->zoneNameLabel->setText(name);
102 ui->zoneNameLabel->setText(name);
103
103
104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
105 ui->dragDropContainer->addAcceptedMimeType(
105 ui->dragDropContainer->addAcceptedMimeType(
106 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
106 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
107 ui->dragDropContainer->addAcceptedMimeType(
107 ui->dragDropContainer->addAcceptedMimeType(
108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
109 ui->dragDropContainer->addAcceptedMimeType(
109 ui->dragDropContainer->addAcceptedMimeType(
110 MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
110 MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
111 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
111 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
112 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
112 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
113 ui->dragDropContainer);
113 ui->dragDropContainer);
114 });
114 });
115
115
116 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
116 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
117 &VisualizationZoneWidget::dropMimeData);
117 &VisualizationZoneWidget::dropMimeData);
118 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
118 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
119 &VisualizationZoneWidget::dropMimeDataOnGraph);
119 &VisualizationZoneWidget::dropMimeDataOnGraph);
120
120
121 // 'Close' options : widget is deleted when closed
121 // 'Close' options : widget is deleted when closed
122 setAttribute(Qt::WA_DeleteOnClose);
122 setAttribute(Qt::WA_DeleteOnClose);
123 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
123 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
124 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
124 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
125
125
126 // Synchronisation id
126 // Synchronisation id
127 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
127 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
128 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
128 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
129 }
129 }
130
130
131 VisualizationZoneWidget::~VisualizationZoneWidget()
131 VisualizationZoneWidget::~VisualizationZoneWidget()
132 {
132 {
133 delete ui;
133 delete ui;
134 }
134 }
135
135
136 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
136 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
137 {
137 {
138 // Synchronize new graph with others in the zone
138 // Synchronize new graph with others in the zone
139 impl->m_Synchronizer->addGraph(*graphWidget);
139 impl->m_Synchronizer->addGraph(*graphWidget);
140
140
141 ui->dragDropContainer->addDragWidget(graphWidget);
141 ui->dragDropContainer->addDragWidget(graphWidget);
142 }
142 }
143
143
144 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
144 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
145 {
145 {
146 // Synchronize new graph with others in the zone
146 // Synchronize new graph with others in the zone
147 impl->m_Synchronizer->addGraph(*graphWidget);
147 impl->m_Synchronizer->addGraph(*graphWidget);
148
148
149 ui->dragDropContainer->insertDragWidget(index, graphWidget);
149 ui->dragDropContainer->insertDragWidget(index, graphWidget);
150 }
150 }
151
151
152 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
152 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
153 {
153 {
154 return createGraph(variable, -1);
154 return createGraph(variable, -1);
155 }
155 }
156
156
157 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
157 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
158 int index)
158 int index)
159 {
159 {
160 auto graphWidget
160 auto graphWidget
161 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
161 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
162
162
163
163
164 // Set graph properties
164 // Set graph properties
165 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
165 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
166 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
166 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
167
167
168
168
169 // Lambda to synchronize zone widget
169 // Lambda to synchronize zone widget
170 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
170 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
171 const SqpRange &oldGraphRange) {
171 const SqpRange &oldGraphRange) {
172
172
173 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
173 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
174 auto frameLayout = ui->dragDropContainer->layout();
174 auto frameLayout = ui->dragDropContainer->layout();
175 for (auto i = 0; i < frameLayout->count(); ++i) {
175 for (auto i = 0; i < frameLayout->count(); ++i) {
176 auto graphChild
176 auto graphChild
177 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
177 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
178 if (graphChild && (graphChild != graphWidget)) {
178 if (graphChild && (graphChild != graphWidget)) {
179
179
180 auto graphChildRange = graphChild->graphRange();
180 auto graphChildRange = graphChild->graphRange();
181 switch (zoomType) {
181 switch (zoomType) {
182 case AcquisitionZoomType::ZoomIn: {
182 case AcquisitionZoomType::ZoomIn: {
183 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
183 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
184 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
184 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
185 graphChildRange.m_TStart += deltaLeft;
185 graphChildRange.m_TStart += deltaLeft;
186 graphChildRange.m_TEnd -= deltaRight;
186 graphChildRange.m_TEnd -= deltaRight;
187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
189 << deltaLeft;
189 << deltaLeft;
190 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
190 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
191 << deltaRight;
191 << deltaRight;
192 qCDebug(LOG_VisualizationZoneWidget())
192 qCDebug(LOG_VisualizationZoneWidget())
193 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
193 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
194
194
195 break;
195 break;
196 }
196 }
197
197
198 case AcquisitionZoomType::ZoomOut: {
198 case AcquisitionZoomType::ZoomOut: {
199 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
199 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
200 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
200 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
201 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
201 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
202 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
202 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
203 << deltaLeft;
203 << deltaLeft;
204 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
204 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
205 << deltaRight;
205 << deltaRight;
206 qCDebug(LOG_VisualizationZoneWidget())
206 qCDebug(LOG_VisualizationZoneWidget())
207 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
207 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
208 graphChildRange.m_TStart -= deltaLeft;
208 graphChildRange.m_TStart -= deltaLeft;
209 graphChildRange.m_TEnd += deltaRight;
209 graphChildRange.m_TEnd += deltaRight;
210 break;
210 break;
211 }
211 }
212 case AcquisitionZoomType::PanRight: {
212 case AcquisitionZoomType::PanRight: {
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
215 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
215 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
216 graphChildRange.m_TStart += deltaLeft;
216 graphChildRange.m_TStart += deltaLeft;
217 graphChildRange.m_TEnd += deltaRight;
217 graphChildRange.m_TEnd += deltaRight;
218 qCDebug(LOG_VisualizationZoneWidget())
218 qCDebug(LOG_VisualizationZoneWidget())
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
220 break;
220 break;
221 }
221 }
222 case AcquisitionZoomType::PanLeft: {
222 case AcquisitionZoomType::PanLeft: {
223 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
223 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
224 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
224 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
225 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
225 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
226 graphChildRange.m_TStart -= deltaLeft;
226 graphChildRange.m_TStart -= deltaLeft;
227 graphChildRange.m_TEnd -= deltaRight;
227 graphChildRange.m_TEnd -= deltaRight;
228 break;
228 break;
229 }
229 }
230 case AcquisitionZoomType::Unknown: {
230 case AcquisitionZoomType::Unknown: {
231 qCDebug(LOG_VisualizationZoneWidget())
231 qCDebug(LOG_VisualizationZoneWidget())
232 << tr("Impossible to synchronize: zoom type unknown");
232 << tr("Impossible to synchronize: zoom type unknown");
233 break;
233 break;
234 }
234 }
235 default:
235 default:
236 qCCritical(LOG_VisualizationZoneWidget())
236 qCCritical(LOG_VisualizationZoneWidget())
237 << tr("Impossible to synchronize: zoom type not take into account");
237 << tr("Impossible to synchronize: zoom type not take into account");
238 // No action
238 // No action
239 break;
239 break;
240 }
240 }
241 graphChild->enableAcquisition(false);
241 graphChild->enableAcquisition(false);
242 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
242 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
243 << graphChild->graphRange();
243 << graphChild->graphRange();
244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
245 << graphChildRange;
245 << graphChildRange;
246 qCDebug(LOG_VisualizationZoneWidget())
246 qCDebug(LOG_VisualizationZoneWidget())
247 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
247 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
248 graphChild->setGraphRange(graphChildRange);
248 graphChild->setGraphRange(graphChildRange);
249 graphChild->enableAcquisition(true);
249 graphChild->enableAcquisition(true);
250 }
250 }
251 }
251 }
252 };
252 };
253
253
254 // connection for synchronization
254 // connection for synchronization
255 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
255 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
256 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
256 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
257 &VisualizationZoneWidget::onVariableAdded);
257 &VisualizationZoneWidget::onVariableAdded);
258 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
258 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
259 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
259 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
260
260
261 auto range = SqpRange{};
261 auto range = SqpRange{};
262 if (auto firstGraph = impl->firstGraph(this)) {
262 if (auto firstGraph = impl->firstGraph(this)) {
263 // Case of a new graph in a existant zone
263 // Case of a new graph in a existant zone
264 range = firstGraph->graphRange();
264 range = firstGraph->graphRange();
265 }
265 }
266 else {
266 else {
267 // Case of a new graph as the first of the zone
267 // Case of a new graph as the first of the zone
268 range = variable->range();
268 range = variable->range();
269 }
269 }
270
270
271 this->insertGraph(index, graphWidget);
271 this->insertGraph(index, graphWidget);
272
272
273 graphWidget->addVariable(variable, range);
273 graphWidget->addVariable(variable, range);
274 graphWidget->setYRange(variable);
274 graphWidget->setYRange(variable);
275
275
276 return graphWidget;
276 return graphWidget;
277 }
277 }
278
278
279 VisualizationGraphWidget *
279 VisualizationGraphWidget *
280 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
280 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
281 {
281 {
282 if (variables.isEmpty()) {
282 if (variables.isEmpty()) {
283 return nullptr;
283 return nullptr;
284 }
284 }
285
285
286 auto graphWidget = createGraph(variables.first(), index);
286 auto graphWidget = createGraph(variables.first(), index);
287 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
287 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
288 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
288 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
289 }
289 }
290
290
291 return graphWidget;
291 return graphWidget;
292 }
292 }
293
293
294 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
294 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
295 {
295 {
296 if (visitor) {
296 if (visitor) {
297 visitor->visitEnter(this);
297 visitor->visitEnter(this);
298
298
299 // Apply visitor to graph children: widgets different from graphs are not visited (no
299 // Apply visitor to graph children: widgets different from graphs are not visited (no
300 // action)
300 // action)
301 processGraphs(
301 processGraphs(
302 *ui->dragDropContainer->layout(),
302 *ui->dragDropContainer->layout(),
303 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
303 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
304
304
305 visitor->visitLeave(this);
305 visitor->visitLeave(this);
306 }
306 }
307 else {
307 else {
308 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
308 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
309 }
309 }
310 }
310 }
311
311
312 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
312 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
313 {
313 {
314 // A tab can always accomodate a variable
314 // A tab can always accomodate a variable
315 Q_UNUSED(variable);
315 Q_UNUSED(variable);
316 return true;
316 return true;
317 }
317 }
318
318
319 bool VisualizationZoneWidget::contains(const Variable &variable) const
319 bool VisualizationZoneWidget::contains(const Variable &variable) const
320 {
320 {
321 Q_UNUSED(variable);
321 Q_UNUSED(variable);
322 return false;
322 return false;
323 }
323 }
324
324
325 QString VisualizationZoneWidget::name() const
325 QString VisualizationZoneWidget::name() const
326 {
326 {
327 return ui->zoneNameLabel->text();
327 return ui->zoneNameLabel->text();
328 }
328 }
329
329
330 QMimeData *VisualizationZoneWidget::mimeData() const
330 QMimeData *VisualizationZoneWidget::mimeData() const
331 {
331 {
332 auto mimeData = new QMimeData;
332 auto mimeData = new QMimeData;
333 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
333 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
334
334
335 return mimeData;
335 return mimeData;
336 }
336 }
337
337
338 bool VisualizationZoneWidget::isDragAllowed() const
338 bool VisualizationZoneWidget::isDragAllowed() const
339 {
339 {
340 return true;
340 return true;
341 }
341 }
342
342
343 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
343 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
344 {
344 {
345 // Closes graphs in the zone
345 // Closes graphs in the zone
346 processGraphs(*ui->dragDropContainer->layout(),
346 processGraphs(*ui->dragDropContainer->layout(),
347 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
347 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
348
348
349 // Delete synchronization group from variable controller
349 // Delete synchronization group from variable controller
350 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
350 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
351 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
351 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
352
352
353 QWidget::closeEvent(event);
353 QWidget::closeEvent(event);
354 }
354 }
355
355
356 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
356 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
357 {
357 {
358 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
358 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
359 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
359 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
360 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
360 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
361 }
361 }
362
362
363 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
363 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
364 {
364 {
365 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
365 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
366 Q_ARG(std::shared_ptr<Variable>, variable),
366 Q_ARG(std::shared_ptr<Variable>, variable),
367 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
367 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
368 }
368 }
369
369
370 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
370 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
371 {
371 {
372 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
372 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
373 impl->dropGraph(index, this);
373 impl->dropGraph(index, this);
374 }
374 }
375 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
375 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
376 auto variables = sqpApp->variableController().variablesForMimeData(
376 auto variables = sqpApp->variableController().variablesForMimeData(
377 mimeData->data(MIME_TYPE_VARIABLE_LIST));
377 mimeData->data(MIME_TYPE_VARIABLE_LIST));
378 impl->dropVariables(variables, index, this);
378 impl->dropVariables(variables, index, this);
379 }
379 }
380 else {
380 else {
381 qCWarning(LOG_VisualizationZoneWidget())
381 qCWarning(LOG_VisualizationZoneWidget())
382 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
382 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
383 }
383 }
384 }
384 }
385
385
386 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
386 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
387 const QMimeData *mimeData)
387 const QMimeData *mimeData)
388 {
388 {
389 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
389 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
390 if (!graphWidget) {
390 if (!graphWidget) {
391 qCWarning(LOG_VisualizationZoneWidget())
391 qCWarning(LOG_VisualizationZoneWidget())
392 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
392 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
393 "drop aborted");
393 "drop aborted");
394 Q_ASSERT(false);
394 Q_ASSERT(false);
395 return;
395 return;
396 }
396 }
397
397
398 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
398 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
399 auto variables = sqpApp->variableController().variablesForMimeData(
399 auto variables = sqpApp->variableController().variablesForMimeData(
400 mimeData->data(MIME_TYPE_VARIABLE_LIST));
400 mimeData->data(MIME_TYPE_VARIABLE_LIST));
401 for (const auto &var : variables) {
401 for (const auto &var : variables) {
402 graphWidget->addVariable(var, graphWidget->graphRange());
402 graphWidget->addVariable(var, graphWidget->graphRange());
403 }
403 }
404 }
404 }
405 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
405 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
406 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
406 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
407 graphWidget->setGraphRange(range);
407 graphWidget->setGraphRange(range);
408 }
408 }
409 else {
409 else {
410 qCWarning(LOG_VisualizationZoneWidget())
410 qCWarning(LOG_VisualizationZoneWidget())
411 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
411 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
412 }
412 }
413 }
413 }
414
414
415 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
415 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
416 int index, VisualizationZoneWidget *zoneWidget)
416 int index, VisualizationZoneWidget *zoneWidget)
417 {
417 {
418 auto &helper = sqpApp->dragDropHelper();
418 auto &helper = sqpApp->dragDropHelper();
419
419
420 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
420 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
421 if (!graphWidget) {
421 if (!graphWidget) {
422 qCWarning(LOG_VisualizationZoneWidget())
422 qCWarning(LOG_VisualizationZoneWidget())
423 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
423 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
424 "found or invalid.");
424 "found or invalid.");
425 Q_ASSERT(false);
425 Q_ASSERT(false);
426 return;
426 return;
427 }
427 }
428
428
429 auto parentDragDropContainer
429 auto parentDragDropContainer
430 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
430 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
431 if (!parentDragDropContainer) {
431 if (!parentDragDropContainer) {
432 qCWarning(LOG_VisualizationZoneWidget())
432 qCWarning(LOG_VisualizationZoneWidget())
433 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
433 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
434 "the dropped graph is not found.");
434 "the dropped graph is not found.");
435 Q_ASSERT(false);
435 Q_ASSERT(false);
436 return;
436 return;
437 }
437 }
438
438
439 const auto &variables = graphWidget->variables();
439 const auto &variables = graphWidget->variables();
440
440
441 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
441 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
442 // The drop didn't occur in the same zone
442 // The drop didn't occur in the same zone
443
443
444 // Abort the requests for the variables (if any)
444 // Abort the requests for the variables (if any)
445 // Commented, because it's not sure if it's needed or not
445 // Commented, because it's not sure if it's needed or not
446 // for (const auto& var : variables)
446 // for (const auto& var : variables)
447 //{
447 //{
448 // sqpApp->variableController().onAbortProgressRequested(var);
448 // sqpApp->variableController().onAbortProgressRequested(var);
449 //}
449 //}
450
450
451 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
451 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
452 auto nbGraph = parentDragDropContainer->countDragWidget();
452 auto nbGraph = parentDragDropContainer->countDragWidget();
453 if (nbGraph == 1) {
453 if (nbGraph == 1) {
454 // This is the only graph in the previous zone, close the zone
454 // This is the only graph in the previous zone, close the zone
455 previousParentZoneWidget->close();
455 helper.delayedCloseWidget(previousParentZoneWidget);
456 }
456 }
457 else {
457 else {
458 // Close the graph
458 // Close the graph
459 graphWidget->close();
459 helper.delayedCloseWidget(graphWidget);
460 }
460 }
461
461
462 // Creates the new graph in the zone
462 // Creates the new graph in the zone
463 zoneWidget->createGraph(variables, index);
463 zoneWidget->createGraph(variables, index);
464 }
464 }
465 else {
465 else {
466 // The drop occurred in the same zone or the graph is empty
466 // The drop occurred in the same zone or the graph is empty
467 // Simple move of the graph, no variable operation associated
467 // Simple move of the graph, no variable operation associated
468 parentDragDropContainer->layout()->removeWidget(graphWidget);
468 parentDragDropContainer->layout()->removeWidget(graphWidget);
469
469
470 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
470 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
471 // The graph is empty and dropped in a different zone.
471 // The graph is empty and dropped in a different zone.
472 // Take the range of the first graph in the zone (if existing).
472 // Take the range of the first graph in the zone (if existing).
473 auto layout = zoneWidget->ui->dragDropContainer->layout();
473 auto layout = zoneWidget->ui->dragDropContainer->layout();
474 if (layout->count() > 0) {
474 if (layout->count() > 0) {
475 if (auto visualizationGraphWidget
475 if (auto visualizationGraphWidget
476 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
476 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
477 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
477 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
478 }
478 }
479 }
479 }
480 }
480 }
481
481
482 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
482 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
483 }
483 }
484 }
484 }
485
485
486 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
486 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
487 const QList<std::shared_ptr<Variable> > &variables, int index,
487 const QList<std::shared_ptr<Variable> > &variables, int index,
488 VisualizationZoneWidget *zoneWidget)
488 VisualizationZoneWidget *zoneWidget)
489 {
489 {
490 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
490 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
491 // compatible variable here
491 // compatible variable here
492 if (variables.count() > 1) {
492 if (variables.count() > 1) {
493 qCWarning(LOG_VisualizationZoneWidget())
493 qCWarning(LOG_VisualizationZoneWidget())
494 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
494 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
495 "aborted.");
495 "aborted.");
496 return;
496 return;
497 }
497 }
498
498
499 zoneWidget->createGraph(variables, index);
499 zoneWidget->createGraph(variables, index);
500 }
500 }
General Comments 1
Under Review
author

Auto status change to "Under Review"

You need to be logged in to leave comments. Login now