Salome HOME
Update copyrights
[modules/paravis.git] / src / Plugins / TableReader / ParaViewPlugin / pqCustomXYChartDisplayPanel.cxx
1 // Copyright (C) 2010-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "pqCustomXYChartDisplayPanel.h"
21 #include "ui_CustomXYChartDisplayPanel.h"
22
23 #include "vtkEventQtSlotConnect.h"
24 #include "vtkSMChartRepresentationProxy.h"
25 #include "vtkSMPropertyHelper.h"
26 #include "vtkDataArray.h"
27 #include "vtkDataObject.h"
28 #include "vtkSMArraySelectionDomain.h"
29 #include "vtkSMIntVectorProperty.h"
30 #include "vtkSMProxy.h"
31 #include "vtkSmartPointer.h"
32 #include "vtkTable.h"
33 #include "vtkChart.h"
34 #include "vtkWeakPointer.h"
35
36 #include <QColorDialog>
37 #include <QHeaderView>
38 #include <QList>
39 #include <QPointer>
40 #include <QPixmap>
41 #include <QSortFilterProxyModel>
42 #include <QDebug>
43
44 #include "pqDataInformationModel.h"
45 #include "pqComboBoxDomain.h"
46 #include "pqPropertyLinks.h"
47 #include "pqSignalAdaptorCompositeTreeWidget.h"
48 #include "pqSignalAdaptors.h"
49 #include "pqSMAdaptor.h"
50 #include "pqXYChartView.h"
51 #include "pqDataRepresentation.h"
52 #include "pqCustomPlotSettingsModel.h"
53
54 #include <assert.h>
55
56 //-----------------------------------------------------------------------------
57 class pqCustomXYChartDisplayPanel::pqInternal : public Ui::CustomXYChartDisplayPanel
58 {
59 public:
60   pqInternal()
61 {
62     this->SettingsModel = 0;
63     this->XAxisArrayDomain = 0;
64     this->XAxisArrayAdaptor = 0;
65
66     this->VTKConnect = vtkSmartPointer<vtkEventQtSlotConnect>::New();
67 }
68
69   ~pqInternal()
70   {
71     delete this->SettingsModel;
72     delete this->XAxisArrayDomain;
73     delete this->XAxisArrayAdaptor;
74   }
75
76   vtkWeakPointer<vtkSMChartRepresentationProxy> ChartRepresentation;
77   pqCustomPlotSettingsModel* SettingsModel;
78   pqComboBoxDomain* XAxisArrayDomain;
79   pqSignalAdaptorComboBox* XAxisArrayAdaptor;
80   pqPropertyLinks Links;
81
82   vtkSmartPointer<vtkEventQtSlotConnect> VTKConnect;
83
84   bool InChange;
85 };
86
87 //-----------------------------------------------------------------------------
88 pqCustomXYChartDisplayPanel::pqCustomXYChartDisplayPanel(
89     pqRepresentation* display,QWidget* p)
90 : pqDisplayPanel(display, p)
91 {
92   this->Internal = new pqCustomXYChartDisplayPanel::pqInternal();
93   this->Internal->setupUi(this);
94
95   this->Internal->SettingsModel = new pqCustomPlotSettingsModel(this);
96   this->Internal->SeriesList->setModel(this->Internal->SettingsModel);
97
98   this->Internal->XAxisArrayAdaptor = new pqSignalAdaptorComboBox(
99       this->Internal->XAxisArray);
100
101   QObject::connect(
102       this->Internal->SeriesList, SIGNAL(activated(const QModelIndex &)),
103       this, SLOT(activateItem(const QModelIndex &)));
104   QItemSelectionModel *model = this->Internal->SeriesList->selectionModel();
105   QObject::connect(model,
106       SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
107       this, SLOT(updateOptionsWidgets()));
108   QObject::connect(model,
109       SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
110       this, SLOT(updateOptionsWidgets()));
111   QObject::connect(this->Internal->SettingsModel, SIGNAL(modelReset()),
112       this, SLOT(updateOptionsWidgets()));
113   QObject::connect(this->Internal->SettingsModel, SIGNAL(redrawChart()),
114       this, SLOT(updateAllViews()));
115   QObject::connect(this->Internal->XAxisArray, SIGNAL(currentIndexChanged(int)),
116       this, SLOT(updateAllViews()));
117
118   QObject::connect(this->Internal->UseArrayIndex, SIGNAL(toggled(bool)),
119       this, SLOT(useArrayIndexToggled(bool)));
120   QObject::connect(this->Internal->UseDataArray, SIGNAL(toggled(bool)),
121       this, SLOT(useDataArrayToggled(bool)));
122
123   QObject::connect(
124       this->Internal->ColorButton, SIGNAL(chosenColorChanged(const QColor &)),
125       this, SLOT(setCurrentSeriesColor(const QColor &)));
126   QObject::connect(this->Internal->Thickness, SIGNAL(valueChanged(int)),
127       this, SLOT(setCurrentSeriesThickness(int)));
128   QObject::connect(this->Internal->StyleList, SIGNAL(currentIndexChanged(int)),
129       this, SLOT(setCurrentSeriesStyle(int)));
130   QObject::connect(this->Internal->AxisList, SIGNAL(currentIndexChanged(int)),
131       this, SLOT(setCurrentSeriesAxes(int)));
132   QObject::connect(this->Internal->MarkerStyleList, SIGNAL(currentIndexChanged(int)),
133       this, SLOT(setCurrentSeriesMarkerStyle(int)));
134
135   QObject::connect(
136       this->Internal->AutoSelect, SIGNAL(toggled(bool)),
137       this, SLOT(autoSelectToggled(bool)));
138
139   QObject::connect(
140       this->Internal->IgnoreUnits, SIGNAL(toggled(bool)),
141       this, SLOT(ignoreUnitsToggled(bool)));
142
143   QObject::connect(
144       this->Internal->GenerateAxesTitles, SIGNAL(toggled(bool)),
145       this, SLOT(updateViewOptions()));
146   QObject::connect(this->Internal->SettingsModel, SIGNAL(redrawChart()),
147       this, SLOT(updateViewOptions()));
148
149   resetUnitsControls();
150
151   this->setDisplay(display);
152
153   QObject::connect(&this->Internal->Links, SIGNAL(qtWidgetChanged()),
154       this, SLOT(reloadSeries()), Qt::QueuedConnection);
155   QObject::connect(&this->Internal->Links, SIGNAL(qtWidgetChanged()),
156       this->Internal->SettingsModel, SLOT(reload()));
157 }
158
159 //-----------------------------------------------------------------------------
160 pqCustomXYChartDisplayPanel::~pqCustomXYChartDisplayPanel()
161 {
162   delete this->Internal;
163 }
164
165 //-----------------------------------------------------------------------------
166 void pqCustomXYChartDisplayPanel::reloadSeries()
167 {
168   updateViewOptions();
169
170   this->updateAllViews();
171   this->updateOptionsWidgets();
172 }
173
174 //-----------------------------------------------------------------------------
175 void pqCustomXYChartDisplayPanel::setDisplay(pqRepresentation* disp)
176 {
177   this->setEnabled(false);
178
179   vtkSMChartRepresentationProxy* proxy =
180       vtkSMChartRepresentationProxy::SafeDownCast(disp->getProxy());
181   this->Internal->ChartRepresentation = proxy;
182   if (!this->Internal->ChartRepresentation)
183   {
184     qWarning() << "pqCustomXYChartDisplayPanel given a representation proxy "
185         "that is not an XYChartRepresentation. Cannot edit.";
186     return;
187   }
188
189   // this is essential to ensure that when you undo-redo, the representation is
190   // indeed update-to-date, thus ensuring correct domains etc.
191   proxy->UpdatePipeline();
192
193   // The model for the plot settings
194   this->Internal->SettingsModel->setRepresentation(
195       qobject_cast<pqDataRepresentation*>(disp));
196
197   // Connect to the new properties.pqComboBoxDomain will ensure that
198   // when ever the domain changes the widget is updated as well.
199   this->Internal->XAxisArrayDomain = new pqComboBoxDomain(
200       this->Internal->XAxisArray, proxy->GetProperty("XArrayName"));
201   this->Internal->Links.addPropertyLink(this->Internal->XAxisArrayAdaptor,
202       "currentText", SIGNAL(currentTextChanged(const QString&)),
203       proxy, proxy->GetProperty("XArrayName"));
204
205   // Link to set whether the index is used for the x axis
206   this->Internal->Links.addPropertyLink(
207       this->Internal->UseArrayIndex, "checked",
208       SIGNAL(toggled(bool)),
209       proxy, proxy->GetProperty("UseIndexForXAxis"));
210
211   // Proxy changed
212   this->Internal->VTKConnect->Connect(proxy->GetProperty("SeriesNamesInfo"),
213       vtkCommand::PropertyModifiedEvent, this, SLOT(resetUnitsControls()));
214
215   this->changeDialog(disp);
216
217   this->setEnabled(true);
218
219   this->reloadSeries();
220 }
221
222 //-----------------------------------------------------------------------------
223 void pqCustomXYChartDisplayPanel::changeDialog(pqRepresentation* disp)
224 {
225   vtkSMChartRepresentationProxy* proxy =
226       vtkSMChartRepresentationProxy::SafeDownCast(disp->getProxy());
227   bool visible = true;
228   if (QString("Bar") == vtkSMPropertyHelper(proxy,"ChartType").GetAsString())
229   {
230     visible = false;
231   }
232
233   this->Internal->Thickness->setVisible(visible);
234   this->Internal->ThicknessLabel->setVisible(visible);
235   this->Internal->StyleList->setVisible(visible);
236   this->Internal->StyleListLabel->setVisible(visible);
237   this->Internal->MarkerStyleList->setVisible(visible);
238   this->Internal->MarkerStyleListLabel->setVisible(visible);
239   this->Internal->AxisList->setVisible(false);
240   this->Internal->AxisListLabel->setVisible(false);
241 }
242
243 //-----------------------------------------------------------------------------
244 void pqCustomXYChartDisplayPanel::activateItem(const QModelIndex &index)
245 {
246   if(!this->Internal->ChartRepresentation
247       || !index.isValid() || index.column() != 1)
248   {
249     // We are interested in clicks on the color swab alone.
250     return;
251   }
252
253   // Get current color
254   QColor color = this->Internal->SettingsModel->getSeriesColor(index.row());
255
256   // Show color selector dialog to get a new color
257   color = QColorDialog::getColor(color, this);
258   if (color.isValid())
259   {
260     // Set the new color
261     this->Internal->SettingsModel->setSeriesColor(index.row(), color);
262     this->Internal->ColorButton->blockSignals(true);
263     this->Internal->ColorButton->setChosenColor(color);
264     this->Internal->ColorButton->blockSignals(false);
265     this->updateAllViews();
266   }
267 }
268
269 //-----------------------------------------------------------------------------
270 void pqCustomXYChartDisplayPanel::updateOptionsWidgets()
271 {
272   QItemSelectionModel *model = this->Internal->SeriesList->selectionModel();
273   if(model)
274   {
275     // Show the options for the current item.
276     QModelIndex current = model->currentIndex();
277     QModelIndexList indexes = model->selectedIndexes();
278     if((!current.isValid() || !model->isSelected(current)) &&
279         indexes.size() > 0)
280     {
281       current = indexes.last();
282     }
283
284     this->Internal->ColorButton->blockSignals(true);
285     this->Internal->Thickness->blockSignals(true);
286     this->Internal->StyleList->blockSignals(true);
287     this->Internal->MarkerStyleList->blockSignals(true);
288     this->Internal->AxisList->blockSignals(true);
289     if (current.isValid())
290     {
291       int seriesIndex = current.row();
292       QColor color = this->Internal->SettingsModel->getSeriesColor(seriesIndex);
293       this->Internal->ColorButton->setChosenColor(color);
294       this->Internal->Thickness->setValue(
295           this->Internal->SettingsModel->getSeriesThickness(seriesIndex));
296       this->Internal->StyleList->setCurrentIndex(
297           this->Internal->SettingsModel->getSeriesStyle(seriesIndex));
298       this->Internal->MarkerStyleList->setCurrentIndex(
299           this->Internal->SettingsModel->getSeriesMarkerStyle(seriesIndex));
300       this->Internal->AxisList->setCurrentIndex(
301           this->Internal->SettingsModel->getSeriesAxisCorner(seriesIndex));
302     }
303     else
304     {
305       this->Internal->ColorButton->setChosenColor(Qt::white);
306       this->Internal->Thickness->setValue(1);
307       this->Internal->StyleList->setCurrentIndex(0);
308       this->Internal->MarkerStyleList->setCurrentIndex(0);
309       this->Internal->AxisList->setCurrentIndex(0);
310     }
311
312     this->Internal->ColorButton->blockSignals(false);
313     this->Internal->Thickness->blockSignals(false);
314     this->Internal->StyleList->blockSignals(false);
315     this->Internal->MarkerStyleList->blockSignals(false);
316     this->Internal->AxisList->blockSignals(false);
317
318     // Disable the widgets if nothing is selected or current.
319     bool hasItems = indexes.size() > 0;
320     this->Internal->ColorButton->setEnabled(hasItems);
321     this->Internal->Thickness->setEnabled(hasItems);
322     this->Internal->StyleList->setEnabled(hasItems);
323     this->Internal->MarkerStyleList->setEnabled(hasItems);
324     this->Internal->AxisList->setEnabled(hasItems);
325   }
326 }
327
328 //-----------------------------------------------------------------------------
329 void pqCustomXYChartDisplayPanel::setCurrentSeriesColor(const QColor &color)
330 {
331   QItemSelectionModel *model = this->Internal->SeriesList->selectionModel();
332   if(model)
333   {
334     this->Internal->InChange = true;
335     QModelIndexList indexes = model->selectedIndexes();
336     QModelIndexList::Iterator iter = indexes.begin();
337     for( ; iter != indexes.end(); ++iter)
338     {
339       this->Internal->SettingsModel->setSeriesColor(iter->row(), color);
340     }
341     this->Internal->InChange = false;
342   }
343 }
344
345 //-----------------------------------------------------------------------------
346 void pqCustomXYChartDisplayPanel::setCurrentSeriesThickness(int thickness)
347 {
348   QItemSelectionModel *model = this->Internal->SeriesList->selectionModel();
349   if (model)
350   {
351     this->Internal->InChange = true;
352     QModelIndexList indexes = model->selectedIndexes();
353     QModelIndexList::Iterator iter = indexes.begin();
354     for( ; iter != indexes.end(); ++iter)
355     {
356       this->Internal->SettingsModel->setSeriesThickness(iter->row(), thickness);
357     }
358     this->Internal->InChange = false;
359   }
360 }
361
362 //-----------------------------------------------------------------------------
363 void pqCustomXYChartDisplayPanel::setCurrentSeriesStyle(int style)
364 {
365   QItemSelectionModel *model = this->Internal->SeriesList->selectionModel();
366   if (model)
367   {
368     this->Internal->InChange = true;
369     QModelIndexList indexes = model->selectedIndexes();
370     QModelIndexList::Iterator iter = indexes.begin();
371     for( ; iter != indexes.end(); ++iter)
372     {
373       this->Internal->SettingsModel->setSeriesStyle(iter->row(), style);
374     }
375     this->Internal->InChange = false;
376   }
377 }
378
379 //-----------------------------------------------------------------------------
380 void pqCustomXYChartDisplayPanel::setCurrentSeriesMarkerStyle(int style)
381 {
382   QItemSelectionModel *model = this->Internal->SeriesList->selectionModel();
383   if (model)
384   {
385     this->Internal->InChange = true;
386     QModelIndexList indexes = model->selectedIndexes();
387     QModelIndexList::Iterator iter = indexes.begin();
388     for( ; iter != indexes.end(); ++iter)
389     {
390       this->Internal->SettingsModel->setSeriesMarkerStyle(iter->row(), style);
391     }
392     this->Internal->InChange = false;
393   }
394 }
395
396 //-----------------------------------------------------------------------------
397 void pqCustomXYChartDisplayPanel::setCurrentSeriesAxes(int)
398 {
399
400 }
401
402 //-----------------------------------------------------------------------------
403 Qt::CheckState pqCustomXYChartDisplayPanel::getEnabledState() const
404 {
405   Qt::CheckState enabledState = Qt::Unchecked;
406
407   return enabledState;
408 }
409
410 //-----------------------------------------------------------------------------
411 void pqCustomXYChartDisplayPanel::useArrayIndexToggled(bool toggle)
412 {
413   this->Internal->UseDataArray->setChecked(!toggle);
414 }
415
416 //-----------------------------------------------------------------------------
417 void pqCustomXYChartDisplayPanel::useDataArrayToggled(bool toggle)
418 {
419   this->Internal->UseArrayIndex->setChecked(!toggle);
420   this->updateAllViews();
421 }
422
423 //-----------------------------------------------------------------------------
424 void pqCustomXYChartDisplayPanel::autoSelectToggled(bool checked)
425 {
426   this->Internal->SettingsModel->SetAutoSelectModeOn(checked);
427 }
428
429 //-----------------------------------------------------------------------------
430 void pqCustomXYChartDisplayPanel::ignoreUnitsToggled(bool checked)
431 {
432   this->Internal->AutoSelect->setEnabled(!checked);
433   this->Internal->SettingsModel->SetIgnoreUnitsModeOn(checked);
434   this->Internal->SettingsModel->SetAutoSelectModeOn(!checked && 
435       this->Internal->AutoSelect->isChecked());
436 }
437
438 //-----------------------------------------------------------------------------
439 void pqCustomXYChartDisplayPanel::resetUnitsControls()
440 {
441   this->Internal->IgnoreUnits->setCheckState(Qt::Checked);
442   this->Internal->AutoSelect->setCheckState(Qt::Unchecked);
443 }
444
445 //-----------------------------------------------------------------------------
446 void pqCustomXYChartDisplayPanel::updateViewOptions()
447 {
448   pqRepresentation* disp = this->getRepresentation();
449   if (!disp || !this->Internal->ChartRepresentation)
450   {
451     return;
452   }
453
454   pqXYChartView* view = qobject_cast<pqXYChartView*>(disp->getView());
455   if (view && view->getProxy())
456   {
457     vtkSMProxy* proxy = view->getProxy();
458
459     QList<QVariant> values =
460         pqSMAdaptor::getMultipleElementProperty(proxy->GetProperty("AxisTitle"));
461     if (values.size() < 2)
462     {
463       return;
464     }
465
466     if (!this->Internal->GenerateAxesTitles->isChecked())
467     {
468       values.insert(0, QVariant(""));
469       values.insert(1, QVariant(""));
470     }
471     else
472     {
473       // Set X axis title
474       int useIndexForXAxis = vtkSMPropertyHelper(
475           this->Internal->ChartRepresentation, "UseIndexForXAxis").GetAsInt();
476
477       QString xTitle("");
478       if (!useIndexForXAxis)
479       {
480         xTitle = vtkSMPropertyHelper(this->Internal->ChartRepresentation, "XArrayName").GetAsString();
481       }
482
483       // Set Y axis title
484       int nbRows = this->Internal->SettingsModel->rowCount(QModelIndex());
485       int nbEnabled = 0;
486       int row = 0;
487       for (int i = 0; i < nbRows && nbEnabled < 2; i++)
488       {
489         if (this->Internal->SettingsModel->getSeriesEnabled(i))
490         {
491           nbEnabled++;
492           row = i;
493         }
494       }
495
496       QString yTitle("");
497       if (nbEnabled == 1)
498       {
499         yTitle = this->Internal->SettingsModel->getSeriesName(row);
500       }
501       values.insert(0, QVariant(yTitle));
502       values.insert(1, QVariant(xTitle));
503     }
504
505     pqSMAdaptor::setMultipleElementProperty(proxy->GetProperty("AxisTitle"), values);
506
507     view->getProxy()->UpdateVTKObjects();
508     view->render();
509   }
510 }