Engauge Digitizer  2
GraphicsView.cpp
1 #include "DataKey.h"
2 #include "GraphicsItemType.h"
3 #include "GraphicsView.h"
4 #include "Logger.h"
5 #include "MainWindow.h"
6 #include "Point.h"
7 #include <QApplication>
8 #include <QDebug>
9 #include <QGraphicsPixmapItem>
10 #include <QGraphicsPolygonItem>
11 #include <QGraphicsScene>
12 #include <QMimeData>
13 #include <QMouseEvent>
14 #include <QScrollBar>
15 #include "QtToString.h"
16 
17 extern const QString AXIS_CURVE_NAME;
18 
19 GraphicsView::GraphicsView(QGraphicsScene *scene,
20  MainWindow &mainWindow) :
21  QGraphicsView (scene)
22 {
23  connect (this, SIGNAL (signalContextMenuEvent (QString)), &mainWindow, SLOT (slotContextMenuEvent (QString)));
24  connect (this, SIGNAL (signalDraggedImage (QImage)), &mainWindow, SLOT (slotFileImportDraggedImage (QImage)));
25  connect (this, SIGNAL (signalDraggedImageUrl (QUrl)), &mainWindow, SLOT (slotFileImportDraggedImageUrl (QUrl)));
26  connect (this, SIGNAL (signalKeyPress (Qt::Key, bool)), &mainWindow, SLOT (slotKeyPress (Qt::Key, bool)));
27  connect (this, SIGNAL (signalLeave ()), &mainWindow, SLOT (slotLeave ()));
28  connect (this, SIGNAL (signalMouseMove(QPointF)), &mainWindow, SLOT (slotMouseMove (QPointF)));
29  connect (this, SIGNAL (signalMousePress (QPointF)), &mainWindow, SLOT (slotMousePress (QPointF)));
30  connect (this, SIGNAL (signalMouseRelease (QPointF)), &mainWindow, SLOT (slotMouseRelease (QPointF)));
31 
32  setMouseTracking (true);
33  setAcceptDrops (true);
34  setEnabled (true);
35  setRenderHints(QPainter::Antialiasing);
36  setBackgroundBrush (QBrush (QColor (Qt::gray)));
37  verticalScrollBar()->setCursor (QCursor (Qt::ArrowCursor));
38  horizontalScrollBar()->setCursor (QCursor (Qt::ArrowCursor));
39 
40  // Skip setStatusTip here since that will overwrite much more important messages, and trigger gratuitous showing of status bar
41  setWhatsThis (tr ("Document\n\n"
42  "After an image file is imported, or an Engauge Document opened, an image appears in this area. "
43  "Points are added to the image.\n\n"
44  "If the image is a graph with two axes and one or more curves, then three axis points must be "
45  "created along those axes. Just put two axis points on one axis and a third axis point on the other "
46  "axis, as far apart as possible for higher accuracy. Then curve points can be added along the curves.\n\n"
47  "If the image is a map with a scale to define length, then two axis points must be "
48  "created at either end of the scale. Then curve points can be added."));
49 }
50 
51 GraphicsView::~GraphicsView()
52 {
53 }
54 
55 void GraphicsView::contextMenuEvent (QContextMenuEvent *event)
56 {
57  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::contextMenuEvent";
58 
59  QList<QGraphicsItem*> items = scene()->selectedItems ();
60 
61  if (items.count () == 1) {
62 
63  QGraphicsItem *item = items.first ();
64  QString pointIdentifier = item->data (DATA_KEY_IDENTIFIER).toString ();
65  GraphicsItemType type = (GraphicsItemType) item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt ();
66  QString curveName = Point::curveNameFromPointIdentifier (pointIdentifier);
67 
68  if ((type == GRAPHICS_ITEM_TYPE_POINT) &&
69  (curveName == AXIS_CURVE_NAME)) {
70 
71  // A single axis point is selected so edit it
72  emit signalContextMenuEvent (pointIdentifier);
73  event->accept ();
74 
75  return;
76  }
77  }
78 
79  QGraphicsView::contextMenuEvent (event);
80 }
81 
82 void GraphicsView::dragEnterEvent (QDragEnterEvent *event)
83 {
84  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::dragEnterEvent " << (event->mimeData ()->hasUrls () ? "urls" : "non-urls");
85 
86  if (event->mimeData ()->hasImage () ||
87  event->mimeData ()->hasUrls ()) {
88  event->acceptProposedAction();
89  }
90 }
91 
92 void GraphicsView::dragMoveEvent (QDragMoveEvent *event)
93 {
94  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::dragMoveEvent";
95 
96  if (event->mimeData ()->hasImage () ||
97  event->mimeData ()->hasUrls ()) {
98  event->acceptProposedAction();
99  }
100 }
101 
102 void GraphicsView::dropEvent (QDropEvent *event)
103 {
104  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::dropEvent";
105 
106  // This code is not specific to a digitizing state so it is implemented here
107 
108  // Urls from text/uri-list
109  QList<QUrl> urlList = event->mimeData ()->urls ();
110  QString urls;
111  QTextStream str (&urls);
112  QList<QUrl>::const_iterator itr;
113  for (itr = urlList.begin (); itr != urlList.end (); itr++) {
114  QUrl url = *itr;
115  str << " url=" << url.toString () << " ";
116  }
117 
118  if (event->mimeData ()->hasImage ()) {
119 
120  // This branch never seems to get executed, but will be kept in case it ever applies (since hasUrls branch is messier and less reliable)
121  QImage image = qvariant_cast<QImage> (event->mimeData ()->imageData ());
122  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::dropEvent image";
123  emit signalDraggedImage (image);
124 
125  } else if (event->mimeData ()->hasUrls ()) {
126 
127  // Sometimes images can be dragged in, but sometimes the url points to an html page that
128  // contains just the image, in which case importing will fail
129  QUrl url = urlList.at(0);
130  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::dropEvent url=" << url.toString ().toLatin1 ().data ();
131  emit signalDraggedImageUrl (url);
132  event->acceptProposedAction();
133 
134  } else {
135 
136  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsView::dropEvent dropped";
137  QGraphicsView::dropEvent (event);
138 
139  }
140 }
141 
142 bool GraphicsView::inBounds (const QPointF &posScreen)
143 {
144  QRectF boundingRect = scene()->sceneRect();
145 
146  return 0 <= posScreen.x () &&
147  0 <= posScreen.y () &&
148  posScreen.x () < boundingRect.width() &&
149  posScreen.y () < boundingRect.height();
150 }
151 
152 void GraphicsView::keyPressEvent (QKeyEvent *event)
153 {
154  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsView::keyPressEvent";
155 
156  // Intercept up/down/left/right if any items are selected
157  Qt::Key key = (Qt::Key) event->key();
158 
159  bool atLeastOneSelectedItem = (scene ()->selectedItems ().count () > 0);
160 
161  if (key == Qt::Key_Down ||
162  key == Qt::Key_Left ||
163  key == Qt::Key_Right ||
164  key == Qt::Key_Up) {
165 
166  emit signalKeyPress (key, atLeastOneSelectedItem);
167  event->accept();
168 
169  } else {
170 
171  QGraphicsView::keyPressEvent (event);
172 
173  }
174 }
175 
176 void GraphicsView::leaveEvent (QEvent *event)
177 {
178  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsView::leaveEvent";
179 
180  emit signalLeave ();
181 
182  QGraphicsView::leaveEvent (event);
183 }
184 
185 void GraphicsView::mouseMoveEvent (QMouseEvent *event)
186 {
187 // LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsView::mouseMoveEvent cursor="
188 // << QtCursorToString (cursor().shape()).toLatin1 ().data ();
189 
190  QPointF posScreen = mapToScene (event->pos ());
191 
192  if (!inBounds (posScreen)) {
193 
194  // Set to out-of-bounds value
195  posScreen = QPointF (-1.0, -1.0);
196  }
197 
198  emit signalMouseMove (posScreen);
199 
200  QGraphicsView::mouseMoveEvent (event);
201 }
202 
203 void GraphicsView::mousePressEvent (QMouseEvent *event)
204 {
205  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsView::mousePressEvent";
206 
207  QPointF posScreen = mapToScene (event->pos ());
208 
209  if (inBounds (posScreen)) {
210 
211  emit signalMousePress (posScreen);
212 
213  }
214 
215  QGraphicsView::mousePressEvent (event);
216 }
217 
218 void GraphicsView::mouseReleaseEvent (QMouseEvent *event)
219 {
220  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsView::mouseReleaseEvent";
221 
222  QPointF posScreen = mapToScene (event->pos ());
223 
224  // Skip if any of the following is true:
225  // 1) Out of bounds
226  // 2) Right click
227  int bitFlag = (event->buttons () & Qt::RightButton);
228  bool isRightClick = (bitFlag != 0);
229 
230  if (inBounds (posScreen) &&
231  !isRightClick) {
232 
233  emit signalMouseRelease (posScreen);
234 
235  }
236 
237  QGraphicsView::mouseReleaseEvent (event);
238 }
void signalMouseMove(QPointF)
Send mouse move to MainWindow for eventual display of cursor coordinates in StatusBar.
static QString curveNameFromPointIdentifier(const QString &pointIdentifier)
Parse the curve name from the specified point identifier. This does the opposite of uniqueIdentifierG...
Definition: Point.cpp:204
virtual void keyPressEvent(QKeyEvent *event)
Intercept key press events to handle left/right/up/down moving.
virtual void dragMoveEvent(QDragMoveEvent *event)
Intercept mouse move event to support drag-and-drop.
virtual void dropEvent(QDropEvent *event)
Intercept mouse drop event to support drag-and-drop. This initiates asynchronous loading of the dragg...
void contextMenuEvent(QContextMenuEvent *event)
Intercept right click to support point editing.
virtual void mouseMoveEvent(QMouseEvent *event)
Intercept mouse move events to populate the current cursor position in StatusBar. ...
GraphicsView(QGraphicsScene *scene, MainWindow &mainWindow)
Single constructor.
void signalMousePress(QPointF)
Send mouse press to MainWindow for creating one or more Points.
void signalKeyPress(Qt::Key, bool atLeastOneSelectedItem)
Send keypress to MainWindow for eventual processing by DigitizeStateAbstractBase subclasses.
virtual void mousePressEvent(QMouseEvent *event)
Intercept mouse press events to create one or more Points.
void signalDraggedImage(QImage)
Send dragged image to MainWindow for import. This typically comes from dragging a file...
virtual void leaveEvent(QEvent *event)
Intercept leave events to manage override cursor.
void signalMouseRelease(QPointF)
Send mouse release to MainWindow for moving Points.
virtual void dragEnterEvent(QDragEnterEvent *event)
Intercept mouse drag event to support drag-and-drop.
virtual void mouseReleaseEvent(QMouseEvent *event)
Intercept mouse release events to move one or more Points.
void signalDraggedImageUrl(QUrl)
Send dragged url to MainWindow for import. This typically comes from dragging an image from a browser...
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:60
void signalLeave()
Send leave to MainWindow for managing the override cursor.
void signalContextMenuEvent(QString pointIdentifier)
Send right click on axis point to MainWindow for editing.