QElectroTech  0.70
elementview.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2006-2019 The QElectroTech Team
3  This file is part of QElectroTech.
4 
5  QElectroTech is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 2 of the License, or
8  (at your option) any later version.
9 
10  QElectroTech is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "elementview.h"
19 #include "qetelementeditor.h"
20 #include "editorcommands.h"
21 #include "qetapp.h"
27 ElementView::ElementView(ElementScene *scene, QWidget *parent) :
28  QGraphicsView(scene, parent),
29  m_scene(scene),
30  offset_paste_count_(0)
31 {
32  grabGesture(Qt::PinchGesture);
33  setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
34  setInteractive(true);
35  setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
36  setResizeAnchor(QGraphicsView::AnchorUnderMouse);
37  setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
38  zoomReset();
39  connect(m_scene, SIGNAL(pasteAreaDefined(const QRectF &)), this, SLOT(pasteAreaDefined(const QRectF &)));
40  connect(m_scene, SIGNAL(needZoomFit()), this, SLOT(zoomFit()));
41 }
42 
45 }
46 
49  return(m_scene);
50 }
51 
56  // recupere la taille du widget viewport
57  QSize viewport_size = viewport() -> size();
58 
59  // recupere la transformation viewport -> scene
60  QTransform view_to_scene = viewportTransform().inverted();
61 
62  // mappe le coin superieur gauche et le coin inferieur droit de la viewport sur la scene
63  QPointF scene_left_top = view_to_scene.map(QPointF(0.0, 0.0));
64  QPointF scene_right_bottom = view_to_scene.map(QPointF(viewport_size.width(), viewport_size.height()));
65 
66  // en deduit le rectangle visualise par la scene
67  return(QRectF(scene_left_top, scene_right_bottom));
68 }
69 
75  QGraphicsView::setScene(s);
76  m_scene = s;
77 }
78 
83  setDragMode(ScrollHandDrag);
84  setInteractive(false);
85  emit(modeChanged());
86 }
87 
92  setDragMode(RubberBandDrag);
93  setInteractive(true);
94  emit(modeChanged());
95 }
96 
101  adjustSceneRect();
102  scale(4.0/3.0, 4.0/3.0);
103 }
104 
109  adjustSceneRect();
110  scale(0.75, 0.75);
111 }
112 
117  scale(1.02, 1.02);
118 }
119 
124  scale(0.98, 0.98);
125 }
126 
133  resetSceneRect();
134  fitInView(sceneRect(), Qt::KeepAspectRatio);
135 }
136 
141  resetSceneRect();
142  resetMatrix();
143  scale(4.0, 4.0);
144 }
145 
152  QRectF esgr = m_scene -> elementSceneGeometricRect();
153  QRectF vpbr = mapToScene(this -> viewport()->rect()).boundingRect();
154  QRectF new_scene_rect = vpbr.adjusted(-vpbr.width()/3, -vpbr.height()/3, vpbr.width()/3, vpbr.height()/3);
155  setSceneRect(new_scene_rect.united(esgr));
156 }
157 
164  setSceneRect(m_scene -> elementSceneGeometricRect());
165 }
166 
172  // delegue cette action a la scene
173  m_scene -> cut();
174  offset_paste_count_ = -1;
175 }
176 
182  // delegue cette action a la scene
183  m_scene -> copy();
185 }
186 
198  QString clipboard_text = QApplication::clipboard() -> text();
199  if (clipboard_text.isEmpty()) return;
200 
201  QDomDocument document_xml;
202  if (!document_xml.setContent(clipboard_text)) return;
203 
204  if (m_scene -> wasCopiedFromThisElement(clipboard_text)) {
205  // copier/coller avec decalage
206  pasteWithOffset(document_xml);
207  } else {
208  // copier/coller par choix de la zone de collage
209  QRectF pasted_content_bounding_rect = m_scene -> boundingRectFromXml(document_xml);
210  if (pasted_content_bounding_rect.isEmpty()) return;
211 
212  to_paste_in_area_ = clipboard_text;
213  getPasteArea(pasted_content_bounding_rect);
214  }
215 }
216 
222  QString clipboard_text = QApplication::clipboard() -> text();
223  if (clipboard_text.isEmpty()) return;
224 
225  QDomDocument document_xml;
226  if (!document_xml.setContent(clipboard_text)) return;
227 
228  QRectF pasted_content_bounding_rect = m_scene -> boundingRectFromXml(document_xml);
229  if (pasted_content_bounding_rect.isEmpty()) return;
230 
231  // copier/coller par choix de la zone de collage
232  to_paste_in_area_ = clipboard_text;
233  getPasteArea(pasted_content_bounding_rect);
234 }
235 
243 ElementContent ElementView::paste(const QPointF &position) {
244  QString clipboard_text = QApplication::clipboard() -> text();
245  if (clipboard_text.isEmpty()) return(ElementContent());
246 
247  QDomDocument document_xml;
248  if (!document_xml.setContent(clipboard_text)) return(ElementContent());
249 
250  // objet pour recuperer le contenu ajoute au schema par le coller
251  return(paste(document_xml, position));
252 }
253 
257 void ElementView::getPasteArea(const QRectF &to_paste) {
258  // on copie le rectangle fourni - on s'interesse a ses dimensions, pas a sa position
259  QRectF used_rect(to_paste);
260 
261  // on lui attribue pour centre l'origine du repere
262  if (underMouse()) {
263  used_rect.moveCenter(mapToScene(mapFromGlobal(QCursor::pos())));
264  } else {
265  used_rect.moveCenter(QPointF(0.0, 0.0));
266  }
267  m_scene -> getPasteArea(used_rect);
268 }
269 
274 ElementContent ElementView::pasteAreaDefined(const QRectF &target_rect) {
275  if (to_paste_in_area_.isEmpty()) return(ElementContent());
276 
277  QDomDocument xml_document;
278  if (!xml_document.setContent(to_paste_in_area_)) {
279  to_paste_in_area_.clear();
280  return(ElementContent());
281  } else {
282  return(paste(xml_document, target_rect.topLeft()));
283  }
284 }
285 
291 ElementContent ElementView::paste(const QDomDocument &xml_document, const QPointF &pos) {
292  // objet pour recuperer le contenu ajoute au schema par le coller
293  ElementContent content_pasted;
294  m_scene -> fromXml(xml_document, pos, false, &content_pasted);
295 
296  // si quelque chose a effectivement ete ajoute au schema, on cree un objet d'annulation
297  if (content_pasted.count()) {
298  m_scene -> clearSelection();
299  PastePartsCommand *undo_object = new PastePartsCommand(this, content_pasted);
300  m_scene -> undoStack().push(undo_object);
301  }
302  return(content_pasted);
303 }
304 
309 ElementContent ElementView::pasteWithOffset(const QDomDocument &xml_document) {
310  // objet pour recuperer le contenu ajoute au schema par le coller
311  ElementContent content_pasted;
312 
313  // rectangle source
314  QRectF pasted_content_bounding_rect = m_scene -> boundingRectFromXml(xml_document);
315  if (pasted_content_bounding_rect.isEmpty()) return(content_pasted);
316 
317  // copier/coller avec decalage
318  QRectF final_pasted_content_bounding_rect;
320  if (!offset_paste_count_) {
321  // the pasted content was cut
322  start_top_left_corner_ = pasted_content_bounding_rect.topLeft();
323  final_pasted_content_bounding_rect = pasted_content_bounding_rect;
324  }
325  else {
326  // the pasted content was copied
327  if (offset_paste_count_ == 1) {
328  start_top_left_corner_ = pasted_content_bounding_rect.topLeft();
329  } else {
330  pasted_content_bounding_rect.moveTopLeft(start_top_left_corner_);
331  }
332 
333  // on applique le decalage qui convient
334  final_pasted_content_bounding_rect = applyMovement(
335  pasted_content_bounding_rect,
337  );
338  }
339  QPointF old_start_top_left_corner = start_top_left_corner_;
340  start_top_left_corner_ = final_pasted_content_bounding_rect.topLeft();
341  m_scene -> fromXml(xml_document, start_top_left_corner_, false, &content_pasted);
342 
343  // si quelque chose a effectivement ete ajoute au schema, on cree un objet d'annulation
344  if (content_pasted.count()) {
345  m_scene -> clearSelection();
346  PastePartsCommand *undo_object = new PastePartsCommand(this, content_pasted);
347  undo_object -> setOffset(offset_paste_count_ - 1, old_start_top_left_corner, offset_paste_count_, start_top_left_corner_);
348  m_scene -> undoStack().push(undo_object);
349  }
350  return(content_pasted);
351 }
352 
358 void ElementView::mousePressEvent(QMouseEvent *e) {
359  if (e->buttons() == Qt::MidButton)
360  {
361  setCursor( (Qt::ClosedHandCursor));
362  reference_view_ = e->pos();
363  }
364  else
365  QGraphicsView::mousePressEvent(e);
366 }
367 
372 void ElementView::mouseMoveEvent(QMouseEvent *e) {
373  if (e->buttons() == Qt::MidButton)
374  {
375  QScrollBar *h = horizontalScrollBar();
376  QScrollBar *v = verticalScrollBar();
377  QPointF pos = reference_view_ - e -> pos();
378  reference_view_ = e -> pos();
379  h -> setValue(h -> value() + pos.x());
380  v -> setValue(v -> value() + pos.y());
381  }
382  else
383  QGraphicsView::mouseMoveEvent(e);
384 }
385 
390 void ElementView::mouseReleaseEvent(QMouseEvent *e) {
391  if (e -> button() == Qt::MidButton) {
392  setCursor(Qt::ArrowCursor);
393  adjustSceneRect();
394  return;
395  }
396  QGraphicsView::mouseReleaseEvent(e);
397 }
398 
404 {
405  QSettings settings;
406  return(settings.value("diagramview/gestures", false).toBool());
407 }
408 
409 
414 void ElementView::wheelEvent(QWheelEvent *e) {
415  //Zoom and scrolling
416  if ( gestures() ) {
417  if (e -> modifiers() & Qt::ControlModifier)
418  e -> delta() > 0 ? zoomInSlowly() : zoomOutSlowly();
419  else
420  QGraphicsView::wheelEvent(e);
421  } else {
422  e -> delta() > 0 ? zoomIn(): zoomOut();
423  }
424 }
425 
430 bool ElementView::event(QEvent *e) {
431  // By default touch events are converted to mouse events. So
432  // after this event we will get a mouse event also but we want
433  // to handle touch events as gestures only. So we need this safeguard
434  // to block mouse events that are actually generated from touch.
435  if (e->type() == QEvent::Gesture)
436  return gestureEvent(static_cast<QGestureEvent *>(e));
437 
438  return(QGraphicsView::event(e));
439 }
440 
447 bool ElementView::gestureEvent(QGestureEvent *event){
448  if (QGesture *gesture = event->gesture(Qt::PinchGesture)) {
449  QPinchGesture *pinch = static_cast<QPinchGesture *>(gesture);
450  if (pinch->changeFlags() & QPinchGesture::ScaleFactorChanged){
451  qreal value = gesture->property("scaleFactor").toReal();
452  if (value > 1){
453  zoomInSlowly();
454  }else{
455  zoomOutSlowly();
456  }
457  }
458  }
459  return true;
460 }
461 
462 
468 void ElementView::drawBackground(QPainter *p, const QRectF &r) {
469  p -> save();
470 
471  // desactive tout antialiasing, sauf pour le texte
472  p -> setRenderHint(QPainter::Antialiasing, false);
473  p -> setRenderHint(QPainter::TextAntialiasing, true);
474  p -> setRenderHint(QPainter::SmoothPixmapTransform, false);
475 
476  // dessine un fond blanc
477  p -> setPen(Qt::NoPen);
478  p -> setBrush(Qt::white);
479  p -> drawRect(r);
480 
481  // determine le zoom en cours
482  qreal zoom_factor = matrix().m11();
483 
484  // choisit la granularite de la grille en fonction du zoom en cours
485  int drawn_x_grid = 1;//scene_ -> xGrid();
486  int drawn_y_grid = 1;//scene_ -> yGrid();
487  bool draw_grid = true;
488  bool draw_cross = false;
489 
490  if (zoom_factor < (4.0/3.0)) { //< no grid
491  draw_grid = false;
492  } else if (zoom_factor < 4.0) { //< grid 10*10
493  drawn_x_grid *= 10;
494  drawn_y_grid *= 10;
495  }else if (zoom_factor < 8.0) { //< grid 5*5
496  drawn_x_grid *= 5;
497  drawn_y_grid *= 5;
498  draw_cross = true;
499  } else if (zoom_factor < 10.0) { //< grid 2*2
500  drawn_x_grid *= 2;
501  drawn_y_grid *= 2;
502  draw_cross = true;
503  } else { //< grid 1*1
504  draw_cross = true;
505  }
506 
507  m_scene->setGrid(drawn_x_grid, drawn_y_grid);
508 
509  if (draw_grid) {
510  // draw the dot of the grid
511  QPen pen(Qt::black);
512  pen.setCosmetic(true);
513  p -> setPen(pen);
514  p -> setBrush(Qt::NoBrush);
515  qreal limite_x = r.x() + r.width();
516  qreal limite_y = r.y() + r.height();
517 
518  int g_x = (int)ceil(r.x());
519  while (g_x % drawn_x_grid) ++ g_x;
520  int g_y = (int)ceil(r.y());
521  while (g_y % drawn_y_grid) ++ g_y;
522 
523  for (int gx = g_x ; gx < limite_x ; gx += drawn_x_grid) {
524  for (int gy = g_y ; gy < limite_y ; gy += drawn_y_grid) {
525  if (draw_cross) {
526  if (!(gx % 10) && !(gy % 10)) {
527  p -> drawLine(QLineF(gx - 0.25, gy, gx + 0.25, gy));
528  p -> drawLine(QLineF(gx, gy - 0.25, gx, gy + 0.25));
529  } else {
530  p -> drawPoint(gx, gy);
531  }
532  } else {
533  p -> drawPoint(gx, gy);
534  }
535  }
536  }
537  }
538  p -> restore();
539 }
540 
547 QRectF ElementView::applyMovement(const QRectF &start, const QPointF &offset) {
548  // calcule le decalage a appliquer a partir de l'offset
549  QPointF final_offset;
550  final_offset.rx() = start.width() + offset.x();
551 
552  // applique le decalage ainsi calcule
553  return(start.translated(final_offset));
554 }
QRectF viewedSceneRect() const
Definition: elementview.cpp:55
ElementScene * scene() const
Definition: elementview.cpp:48
void zoomOut()
void wheelEvent(QWheelEvent *) override
ElementView::wheelEvent.
QPointF reference_view_
Definition: elementview.h:90
int offset_paste_count_
Definition: elementview.h:88
void setScene(ElementScene *)
Definition: elementview.cpp:74
void modeChanged()
Signal emitted after the mode changed.
void mouseReleaseEvent(QMouseEvent *) override
ElementView::mouseReleaseEvent Manage event release click mouse.
void setVisualisationMode()
Definition: elementview.cpp:82
void zoomFit()
bool gestures() const
ElementView::gestures.
void resetSceneRect()
ElementView::resetSceneRect reset le sceneRect (zone du schéma visualisée par l&#39;ElementView) afin que...
virtual void setGrid(int, int)
bool gestureEvent(QGestureEvent *event)
ElementView::gestureEvent.
void adjustSceneRect()
ElementView::adjustSceneRect Adjust the scenRect, so that he include all primitives of element plus t...
void zoomReset()
~ElementView() override
Destructeur.
Definition: elementview.cpp:44
void mousePressEvent(QMouseEvent *) override
void pasteInArea()
void getPasteArea(const QRectF &)
ElementContent pasteAreaDefined(const QRectF &)
static QPointF pasteOffset()
void zoomInSlowly()
void drawBackground(QPainter *, const QRectF &) override
ElementView(ElementScene *, QWidget *=nullptr)
Definition: elementview.cpp:27
QPointF start_top_left_corner_
Definition: elementview.h:89
ElementScene * m_scene
Definition: elementview.h:86
QList< QGraphicsItem * > ElementContent
ElementContent pasteWithOffset(const QDomDocument &)
void setSelectionMode()
Definition: elementview.cpp:91
void zoomOutSlowly()
QRectF applyMovement(const QRectF &, const QPointF &)
void mouseMoveEvent(QMouseEvent *) override
ElementView::mouseMoveEvent Manage the event move mouse.
bool event(QEvent *event) override
QString to_paste_in_area_
Definition: elementview.h:87
friend class PastePartsCommand
Definition: elementview.h:29