Isis 3 Programmer Reference
CubePlotCurve.cpp
1 
7 /* SPDX-License-Identifier: CC0-1.0 */
8 
9 #include "IsisDebug.h"
10 
11 #include "CubePlotCurve.h"
12 
13 #include <iostream>
14 
15 #include <QAction>
16 #include <QApplication>
17 #include <QBuffer>
18 #include <QByteArray>
19 #include <QClipboard>
20 #include <QDataStream>
21 #include <QDrag>
22 #include <QFileInfo>
23 #include <QEvent>
24 #include <QMenu>
25 #include <QMimeData>
26 #include <QMouseEvent>
27 #include <QPainter>
28 #include <QString>
29 
30 #include <qwt_legend.h>
31 
32 #include "Cube.h"
33 #include "CubeViewport.h"
34 #include "FileName.h"
35 #include "IException.h"
36 #include "IString.h"
37 #include "CubePlotCurveConfigureDialog.h"
38 
39 namespace Isis {
51  PlotCurve(xUnits, yUnits) {
52  m_legendItem = NULL;
53  m_renameAutomatically = true;
54  }
55 
56 
64  CubePlotCurve::CubePlotCurve(const QByteArray &parentAndChildData) :
65  PlotCurve(Unknown, Unknown) {
66  // Copy will get a new legend item widget when attached to the plot in PlotWindow
67  m_legendItem = NULL;
68 
69  QByteArray classData = fromByteArray(parentAndChildData);
70 
71  QString expectedHeader("PLOT_TOOL_CURVE_V1");
72  int headerKeySize = expectedHeader.toUtf8().size();
73 
74  if (classData.size() > headerKeySize) {
75  int dataPos = 0;
76  const char *rawClassData = classData.data();
77 
78  QString givenKey = QString::fromUtf8(classData.data() + dataPos,
79  headerKeySize);
80  dataPos += headerKeySize;
81  if (givenKey != expectedHeader) {
82  IString msg = "The given byte array does not contain the required "
83  "header";
84  throw IException(IException::Programmer, msg, _FILEINFO_);
85  }
86 
87  int numSourceCubes = *(((int *)(rawClassData + dataPos)));
88  dataPos += sizeof(int);
89 
90  for (int i = 0; i < numSourceCubes; i++) {
91  int sourceCubeSize = *(((int *)(rawClassData + dataPos)));
92  dataPos += sizeof(int);
93  QString data = QString::fromUtf8(classData.data() + dataPos,
94  sourceCubeSize);
95  m_sourceCube << data;
96  dataPos += sourceCubeSize;
97  }
98 
99  int pointListSize = *(((int *)(rawClassData + dataPos)));
100  dataPos += sizeof(int);
101 
102  for (int i = 0; i < pointListSize; i ++) {
103  int npts = *(((int *)(rawClassData + dataPos)));
104  dataPos += sizeof(int);
105 
106  QList<QPointF> points;
107  for (int pt = 0; pt < npts; pt++) {
108  double x = *((double *)(rawClassData + dataPos));
109  dataPos += sizeof(double);
110 
111  double y = *((double *)(rawClassData + dataPos));
112  dataPos += sizeof(double);
113 
114  points.append(QPointF(x, y));
115  }
116  m_pointList.append(points);
117  }
118 
119  ASSERT(dataPos == classData.size());
120  }
121  else {
122  IString msg = "The given byte array is not large enough to contain the "
123  "required header";
124  throw IException(IException::Programmer, msg, _FILEINFO_);
125  }
126  }
127 
128 
139  bool CubePlotCurve::eventFilter(QObject *o, QEvent *e) {
140  bool blockWidgetFromEvent = false;
141 
142  switch (e->type()) {
143  case QEvent::MouseButtonPress: {
144  mousePressEvent((QMouseEvent *)e);
145  blockWidgetFromEvent = true;
146  break;
147  }
148 
149  case QEvent::MouseButtonDblClick:
150  case QEvent::MouseButtonRelease:
151  blockWidgetFromEvent = true;
152  break;
153 
154 
155  default:
156  break;
157  }
158 
159  return blockWidgetFromEvent;
160  }
161 
162 
171  void CubePlotCurve::paint(CubeViewport *vp, QPainter *painter) {
172  if (m_sourceCube.contains(vp->cube()->fileName())) {
173  int i = m_sourceCube.indexOf(vp->cube()->fileName());
174  QPen customPen;
175  customPen.setColor(pen().color());
176  customPen.setWidth(pen().width());
177 
178  if (pen().style() != Qt::NoPen)
179  customPen.setStyle(pen().style());
180 
181  painter->setPen(customPen);
182  QList< QList <QPointF> > allPoints = sourceVertices();
183  QList<QPointF> points = allPoints.at(i);
184 
185  for (int p = 1; p <= points.size(); p++) {
186  int sample1;
187  int sample2;
188  int line1;
189  int line2;
190 
191  if (p != points.size()) {
192  vp->cubeToViewport(points[p - 1].x(), points[p - 1].y(), sample1, line1);
193  vp->cubeToViewport(points[p].x(), points[p].y(), sample2, line2);
194  }
195  else {
196  vp->cubeToViewport(points[p - 1].x(), points[p - 1].y(),
197  sample1, line1);
198  vp->cubeToViewport(points[0].x(), points[0].y(), sample2, line2);
199  }
200 
201  painter->drawLine(QPoint(sample1, line1), QPoint(sample2, line2));
202  }
203  }
204  }
205 
206 
214  return m_pointList;
215  }
216 
217 
225  return m_legendItem;
226  }
227 
228 
236  return m_sourceCube;
237  }
238 
239 
248  m_renameAutomatically = allowed;
249  }
250 
251 
259  m_sourceCube = other.m_sourceCube;
260  m_pointList = other.m_pointList;
261  emit needsRepaint();
262  }
263 
264 
265  void CubePlotCurve::clearSource() {
266 
267  if (m_originalName != "" && !m_sourceCube.empty() && m_renameAutomatically) {
268  setTitle(m_originalName);
269  }
270  else if (m_originalName == "") {
271  m_originalName = title().text();
272  }
273 
274  m_sourceCube.clear();
275  m_pointList.clear();
276 
277  }
278 
279 
280  void CubePlotCurve::addSource(CubeViewport *cvp, QList<QPoint> screenPoints,
281  int band) {
282 
283  if (cvp) {
284  m_sourceCube << cvp->cube()->fileName();
285 
286  if (m_renameAutomatically) {
287  setTitle(title().text() + " - " +
288  QFileInfo(m_sourceCube.at(m_sourceCube.size()-1)).baseName());
289 
290  if (band != -1) {
291  setTitle(title().text() + "+" + IString(band).ToQt());
292  }
293  }
294 
295  QList<QPointF> points;
296  foreach (QPoint screenpoint, screenPoints) {
297  double sample = 0.0;
298  double line = 0.0;
299 
300  cvp->viewportToCube(screenpoint.x(), screenpoint.y(), sample, line);
301 
302  points.append(QPointF(sample, line));
303  }
304  m_pointList.append(points);
305 
306  emit needsRepaint();
307  }
308 
309  }
310 
324  int band) {
325 
326  clearSource();
327  addSource(cvp, screenPoints, band);
328 // emit needsRepaint();
329  }
330 
331 
333  QList< QList<QPoint> > screenPoints,
334  QList<int> band) {
335  for (int i = 0; i < cvps.size(); i++) {
336  addSource(cvps.at(i), screenPoints.at(i), band.at(i));
337  }
338 // emit needsRepaint();
339  }
340 
341 
347  m_legendItem->installEventFilter(this);
348  // if (!m_legendItem) {
350  // m_legendItem->installEventFilter(this);
351  // connect(m_legendItem, SIGNAL(destroyed(QObject *)),
352  // this, SLOT(updateLegendItemWidget()));
353  //}
354  }
355 
356 
364  QMimeData *CubePlotCurve::createMimeData() const {
365  QMimeData *mimeData = new QMimeData;
366  mimeData->setData("application/isis3-plot-curve",
367  toByteArray());
368  return mimeData;
369  }
370 
371 
378  QByteArray CubePlotCurve::toByteArray() const {
379  QByteArray classData;
380 
381  classData.append(PlotCurve::toByteArray());
382 
383  QString header("PLOT_TOOL_CURVE_V1");
384  int size = header.size();
385  classData.append(header);
386 
387  size = m_sourceCube.size();
388  classData.append((char *)&size, sizeof(int));
389 
390  for (int i = 0; i < size; i++) {
391  int sourceCubeSize = m_sourceCube.at(i).toUtf8().size();
392  classData.append((char *)&sourceCubeSize, sizeof(int));
393  classData.append(m_sourceCube.at(i).toUtf8());
394  }
395 
396  size = m_pointList.size();
397  classData.append((char *)&size, sizeof(int));
398 
399  for (int i = 0; i < size; i ++) {
400  QList<QPointF> points = m_pointList[i];
401  int npts = points.size();
402  classData.append((char *)&npts, sizeof(int));
403 
404  for (int pt = 0; pt < npts; pt++) {
405  QPointF data = points[pt];
406  double x = data.x();
407  double y = data.y();
408 
409  classData.append((char *)&x, sizeof(double));
410  classData.append((char *)&y, sizeof(double));
411  }
412  }
413 
414  return classData;
415  }
416 
417 
425  void CubePlotCurve::mousePressEvent(QMouseEvent *event) {
426  bool deleteThisCurve = false;
427  if (event->button() == Qt::LeftButton) {
428  QDrag *drag = new QDrag(m_legendItem);
429 
430  // The icon for drag & drop sometimes gets in the way of the image,
431  // so let's move the image a little more to the right of the cursor
432  // than usual.
433  QPoint newHotSpot = drag->hotSpot();
434  newHotSpot.setX(newHotSpot.x() * 2);
435  drag->setHotSpot(newHotSpot);
436 
437  drag->setMimeData(createMimeData());
438  drag->setPixmap( m_legendItem->grab(m_legendItem->rect()) );
439 
440  Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction,
441  Qt::CopyAction);
442 
443  if (dropAction == Qt::MoveAction) {
444  deleteThisCurve = true;
445  }
446  }
447  else if (event->button() == Qt::RightButton) {
448  QMenu contextMenu;
449 
450  QAction *cutAct = new QAction(QIcon::fromTheme("edit-cut"), "Cut", this);
451  contextMenu.addAction(cutAct);
452  QAction *copyAct = new QAction(QIcon::fromTheme("edit-copy"), "Copy",
453  this);
454  // copyAct
455  contextMenu.addAction(copyAct);
456 
457  contextMenu.addSeparator();
458 
459  QAction *deleteAct = new QAction(QIcon::fromTheme("edit-delete"), "Delete",
460  this);
461  contextMenu.addAction(deleteAct);
462 
463  contextMenu.addSeparator();
464 
465  QString configureIconFile =
466  FileName("$ISISROOT/appdata/images/icons/plot_configure.png").expanded();
467  QAction *configureAct = new QAction(QPixmap(configureIconFile),
468  "Configure...", this);
469  contextMenu.addAction(configureAct);
470 
471  QAction *chosenAct = contextMenu.exec(
472  m_legendItem->mapToGlobal(event->pos()));
473 
474  if (chosenAct == cutAct || chosenAct == copyAct) {
475  QApplication::clipboard()->setMimeData(createMimeData());
476 
477  if (chosenAct == cutAct) {
478  deleteThisCurve = true;
479  }
480  }
481  // handle the configure action dialog
482  // opens the dialog with only the right-clicked CubePlotCurve
483  else if (chosenAct == configureAct) {
484  CubePlotCurveConfigureDialog configure(this);
485  configure.exec();
486  emit needsRepaint();
487  }
488  else if (chosenAct == deleteAct) {
489  deleteThisCurve = true;
490  }
491  }
492 
493  if (deleteThisCurve) {
494  setColor(QColor(255, 255, 255, 0));
495  emit needsRepaint();
496 
497  QwtPlot *plotToReplot = plot();
498 
499  connect(this, SIGNAL(removing()),
500  this, SLOT(deleteLater()), Qt::QueuedConnection);
501  connect(this, SIGNAL(removing()),
502  plotToReplot, SLOT(replot()), Qt::QueuedConnection);
503  emit removing();
504  }
505  }
506 }
QwtPlot
QWidget
Isis::Cube::fileName
virtual QString fileName() const
Returns the opened cube's filename.
Definition: Cube.cpp:1563
Isis::CubePlotCurve::m_pointList
QList< QList< QPointF > > m_pointList
List of vertices in sample,line coordinates from the rubber band.
Definition: CubePlotCurve.h:111
Isis::CubePlotCurve::m_legendItem
QPointer< QWidget > m_legendItem
This is the widget legend item associated with this curve.
Definition: CubePlotCurve.h:99
Isis::CubePlotCurve::updateLegendItemWidget
void updateLegendItemWidget(QWidget *legendItem)
This creates a legend item and overrides events from it.
Definition: CubePlotCurve.cpp:345
QList< QPointF >
Isis::CubePlotCurve::copySource
void copySource(const CubePlotCurve &other)
This copies the source data from another CubePlotCurve.
Definition: CubePlotCurve.cpp:258
Isis::CubePlotCurve::removing
void removing()
This is emitted just before the cube plot curve is deleted.
Isis::CubePlotCurve
This is a plot curve with information relating it to a particular cube or region of a cube.
Definition: CubePlotCurve.h:53
Isis::CubePlotCurveConfigureDialog
This should be an inner class for CubePlotCurve, but Qt doesn't support having a QObject as an inner ...
Definition: CubePlotCurveConfigureDialog.h:41
Isis::FileName
File name manipulation and expansion.
Definition: FileName.h:100
Isis::CubePlotCurve::toByteArray
QByteArray toByteArray() const
Serialize this plot curve into a binary byte array.
Definition: CubePlotCurve.cpp:378
QMenu
Isis::CubePlotCurve::legendItem
virtual QWidget * legendItem() const
This method is necessary for getting the correct (event filter altered) legend item.
Definition: CubePlotCurve.cpp:224
Isis::CubePlotCurve::paint
void paint(CubeViewport *vp, QPainter *painter)
Use information inside of the plot curve to paint onto a cube viewport.
Definition: CubePlotCurve.cpp:171
Isis::PlotCurve
Definition: PlotCurve.h:44
Isis::CubePlotCurve::m_renameAutomatically
bool m_renameAutomatically
This indicates if we are allowed to modify the title of this curve when the source (origin) data chan...
Definition: CubePlotCurve.h:108
Isis::CubePlotCurve::CubePlotCurve
CubePlotCurve(Units xUnits, Units yUnits)
This constructs a CubePlotCurve...
Definition: CubePlotCurve.cpp:50
Isis::CubePlotCurve::enableAutoRenaming
void enableAutoRenaming(bool)
This enables/disables the plot curve from changing it's title when the source data changes.
Definition: CubePlotCurve.cpp:247
Isis::PlotCurve::Units
Units
These are all the possible units for the x or y data in a plot curve.
Definition: PlotCurve.h:54
Isis::CubePlotCurve::setSource
void setSource(CubeViewport *cvp, QList< QPoint > screenPoints, int band=-1)
Tell this plot curve from where its data originated.
Definition: CubePlotCurve.cpp:323
QStringList
Isis::CubeViewport::cubeToViewport
void cubeToViewport(double sample, double line, int &x, int &y) const
Turns a cube into a viewport.
Definition: CubeViewport.cpp:852
Isis::FileName::expanded
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
Definition: FileName.cpp:196
Isis::CubePlotCurve::needsRepaint
void needsRepaint()
This is emitted when the curve is modified in such a way that it would paint a viewport differently.
Isis::CubePlotCurve::mousePressEvent
void mousePressEvent(QMouseEvent *e)
Handle various events on the legend item.
Definition: CubePlotCurve.cpp:425
Isis::CubePlotCurve::eventFilter
bool eventFilter(QObject *o, QEvent *e)
This will start the drag & drop operation for these curves.
Definition: CubePlotCurve.cpp:139
Isis::CubePlotCurve::sourceCube
QStringList sourceCube() const
This method returns the cube view port associated with the curve.
Definition: CubePlotCurve.cpp:235
Isis::CubePlotCurve::m_originalName
QString m_originalName
This is the curve's name before any automatic renaming happened.
Definition: CubePlotCurve.h:102
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::CubeViewport
Widget to display Isis cubes for qt apps.
Definition: CubeViewport.h:122
Isis::CubePlotCurve::sourceVertices
QList< QList< QPointF > > sourceVertices() const
This method returns a list of points which are the vertices of the selected area (by the rubberband) ...
Definition: CubePlotCurve.cpp:213
Isis::PlotCurve::setColor
void setColor(const QColor &color)
Set the color of this curve and it's markers.
Definition: PlotCurve.cpp:97
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
Isis::PlotCurve::fromByteArray
QByteArray fromByteArray(const QByteArray &classData)
Construct the plot curve given the past results of toByteArray(...).
Definition: PlotCurve.cpp:145
Isis::CubePlotCurve::m_sourceCube
QStringList m_sourceCube
The cube that the data is coming from.
Definition: CubePlotCurve.h:114
Isis::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
QObject
Isis::CubePlotCurve::createMimeData
QMimeData * createMimeData() const
This converts the plot curve into a binary, clipboard-compatible storage format (QMimeData).
Definition: CubePlotCurve.cpp:364
QAction
Isis::CubeViewport::cube
Cube * cube() const
Definition: CubeViewport.h:338
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::PlotCurve::color
QColor color() const
This method returns the color of the curve.
Definition: PlotCurve.cpp:56