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