1 /***************************************************************************
2  *                                                                         *
3  *   copyright : (C) 2007 The University of Toronto                        *
4  *                   netterfield@astro.utoronto.ca                         *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  ***************************************************************************/
12 
13 #include "viewitem.h"
14 #include "applicationsettings.h"
15 #include "viewitemdialog.h"
16 #include "viewgridlayout.h"
17 #include "plotitem.h"
18 #include "sharedaxisboxitem.h"
19 #include "plotitemmanager.h"
20 #include "document.h"
21 #include "datacollection.h"
22 #include "formatgridhelper.h"
23 #include "dialogdefaults.h"
24 #include "cartesianrenderitem.h"
25 #include "viewitemscriptinterface.h"
26 
27 #include "layoutboxitem.h"
28 
29 #include <math.h>
30 
31 #include <QMenu>
32 #include <QDebug>
33 #include <QLabel>
34 #include <QHBoxLayout>
35 #include <QWidgetAction>
36 #include <QGraphicsScene>
37 #include <QGraphicsSceneContextMenuEvent>
38 #include <QInputDialog>
39 #include <QDrag>
40 #include <QMimeData>
41 #include <QtAlgorithms>
42 
43 static const qreal ONE_PI = 3.14159265358979323846264338327950288419717;
44 static qreal TWO_PI = 2.0 * ONE_PI;
45 static qreal RAD2DEG = 180.0 / ONE_PI;
46 static const int DRAWING_ZORDER = 500;
47 
48 #define DEBUG_GEOMETRY 0
49 #define DEBUG_REPARENT 0
50 
51 // enable drag & drop
52 #define KST_ENABLE_DD
53 
54 namespace Kst {
55 
ViewItem(View * parentView)56 ViewItem::ViewItem(View *parentView) :
57     QObject(parentView),
58     NamedObject(),
59     _isXTiedZoom(false),
60     _isYTiedZoom(false),
61     _plotMaximized(false),
62     _activeGrip(NoGrip),
63     _parentRelativeHeight(0),
64     _parentRelativeWidth(0),
65     _gripMode(Move),
66     _allowedGripModes(Move | Resize | Rotate /*| Scale*/),
67     _creationState(None),
68     _typeName("View Item"),
69     _zoomOnlyMode(View::ZoomOnlyDisabled),
70     _supportsTiedZoom(false),
71     _fixedSize(false),
72     _lockAspectRatio(false),
73     _lockAspectRatioFixed(false),
74     _hasStaticGeometry(false),
75     _lockParent(false),
76     _skipNextParentCheck(false),
77     _allowsLayout(true),
78     _hovering(false),
79     _acceptsChildItems(true),
80     _acceptsContextMenuEvents(true),
81     _updatingLayout(false),
82     _highlighted(false),
83     _allowedGrips(TopLeftGrip | TopRightGrip | BottomRightGrip | BottomLeftGrip |
84                 TopMidGrip | RightMidGrip | BottomMidGrip | LeftMidGrip),
85     _lockPosToData(false),
86     _editDialog(0),
87     _interface(0),
88     _dpi(71.0)
89 {
90   _initializeShortName();
91   setZValue(DRAWING_ZORDER);
92   setAcceptsHoverEvents(true);
93   setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable);
94   connect(parentView, SIGNAL(mouseModeChanged(View::MouseMode)),
95           this, SLOT(viewMouseModeChanged(View::MouseMode)));
96   connect(parentView, SIGNAL(viewModeChanged(View::ViewMode)),
97           this, SLOT(updateView()));
98 
99   connect(this, SIGNAL(geometryChanged()), parentView, SLOT(viewChanged()));
100 
101   setLayoutMargins(ApplicationSettings::self()->layoutMargins());
102   setLayoutSpacing(ApplicationSettings::self()->layoutSpacing());
103 
104   // Add actions common to all view objects
105   // create them here in the constructor so we
106   // can register shortcuts.
107   _editAction = new QAction(tr("Edit"), this);
108   _editAction->setShortcut(Qt::Key_E);
109   registerShortcut(_editAction);
110   connect(_editAction, SIGNAL(triggered()), this, SLOT(edit()));
111 
112   _deleteAction = new QAction(tr("Delete"), this);
113   _deleteAction->setShortcut(Qt::Key_Delete);
114   registerShortcut(_deleteAction);
115   connect(_deleteAction, SIGNAL(triggered()), this, SLOT(remove()));
116 
117   _raiseAction = new QAction(tr("Raise"), this);
118   connect(_raiseAction, SIGNAL(triggered()), this, SLOT(raise()));
119 
120   _lowerAction = new QAction(tr("Lower"), this);
121   connect(_lowerAction, SIGNAL(triggered()), this, SLOT(lower()));
122 
123   _autoLayoutAction = new QAction(tr("Automatic"), this);
124   _autoLayoutAction->setShortcut(Qt::Key_U);
125   registerShortcut(_autoLayoutAction);
126   connect(_autoLayoutAction, SIGNAL(triggered()), this, SLOT(createAutoLayout()));
127 
128   _protectedLayoutAction = new QAction(tr("Protect Layout"), this);
129   connect(_protectedLayoutAction, SIGNAL(triggered()), this, SLOT(createProtectedLayout()));
130 
131   _customLayoutAction = new QAction(tr("Columns"), this);
132   connect(_customLayoutAction, SIGNAL(triggered()), this, SLOT(createCustomLayout()));
133 
134   _oneColumnLayoutAction = new QAction(tr("1 Column"), this);
135   _oneColumnLayoutAction->setShortcut(Qt::Key_1);
136   registerShortcut(_oneColumnLayoutAction);
137   connect(_oneColumnLayoutAction, SIGNAL(triggered()), this, SLOT(createOneColLayout()));
138 
139   _twoColumnLayoutAction = new QAction(tr("2 Columns"), this);
140   _twoColumnLayoutAction->setShortcut(Qt::Key_2);
141   registerShortcut(_twoColumnLayoutAction);
142   connect(_twoColumnLayoutAction, SIGNAL(triggered()), this, SLOT(createTwoColLayout()));
143 
144   _threeColumnLayoutAction = new QAction(tr("3 Columns"), this);
145   _threeColumnLayoutAction->setShortcut(Qt::Key_3);
146   registerShortcut(_threeColumnLayoutAction);
147   connect(_threeColumnLayoutAction, SIGNAL(triggered()), this, SLOT(createThreeColLayout()));
148 
149   _lockPosToDataAction = new QAction(tr("&Lock Position to Data"),this);
150   _lockPosToDataAction->setCheckable(true);
151   connect(_lockPosToDataAction, SIGNAL(toggled(bool)), this, SLOT(setLockPosToData(bool)));
152 
153   // only drop plots onto TabBar
154   setAcceptDrops(false);
155 
156 }
157 
158 
~ViewItem()159 ViewItem::~ViewItem() {
160 }
161 
_initializeShortName()162 void ViewItem::_initializeShortName() {
163   _shortName = 'D'+QString::number(_viewitemnum);
164   if (_viewitemnum>max_viewitemnum)
165     max_viewitemnum = _viewitemnum;
166   _viewitemnum++;
167 
168 }
169 
170 
save(QXmlStreamWriter & xml)171 void ViewItem::save(QXmlStreamWriter &xml) {
172 
173   // when saving, check to see if your parent is a cartesianrenderitem.
174   // if so, we'll need to adjust to take into account that when loaded,
175   // the object will be created in a cartesian render item with no plot
176   // borders, and then resized.
177   // this keeps line end points in the right place.
178   CartesianRenderItem *cri = dynamic_cast<CartesianRenderItem *>(parentItem());
179   QTransform tr;
180   qreal w = _parentRelativeWidth;
181   if (cri) {
182     QRectF cri_rect = cri->rect();
183     QRectF plot_rect = cri->parentRect();
184     qreal oldL = relativeWidth()*cri_rect.width();
185 
186     qreal r0 = rotationAngleRadians();
187     qreal dy = oldL*sin(r0)*plot_rect.height()/cri_rect.height();
188     qreal dx = oldL*cos(r0)*plot_rect.width()/cri_rect.width();
189     qreal r1 = atan2(dy, dx);
190 
191     w = sqrt(dy*dy + dx*dx)/plot_rect.width();
192 
193     tr.rotateRadians(r1);
194   } else {
195     tr = transform();
196   }
197 
198   xml.writeAttribute("name", typeName());
199   xml.writeStartElement("position");
200   xml.writeAttribute("x", QVariant(pos().x()).toString());
201   xml.writeAttribute("y", QVariant(pos().y()).toString());
202   xml.writeAttribute("z", QVariant(zValue()).toString());
203   xml.writeEndElement();
204   xml.writeStartElement("rect");
205   xml.writeAttribute("x", QVariant(viewRect().x()).toString());
206   xml.writeAttribute("y", QVariant(viewRect().y()).toString());
207   xml.writeAttribute("width", QVariant(viewRect().width()).toString());
208   xml.writeAttribute("height", QVariant(viewRect().height()).toString());
209   xml.writeEndElement();
210   xml.writeStartElement("relativesize");
211   xml.writeAttribute("width", QVariant(w).toString());
212   xml.writeAttribute("height", QVariant(_parentRelativeHeight).toString());
213   xml.writeAttribute("centerx", QVariant(_parentRelativeCenter.x()).toString());
214   xml.writeAttribute("centery", QVariant(_parentRelativeCenter.y()).toString());
215   xml.writeAttribute("posx", QVariant(_parentRelativePosition.x()).toString());
216   xml.writeAttribute("posy", QVariant(_parentRelativePosition.y()).toString());
217   xml.writeAttribute("leftx", QVariant(_parentRelativeLeft.x()).toString());
218   xml.writeAttribute("lefty", QVariant(_parentRelativeLeft.y()).toString());
219   xml.writeAttribute("rightx", QVariant(_parentRelativeRight.x()).toString());
220   xml.writeAttribute("righty", QVariant(_parentRelativeRight.y()).toString());
221   xml.writeAttribute("fixaspect", QVariant(_lockAspectRatio).toString());
222   xml.writeAttribute("lockpostodata", QVariant(_lockPosToData).toString());
223   if (_lockPosToData) { // meaningless if not locked: why pollute the file?
224     xml.writeAttribute("datarect_x", QVariant(_dataRelativeRect.x()).toString());
225     xml.writeAttribute("datarect_y", QVariant(_dataRelativeRect.y()).toString());
226     xml.writeAttribute("datarect_width", QVariant(_dataRelativeRect.width()).toString());
227     xml.writeAttribute("datarect_height", QVariant(_dataRelativeRect.height()).toString());
228   }
229   xml.writeEndElement();
230 
231   xml.writeStartElement("transform");
232   xml.writeAttribute("m11", QVariant(tr.m11()).toString());
233   xml.writeAttribute("m12", QVariant(tr.m12()).toString());
234   xml.writeAttribute("m13", QVariant(tr.m13()).toString());
235   xml.writeAttribute("m21", QVariant(tr.m21()).toString());
236   xml.writeAttribute("m22", QVariant(tr.m22()).toString());
237   xml.writeAttribute("m23", QVariant(tr.m23()).toString());
238   xml.writeAttribute("m31", QVariant(tr.m31()).toString());
239   xml.writeAttribute("m32", QVariant(tr.m32()).toString());
240   xml.writeAttribute("m33", QVariant(tr.m33()).toString());
241   xml.writeEndElement();
242   xml.writeStartElement("pen");
243   xml.writeAttribute("style", QVariant((int)pen().style()).toString());
244   xml.writeAttribute("width", QVariant(storedPen().widthF()).toString());
245   xml.writeAttribute("miterlimit", QVariant(pen().miterLimit()).toString());
246   xml.writeAttribute("cap", QVariant(pen().capStyle()).toString());
247   xml.writeAttribute("joinStyle", QVariant(pen().joinStyle()).toString());
248   xml.writeStartElement("brush");
249   xml.writeAttribute("color", pen().brush().color().name());
250   xml.writeAttribute("alpha", QString::number(pen().brush().color().alphaF()));
251   xml.writeAttribute("style", QVariant((int)pen().brush().style()).toString());
252   xml.writeEndElement();
253   xml.writeEndElement();
254   xml.writeStartElement("brush");
255   xml.writeAttribute("color", brush().color().name());
256   xml.writeAttribute("alpha", QString::number(brush().color().alphaF()));
257   xml.writeAttribute("style", QVariant((int)brush().style()).toString());
258   if (brush().gradient()) {
259     QString stopList;
260     foreach(const QGradientStop &stop, brush().gradient()->stops()) {
261       qreal point = (qreal)stop.first;
262       QColor color = (QColor)stop.second;
263 
264       stopList += QString::number(point);
265       stopList += ',';
266       stopList += color.name();
267       stopList += ',';
268     }
269     xml.writeAttribute("gradient", stopList);
270   }
271   xml.writeEndElement();
272 
273   QList<QGraphicsItem*> list = QGraphicsItem::childItems();
274   foreach (QGraphicsItem *item, list) {
275     ViewItem *viewItem = dynamic_cast<ViewItem*>(item);
276     if (!viewItem)
277       continue;
278 
279     viewItem->save(xml);
280   }
281 }
282 
applyDialogDefaultsFill(bool default_no_fill)283 void ViewItem::applyDialogDefaultsFill(bool default_no_fill) {
284   if (hasBrush()) {
285     //set the brush
286     QBrush brush = dialogDefaultsBrush(defaultsGroupName(), default_no_fill);
287     setBrush(brush);
288   }
289 }
290 
applyDialogDefaultsStroke(bool default_no_pen)291 void ViewItem::applyDialogDefaultsStroke(bool default_no_pen) {
292   if (hasStroke()) {
293     // set the pen
294     QPen pen = dialogDefaultsPen(defaultsGroupName(), default_no_pen);
295     storePen(pen);
296   }
297 }
298 
applyDialogDefaultsLockPosToData()299 void ViewItem::applyDialogDefaultsLockPosToData() {
300   setLockPosToData(dialogDefaultsLockPosToData(defaultsGroupName()));
301 }
302 
setLockPosToData(bool lockPosToData)303 void ViewItem::setLockPosToData(bool lockPosToData) {
304   _lockPosToData = lockPosToData;
305   _lockPosToDataAction->setChecked(lockPosToData);
306   emit(relativeSizeUpdated());
307 }
308 
309 
parentRect() const310 QRectF ViewItem::parentRect() const {
311   if (parentViewItem()) {
312     return parentViewItem()->rect().normalized();
313   } else if (view()) {
314     return view()->rect();
315   } else {
316     Q_ASSERT_X(false,"parent test", "item has no parentview item");
317   }
318   return QRectF(0,0,1,1); // shouldn't get here
319 }
320 
321 
applyDataLockedDimensions()322 void ViewItem::applyDataLockedDimensions() {
323   PlotRenderItem *render_item = dynamic_cast<PlotRenderItem *>(parentViewItem());
324   if (render_item) {
325     qreal parentWidth = render_item->width();
326     qreal parentHeight = render_item->height();
327     qreal parentX = render_item->rect().x();
328     qreal parentY = render_item->rect().y();
329 
330     qreal aspectRatio;
331     if (rect().width() > 0) {
332       aspectRatio = qreal(rect().height()) / qreal(rect().width());
333     } else {
334       aspectRatio = 10000.0;
335     }
336 
337     qreal relativeWidth = _dataRelativeRect.width()/(render_item->plotItem()->xMax() - render_item->plotItem()->xMin());
338     qreal relativeHeight = _dataRelativeRect.height()/(render_item->plotItem()->yMax() - render_item->plotItem()->yMin());
339     qreal relativeX = (_dataRelativeRect.center().x() - render_item->plotItem()->xMin())/
340         (render_item->plotItem()->xMax() - render_item->plotItem()->xMin());
341     qreal relativeY = (_dataRelativeRect.center().y() - render_item->plotItem()->yMin())/
342         (render_item->plotItem()->yMax() - render_item->plotItem()->yMin());
343 
344     qreal width = relativeWidth * parentWidth;
345     qreal height;
346     if (lockAspectRatio()) {
347       height = width * aspectRatio;
348     } else {
349       height = relativeHeight * parentHeight;
350     }
351     setPos(parentX + relativeX*parentWidth, parentY + (1.0-relativeY)*parentHeight);
352     setViewRect(-width/2, -height/2, width, height);
353 
354     updateRelativeSize();
355 
356   } else {
357     qDebug() << "apply data locked dimensions called without a render item (!)";
358   }
359 }
360 
parse(QXmlStreamReader & xml,bool & validChildTag)361 bool ViewItem::parse(QXmlStreamReader &xml, bool &validChildTag) {
362   bool knownTag = false;
363   QString expectedTag;
364   if (xml.isStartElement()) {
365     expectedTag = xml.name().toString();
366     QXmlStreamAttributes attrs = xml.attributes();
367     QStringRef av;
368     if (xml.name().toString() == "name") {
369       knownTag = true;
370       av = attrs.value("name");
371       if (!av.isNull()) {
372         setTypeName(av.toString());
373      }
374     } else if (xml.name().toString() == "position") {
375       knownTag = true;
376       qreal x = 0, y = 0, z = DRAWING_ZORDER;
377       av = attrs.value("x");
378       if (!av.isNull()) {
379         x = av.toString().toDouble();
380       }
381       av = attrs.value("y");
382       if (!av.isNull()) {
383         y = av.toString().toDouble();
384      }
385      setPos(x, y);
386 
387      av = attrs.value("z");
388      if (!av.isNull()) {
389        z = av.toString().toDouble();
390      }
391      setZValue(z);
392 
393     } else if (xml.name().toString() == "brush") {
394       knownTag = true;
395       QBrush brush;
396       av = attrs.value("gradient");
397       if (!av.isNull()) {
398         QStringList stopInfo = av.toString().split(',', QString::SkipEmptyParts);
399         QLinearGradient gradient(1,0,0,0);
400         gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
401         for (int i = 0; i < stopInfo.size(); i+=2) {
402           gradient.setColorAt(stopInfo.at(i).toDouble(), QColor(stopInfo.at(i+1)));
403         }
404         brush = QBrush(gradient);
405       } else {
406         av = attrs.value("color");
407         if (!av.isNull()) {
408           brush.setColor(QColor(av.toString()));
409         }
410         av = attrs.value("style");
411         if (!av.isNull()) {
412           brush.setStyle((Qt::BrushStyle)av.toString().toInt());
413         }
414         av = attrs.value("alpha");
415         if (!av.isNull()) {
416           qreal alpha = av.toString().toDouble();
417           QColor c = brush.color();
418           c.setAlphaF(alpha);
419           brush.setColor(c);
420         }
421       }
422       setBrush(brush);
423     } else if (xml.name().toString() == "pen") {
424       knownTag = true;
425       QPen pen;
426       av = attrs.value("style");
427       if (!av.isNull()) {
428         pen.setStyle((Qt::PenStyle)av.toString().toInt());
429       }
430       av = attrs.value("width");
431       if (!av.isNull()) {
432         pen.setWidthF(av.toString().toDouble());
433       }
434       av = attrs.value("miterlimit");
435       if (!av.isNull()) {
436         pen.setMiterLimit(av.toString().toDouble());
437       }
438       av = attrs.value("cap");
439       if (!av.isNull()) {
440         pen.setCapStyle((Qt::PenCapStyle)av.toString().toInt());
441       }
442       av = attrs.value("joinstyle");
443       if (!av.isNull()) {
444         pen.setJoinStyle((Qt::PenJoinStyle)av.toString().toInt());
445       }
446       xml.readNext();
447       xml.readNext();
448       if (xml.isStartElement() && (xml.name().toString() == "brush")) {
449         QBrush penBrush;
450         attrs = xml.attributes();
451         av = attrs.value("color");
452         if (!av.isNull()) {
453             penBrush.setColor(QColor(av.toString()));
454         }
455         av = attrs.value("alpha");
456         if (!av.isNull()) {
457           qreal alpha = av.toString().toDouble();
458           QColor c = penBrush.color();
459           c.setAlphaF(alpha);
460           penBrush.setColor(c);
461         }
462 
463         av = attrs.value("style");
464         if (!av.isNull()) {
465           penBrush.setStyle((Qt::BrushStyle)av.toString().toInt());
466         }
467         pen.setBrush(penBrush);
468         xml.readNext();
469         if (!xml.isEndElement() || (xml.name().toString() != "brush")) {
470           expectedTag = "InvalidTag";
471         }
472         xml.readNext();
473       }
474       storePen(pen);
475     } else if (xml.name().toString() == "rect") {
476       knownTag = true;
477       qreal x = 0, y = 0, w = 10, h = 10;
478       av = attrs.value("width");
479       if (!av.isNull()) {
480         w = av.toString().toDouble();
481       }
482       av = attrs.value("height");
483       if (!av.isNull()) {
484         h = av.toString().toDouble();
485       }
486       av = attrs.value("x");
487       if (!av.isNull()) {
488          x = av.toString().toDouble();
489       }
490       av = attrs.value("y");
491       if (!av.isNull()) {
492         y = av.toString().toDouble();
493       }
494       setViewRect(QRectF(QPointF(x, y), QSizeF(w, h)));
495     } else if (xml.name().toString() == "relativesize") {
496       knownTag = true;
497       qreal width = 0, height = 0, centerx = 0, centery = 0, posx = 0, posy = 0;
498       qreal leftx = -1.0, lefty = -1.0, rightx = -1.0, righty = -1.0;
499       bool lock_aspect_ratio = false;
500       av = attrs.value("width");
501       if (!av.isNull()) {
502         width = av.toString().toDouble();
503       }
504       av = attrs.value("height");
505       if (!av.isNull()) {
506         height = av.toString().toDouble();
507       }
508       av = attrs.value("centerx");
509       if (!av.isNull()) {
510         centerx = av.toString().toDouble();
511       }
512       av = attrs.value("centery");
513       if (!av.isNull()) {
514         centery = av.toString().toDouble();
515       }
516       av = attrs.value("posx");
517       if (!av.isNull()) {
518         posx = av.toString().toDouble();
519       }
520       av = attrs.value("posy");
521       if (!av.isNull()) {
522         posy = av.toString().toDouble();
523       }
524       av = attrs.value("leftx");
525       if (!av.isNull()) {
526         leftx = av.toString().toDouble();
527       }
528       av = attrs.value("lefty");
529       if (!av.isNull()) {
530         lefty = av.toString().toDouble();
531       }
532       av = attrs.value("rightx");
533       if (!av.isNull()) {
534         rightx = av.toString().toDouble();
535       }
536       av = attrs.value("righty");
537       if (!av.isNull()) {
538         righty = av.toString().toDouble();
539       }
540       av = attrs.value("fixaspect");
541       if (!av.isNull()) {
542         lock_aspect_ratio = QVariant(av.toString()).toBool();
543       }
544       if (rightx <-0.99) { // old kst file: generate from center
545         rightx = centerx + width/2.0;
546         leftx  = centerx - width/2.0;
547         righty = centery + height/2.0;
548         lefty  = centery + height/2.0;
549       }
550       setRelativeWidth(width);
551       setRelativeHeight(height);
552       setRelativeCenter(QPointF(centerx, centery));
553       setRelativePosition(QPointF(posx, posy));
554       setRelativeLeft(QPointF(leftx, lefty));
555       setRelativeRight(QPointF(rightx, righty));
556       setLockAspectRatio(lock_aspect_ratio);
557 
558       av = attrs.value("lockpostodata");
559       if (!av.isNull()) {
560         bool lock_pos_to_data = QVariant(av.toString()).toBool();
561         setLockPosToData(lock_pos_to_data);
562         if (lock_pos_to_data) {
563           qreal x=0, y=0, w=0.1, h=0.1;
564           av = attrs.value("datarect_x");
565           if (!av.isNull()) {
566             x = av.toString().toDouble();
567           }
568           av = attrs.value("datarect_y");
569           if (!av.isNull()) {
570             y = av.toString().toDouble();
571           }
572           av = attrs.value("datarect_width");
573           if (!av.isNull()) {
574             w = av.toString().toDouble();
575           }
576           av = attrs.value("datarect_height");
577           if (!av.isNull()) {
578             h = av.toString().toDouble();
579           }
580           _dataRelativeRect = QRectF(x,y,w,h);
581         }
582       } else {
583         setLockPosToData(false);
584       }
585     } else if (xml.name().toString() == "transform") {
586       knownTag = true;
587       qreal m11 = 1.0, m12 = 0, m13 = 0, m21 = 0, m22 = 1.0, m23 = 0, m31 = 0, m32= 0, m33 = 1.0;
588       av = attrs.value("m11");
589       if (!av.isNull()) {
590         m11 = av.toString().toDouble();
591       }
592       av = attrs.value("m12");
593       if (!av.isNull()) {
594         m12 = av.toString().toDouble();
595       }
596       av = attrs.value("m13");
597       if (!av.isNull()) {
598         m13 = av.toString().toDouble();
599       }
600       av = attrs.value("m21");
601       if (!av.isNull()) {
602         m21 = av.toString().toDouble();
603       }
604       av = attrs.value("m22");
605       if (!av.isNull()) {
606         m22 = av.toString().toDouble();
607       }
608       av = attrs.value("m23");
609       if (!av.isNull()) {
610         m23 = av.toString().toDouble();
611       }
612       av = attrs.value("m31");
613       if (!av.isNull()) {
614         m31 = av.toString().toDouble();
615       }
616       av = attrs.value("m32");
617       if (!av.isNull()) {
618         m32 = av.toString().toDouble();
619       }
620       av = attrs.value("m33");
621       if (!av.isNull()) {
622         m33 = av.toString().toDouble();
623       }
624       setTransform(QTransform(m11, m12, m13, m21, m22, m23, m31, m32, m33));
625     }
626   }
627 
628   if (knownTag) {
629     xml.readNext();
630     if (xml.isEndElement()) {
631       if ((xml.name().toString() == expectedTag) ) {
632       validChildTag = true;
633       }
634     }
635   }
636   return knownTag;
637 }
638 
view() const639 View *ViewItem::view() const {
640   return qobject_cast<View*>(QObject::parent());
641 }
642 
setView(View * parentView)643 void ViewItem::setView(View* parentView) {
644   QObject::setParent(parentView);
645   reRegisterShortcut();
646 
647   QList<QGraphicsItem*> list = QGraphicsItem::childItems();
648   foreach (QGraphicsItem *item, list) {
649     ViewItem *viewItem = dynamic_cast<ViewItem*>(item);
650     if (viewItem) {
651       viewItem->setView(parentView);
652     }
653   }
654 }
655 
656 
parentViewItem() const657 ViewItem *ViewItem::parentViewItem() const {
658   return dynamic_cast<ViewItem*>(parentItem());
659 }
660 
661 
setParentViewItem(ViewItem * parent)662 void ViewItem::setParentViewItem(ViewItem* parent) {
663   QGraphicsItem::setParentItem(parent);
664   updateRelativeSize(true);
665 }
666 
667 
gripMode() const668 ViewItem::GripMode ViewItem::gripMode() const {
669   return _gripMode;
670 }
671 
672 
setGripMode(GripMode mode)673 void ViewItem::setGripMode(GripMode mode) {
674   _gripMode = mode;
675   update();
676 }
677 
678 
allowedGripModes() const679 ViewItem::GripModes ViewItem::allowedGripModes() const {
680   return _allowedGripModes;
681 }
682 
683 
setAllowedGripModes(GripModes modes)684 void ViewItem::setAllowedGripModes(GripModes modes) {
685   _allowedGripModes = modes;
686 }
687 
688 
isAllowed(GripMode mode) const689 bool ViewItem::isAllowed(GripMode mode) const {
690   return _allowedGripModes & mode;
691 }
692 
693 
viewRect() const694 QRectF ViewItem::viewRect() const {
695   return rect();
696 }
697 
698 
setViewRect(const QRectF & viewRect,bool automaticChange)699 void ViewItem::setViewRect(const QRectF &viewRect, bool automaticChange) {
700   QRectF oldViewRect = rect();
701 
702   if (oldViewRect == viewRect)
703     return;
704 
705   setRect(viewRect);
706 
707   emit geometryChanged();
708 
709   if (!automaticChange) {
710     updateRelativeSize();
711   }
712 
713   foreach (QGraphicsItem *item, QGraphicsItem::childItems()) {
714     if (item->parentItem() != this)
715       continue;
716 
717     ViewItem *viewItem = dynamic_cast<ViewItem*>(item);
718 
719     if (!viewItem)
720       continue;
721 
722     if (viewItem->hasStaticGeometry())
723       continue;
724 
725     viewItem->setSkipNextParentCheck(true);
726     viewItem->updateChildGeometry(oldViewRect, viewRect);
727   }
728 }
729 
730 
setViewRect(qreal x,qreal y,qreal width,qreal height,bool automaticChange)731 void ViewItem::setViewRect(qreal x, qreal y, qreal width, qreal height, bool automaticChange) {
732   setViewRect(QRectF(x, y, width, height), automaticChange);
733 }
734 
735 
sizeOfGrip() const736 QSizeF ViewItem::sizeOfGrip() const {
737   if (!view())
738     return QSizeF();
739 
740   int base = _dpi*11.0/96.0 ;
741 
742   return view()->mapToScene(QRect(0, 0, base, base)).boundingRect().size();
743 }
744 
745 
topLeftGrip() const746 QPainterPath ViewItem::topLeftGrip() const {
747   QRectF bound = gripBoundingRect();
748   QRectF grip = QRectF(bound.topLeft(), sizeOfGrip());
749   QPainterPath path;
750   if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move)
751     path.addRect(grip);
752   else
753     path.addEllipse(grip);
754 
755   return path;
756 }
757 
758 
topRightGrip() const759 QPainterPath ViewItem::topRightGrip() const {
760   QRectF bound = gripBoundingRect();
761   QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width(), 0), sizeOfGrip());
762   QPainterPath path;
763   if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move)
764     path.addRect(grip);
765   else
766     path.addEllipse(grip);
767 
768   return path;
769 }
770 
771 
bottomRightGrip() const772 QPainterPath ViewItem::bottomRightGrip() const {
773   QRectF bound = gripBoundingRect();
774   QRectF grip = QRectF(bound.bottomRight() - QPointF(sizeOfGrip().width(), sizeOfGrip().height()), sizeOfGrip());
775   QPainterPath path;
776   if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move)
777     path.addRect(grip);
778   else
779     path.addEllipse(grip);
780 
781   return path;
782 }
783 
784 
bottomLeftGrip() const785 QPainterPath ViewItem::bottomLeftGrip() const {
786   QRectF bound = gripBoundingRect();
787   QRectF grip = QRectF(bound.bottomLeft() - QPointF(0, sizeOfGrip().height()), sizeOfGrip());
788   QPainterPath path;
789   if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move)
790     path.addRect(grip);
791   else
792     path.addEllipse(grip);
793 
794   return path;
795 }
796 
797 
topMidGrip() const798 QPainterPath ViewItem::topMidGrip() const {
799   if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio)
800     return QPainterPath();
801 
802   QRectF bound = gripBoundingRect();
803   QRectF grip = QRectF(bound.topLeft(), sizeOfGrip());
804   grip.moveCenter(QPointF(bound.center().x(), grip.center().y()));
805 
806   QPainterPath path;
807   path.addRect(grip);
808 
809   return path;
810 }
811 
812 
rightMidGrip() const813 QPainterPath ViewItem::rightMidGrip() const {
814   if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio)
815     return QPainterPath();
816 
817   QRectF bound = gripBoundingRect();
818   QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width(), 0), sizeOfGrip());
819   grip.moveCenter(QPointF(grip.center().x(), bound.center().y()));
820 
821   QPainterPath path;
822   path.addRect(grip);
823 
824   return path;
825 }
826 
827 
bottomMidGrip() const828 QPainterPath ViewItem::bottomMidGrip() const {
829   if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio)
830     return QPainterPath();
831 
832   QRectF bound = gripBoundingRect();
833   QRectF grip = QRectF(bound.bottomLeft() - QPointF(0, sizeOfGrip().height()), sizeOfGrip());
834   grip.moveCenter(QPointF(bound.center().x(), grip.center().y()));
835 
836   QPainterPath path;
837   path.addRect(grip);
838 
839   return path;
840 }
841 
842 
leftMidGrip() const843 QPainterPath ViewItem::leftMidGrip() const {
844   if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio)
845     return QPainterPath();
846 
847   QRectF bound = gripBoundingRect();
848   QRectF grip = QRectF(bound.topLeft(), sizeOfGrip());
849   grip.moveCenter(QPointF(grip.center().x(), bound.center().y()));
850 
851   QPainterPath path;
852   path.addRect(grip);
853 
854   return path;
855 }
856 
857 
grips() const858 QPainterPath ViewItem::grips() const {
859   QPainterPath grips;
860   grips.addPath(topLeftGrip());
861   grips.addPath(topRightGrip());
862   grips.addPath(bottomRightGrip());
863   grips.addPath(bottomLeftGrip());
864   grips.addPath(topMidGrip());
865   grips.addPath(rightMidGrip());
866   grips.addPath(bottomMidGrip());
867   grips.addPath(leftMidGrip());
868   return grips;
869 }
870 
871 
activeGrip() const872 ViewItem::ActiveGrip ViewItem::activeGrip() const {
873   return _activeGrip;
874 }
875 
876 
setActiveGrip(ActiveGrip grip)877 void ViewItem::setActiveGrip(ActiveGrip grip) {
878   _activeGrip = grip;
879 }
880 
881 
allowedGrips() const882 ViewItem::ActiveGrips ViewItem::allowedGrips() const {
883   return _allowedGrips;
884 }
885 
886 
setAllowedGrips(ActiveGrips grips)887 void ViewItem::setAllowedGrips(ActiveGrips grips) {
888   _allowedGrips = grips;
889 }
890 
891 
isAllowed(ActiveGrip grip) const892 bool ViewItem::isAllowed(ActiveGrip grip) const {
893   return _allowedGrips & grip;
894 }
895 
896 
selectBoundingRect() const897 QRectF ViewItem::selectBoundingRect() const {
898   return rect();
899 }
900 
901 
gripBoundingRect() const902 QRectF ViewItem::gripBoundingRect() const {
903   QRectF bound = selectBoundingRect();
904   bound.setTopLeft(bound.topLeft() - QPointF(sizeOfGrip().width() / 2.0, sizeOfGrip().height() / 2.0));
905   bound.setWidth(bound.width() + sizeOfGrip().width() / 2.0);
906   bound.setHeight(bound.height() + sizeOfGrip().height() / 2.0);
907   return bound;
908 }
909 
910 
boundingRect() const911 QRectF ViewItem::boundingRect() const {
912   bool inCreation = false;
913   if (view()) /* false when exiting */
914     inCreation = view()->mouseMode() == View::Create;
915   if ((!isSelected() && !isHovering()) || inCreation)
916     return QGraphicsRectItem::boundingRect();
917 
918   QPolygonF gripBound = gripBoundingRect();
919   return QRectF(gripBound[0], gripBound[2]);
920 }
921 
922 
shape() const923 QPainterPath ViewItem::shape() const {
924   if ((!isSelected() && !isHovering()) || (view()->mouseMode() == View::Create))
925     return itemShape();
926 
927   QPainterPath selectPath;
928   selectPath.setFillRule(Qt::WindingFill);
929 
930   selectPath.addPolygon(rect());
931 
932   selectPath.addPath(grips());
933   return selectPath;
934 }
935 
isMaximized()936 bool ViewItem::isMaximized() {
937   if (_plotMaximized) {
938     return true;
939   } else if (parentViewItem()) {
940     return parentViewItem()->isMaximized();
941   } else {
942     return false;
943   }
944 }
945 
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)946 void ViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
947   Q_UNUSED(option);
948   Q_UNUSED(widget);
949   if ((!isMaximized()) && view()->childMaximized()) {
950     return;
951   }
952 
953   _dpi = painter->device()->logicalDpiX();
954 
955   QPen rescaled_pen(_storedPen);
956   rescaled_pen.setWidthF(Curve::lineDim(painter->window(),rescaled_pen.widthF()));
957   setPen(rescaled_pen);
958 
959   painter->save();
960   painter->setPen(pen());
961   painter->setBrush(brush());
962   if (_lockPosToData) {
963     PlotRenderItem *render_item = dynamic_cast<PlotRenderItem *>(parentViewItem());
964     if (render_item) {
965       QPolygonF PF = mapFromParent(render_item->rect());
966       QPainterPath path;
967       path.addPolygon(PF);
968       painter->setClipPath(path);
969     }
970   }
971   paint(painter); //this is the overload that subclasses should use...
972   if (!view()->isPrinting() && !view()->childMaximized()) {
973     painter->setPen(Qt::DotLine);
974     painter->setBrush(Qt::NoBrush);
975     if ((isSelected() || isHovering())
976         && view()->mouseMode() != View::Create
977         && view()->viewMode() != View::Data) {
978       painter->drawPath(shape());
979       if (_gripMode == Resize)
980         painter->fillPath(grips(), Qt::blue);
981       else if (_gripMode == Scale)
982         painter->fillPath(grips(), Qt::black);
983       else if (_gripMode == Rotate)
984         painter->fillPath(grips(), Qt::red);
985       else if (_gripMode == Move)
986         painter->fillPath(grips(), Qt::transparent);
987     } else if (isHighlighted()) {
988       QColor highlightColor(QColor(255, 255, 0, 120));
989       painter->fillPath(shape(), highlightColor);
990     }
991     if (supportsTiedZoom()) {
992       painter->save();
993       painter->setPen(Qt::black);
994       painter->setRenderHint(QPainter::Antialiasing, true);
995       painter->fillPath(checkBox(), Qt::white);
996       if (isHovering()) {
997         QRectF check = checkBox().controlPointRect();
998         check.setSize(QSizeF(check.width() / 3.5, check.height() / 3.5));
999         check.moveCenter(checkBox().controlPointRect().center());
1000         QPainterPath p;
1001         p.addEllipse(check);
1002         painter->fillPath(p, Qt::black);
1003       }
1004       if (isTiedZoom()) {
1005         painter->save();
1006         QColor c = Qt::black;
1007         c.setAlphaF(c.alphaF() * 0.6);
1008         painter->fillPath(tiedZoomCheck(), c);
1009         painter->restore();
1010       }
1011       painter->setBrush(Qt::transparent);
1012       painter->drawPath(checkBox());
1013       painter->restore();
1014     }
1015 #if DEBUG_GEOMETRY
1016   //  painter->fillRect(selectBoundingRect(), Qt::blue);
1017     QColor semiRed(QColor(255, 0, 0, 50));
1018     painter->fillPath(shape(), semiRed);
1019 
1020     QPen p = painter->pen();
1021 
1022     painter->setPen(Qt::white);
1023     painter->drawLine(_normalLine);
1024 
1025     painter->setPen(Qt::red);
1026     painter->drawLine(_rotationLine);
1027     painter->setPen(p);
1028 
1029     painter->drawText(rect().topLeft(), "TL");
1030     painter->drawText(rect().topRight(), "TR");
1031     painter->drawText(rect().bottomLeft(), "BL");
1032     painter->drawText(rect().bottomRight(), "BR");
1033 #endif
1034   }
1035   painter->restore();
1036 }
1037 
1038 
paint(QPainter * painter)1039 void ViewItem::paint(QPainter *painter) {
1040   Q_UNUSED(painter);
1041 }
1042 
1043 
edit()1044 void ViewItem::edit() {
1045   if (!_editDialog) {
1046     _editDialog = new ViewItemDialog(this, kstApp->mainWindow());
1047   }
1048   _editDialog->show();
1049   _editDialog->raise();
1050 }
1051 
1052 
sharePlots(QPainter * painter,bool creation)1053 void ViewItem::sharePlots(QPainter *painter, bool creation) {
1054   if (!_updatingLayout) {
1055     _updatingLayout = true;
1056     ViewGridLayout::sharePlots(this, painter, creation);
1057     _updatingLayout = false;
1058   }
1059 }
1060 
1061 
createAutoLayout()1062 void ViewItem::createAutoLayout() {
1063   if (parentViewItem()) {
1064     LayoutCommand *layout = new LayoutCommand(parentViewItem());
1065     layout->createLayout(false);
1066   } else if (view()) {
1067     view()->createLayout(false);
1068   }
1069 }
1070 
createProtectedLayout()1071 void ViewItem::createProtectedLayout() {
1072   if (parentViewItem()) {
1073     LayoutCommand *layout = new LayoutCommand(parentViewItem());
1074     layout->createLayout(true);
1075   } else if (view()) {
1076     view()->createLayout(true);
1077   }
1078 }
1079 
1080 
createCustomLayout(int columns)1081 void ViewItem::createCustomLayout(int columns) {
1082   bool ok = true;
1083   int default_cols = qMax(1,int(sqrt((qreal)Data::self()->plotList().count())));
1084 
1085   if (columns<1) {
1086     columns = QInputDialog::getInt(view(), tr("Kst: Column Layout"),
1087                                        tr("Layout in columns in order of creation.\nSelect number of columns:"),default_cols, 1,
1088                                        15, 1, &ok);
1089   }
1090 
1091   if (ok) {
1092     if (parentViewItem() && false) {
1093       LayoutCommand *layout = new LayoutCommand(parentViewItem());
1094       layout->createLayout(false, columns);
1095     } else if (view()) {
1096       view()->createLayout(false, columns);
1097     }
1098   }
1099 }
1100 
1101 
raise()1102 void ViewItem::raise() {
1103   RaiseCommand *up = new RaiseCommand(this);
1104   up->redo();
1105 }
1106 
1107 
lower()1108 void ViewItem::lower() {
1109   LowerCommand *down = new LowerCommand(this);
1110   down->redo();
1111 }
1112 
1113 
remove()1114 void ViewItem::remove() {
1115   RemoveCommand *remove = new RemoveCommand(this);
1116   remove->redo();
1117 }
1118 
1119 
creationPolygonChanged(View::CreationEvent event)1120 void ViewItem::creationPolygonChanged(View::CreationEvent event) {
1121   if (event == View::EscapeEvent) {
1122     deleteLater();
1123     kstApp->mainWindow()->clearDrawingMarker();
1124     return;
1125   }
1126 
1127   if (event == View::MousePress) {
1128     const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MousePress));
1129     setPos(poly.first().x(), poly.first().y());
1130     setViewRect(0.0, 0.0, 0.0, 0.0);
1131     view()->scene()->addItem(this);
1132     _creationState = InProgress;
1133     return;
1134   }
1135 
1136   if (event == View::MouseMove) {
1137     const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MouseMove));
1138     qreal x0 = qMin(qreal(0.0), poly.last().x());
1139     qreal y0 = qMin(qreal(0.0), poly.last().y());
1140     QRectF newRect(x0, y0, fabs(poly.last().x()), fabs(poly.last().y()));
1141     setViewRect(newRect);
1142     return;
1143   }
1144 
1145   if (event == View::MouseRelease) {
1146     const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MouseRelease));
1147     qreal x0 = qMin(qreal(0.0), poly.last().x());
1148     qreal y0 = qMin(qreal(0.0), poly.last().y());
1149     QRectF newRect(x0, y0, fabs(poly.last().x()), fabs(poly.last().y()));
1150 
1151     if (!newRect.isValid()) {
1152       newRect = newRect.normalized();
1153       newRect.setWidth(qMax(qreal(3.0), newRect.width()));
1154       newRect.setHeight(qMax(qreal(3.0), newRect.height()));
1155       setPos(pos() + newRect.topLeft());
1156 
1157       newRect.moveTopLeft(QPointF(0, 0));
1158       setViewRect(newRect);
1159 
1160       view()->setPlotBordersDirty(true);
1161     } else {
1162       setViewRect(newRect.normalized());
1163     }
1164 
1165     view()->disconnect(this, SLOT(deleteLater())); //Don't delete ourself
1166     view()->disconnect(this, SLOT(creationPolygonChanged(View::CreationEvent)));
1167     view()->setMouseMode(View::Default);
1168 
1169     updateViewItemParent();
1170     _creationState = Completed;
1171     setZValue(DRAWING_ZORDER);
1172     emit creationComplete();
1173     return;
1174   }
1175 }
1176 
1177 
1178 
creationPolygonChangedFixedAspect(View::CreationEvent event,qreal aspect)1179 void ViewItem::creationPolygonChangedFixedAspect(View::CreationEvent event, qreal aspect) {
1180 
1181   if (event == View::EscapeEvent) {
1182     ViewItem::creationPolygonChanged(event);
1183     return;
1184   }
1185 
1186   if (event == View::MousePress) {
1187     const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MousePress));
1188     setPos(poly.first().x(), poly.first().y());
1189     setViewRect(QRectF(0.0, 0.0, 0.0, sizeOfGrip().height()));
1190     setRect(0,0,4,4);
1191     view()->scene()->addItem(this);
1192     return;
1193   }
1194 
1195   if (event == View::MouseMove) {
1196     const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MouseMove));
1197 
1198     QPointF offset = lockOffset(poly.last(), aspect, false);
1199 
1200     if (offset.x()<5.0) {
1201       offset.setX(5.0);
1202       offset.setY(5.0/aspect);
1203     }
1204 
1205     setViewRect(0,0,offset.x(), offset.y());
1206     return;
1207   }
1208 
1209   if (event == View::MouseRelease) {
1210     view()->disconnect(this, SLOT(deleteLater())); //Don't delete ourself
1211     view()->disconnect(this, SLOT(creationPolygonChanged(View::CreationEvent)));
1212     view()->setMouseMode(View::Default);
1213 
1214     updateViewItemParent();
1215     _creationState = Completed;
1216     setZValue(DRAWING_ZORDER);
1217     emit creationComplete();
1218     return;
1219   }
1220 }
1221 
1222 
addTitle(QMenu * menu) const1223 void ViewItem::addTitle(QMenu *menu) const {
1224   QWidgetAction *action = new QWidgetAction(menu);
1225   action->setEnabled(false);
1226 
1227   QLabel *label = new QLabel(tr("%1 Menu", "title of menu for object type arg1").arg(typeName()), menu);
1228   label->setAlignment(Qt::AlignCenter);
1229   label->setStyleSheet("QLabel {"
1230                        "border-bottom: 2px solid lightGray;"
1231                        "font: bold large;"
1232                        "padding: 3px;"
1233                        "margin: 1px;"
1234                        "}");
1235   action->setDefaultWidget(label);
1236   menu->addAction(action);
1237 }
1238 
1239 
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)1240 void ViewItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
1241   QMenu menu;
1242 
1243   addTitle(&menu);
1244 
1245 
1246   //if (!(lockParent() || (parentViewItem() && parentViewItem()->lockParent()))) {
1247   QMenu *layoutMenu = menu.addMenu(tr("Cleanup Layout"));
1248   layoutMenu->setTitle(tr("Cleanup Layout"));
1249   layoutMenu->addAction(_autoLayoutAction);
1250   //layoutMenu->addAction(_protectedLayoutAction);
1251   layoutMenu->addAction(_customLayoutAction);
1252   layoutMenu->addAction(_oneColumnLayoutAction);
1253   layoutMenu->addAction(_twoColumnLayoutAction);
1254   layoutMenu->addAction(_threeColumnLayoutAction);
1255   //}
1256 
1257   menu.addAction(_editAction);
1258 
1259   addToMenuForContextEvent(menu);
1260 
1261   menu.addSeparator();
1262 
1263   if (!(lockParent() || (parentViewItem() && parentViewItem()->lockParent()))) {
1264     menu.addAction(_raiseAction);
1265     menu.addAction(_lowerAction);
1266     menu.addAction(_deleteAction);
1267   }
1268 
1269   if (dataPosLockable()) {
1270     menu.addSeparator();
1271     menu.addAction(_lockPosToDataAction);
1272   }
1273 
1274 
1275   menu.exec(event->screenPos());
1276 }
1277 
dataPosLockable() const1278 bool ViewItem::dataPosLockable() const {
1279   return bool(dynamic_cast<PlotRenderItem *>(parentViewItem()));
1280 }
1281 
addToMenuForContextEvent(QMenu & menu)1282 void ViewItem::addToMenuForContextEvent(QMenu &menu) {
1283   Q_UNUSED(menu);
1284 }
1285 
startDragging(QWidget * widget,const QPointF & hotspot)1286 void ViewItem::startDragging(QWidget *widget, const QPointF& hotspot) {
1287 
1288   QPointF old_topleft = rect().topLeft();
1289   normalizePosition();
1290   QPointF new_hotspot = hotspot.toPoint() + rect().topLeft() - old_topleft;
1291 
1292   // UNDO tied zoom settings done in PlotItem::mousePressEvent
1293   setTiedZoom(false, false);
1294 
1295   QDrag *drag = new QDrag(widget);
1296   MimeDataViewItem* mimeData = new MimeDataViewItem;
1297   mimeData->item = this;
1298   mimeData->hotSpot = new_hotspot;
1299 
1300   qreal theta = rotationAngle()*ONE_PI/180.0;
1301   qreal w = fabs(rect().width()*cos(theta)) + fabs(rect().height()*sin(theta));
1302   qreal h = fabs(rect().width()*sin(theta)) + fabs(rect().height()*cos(theta));
1303 
1304 #ifdef QT5
1305   int device_pixel_ratio = view()->devicePixelRatio();
1306 #else
1307   int device_pixel_ratio = 1;
1308 #endif
1309 
1310   QPixmap pixmap(device_pixel_ratio*(w+2), device_pixel_ratio*(h+2));
1311 
1312 #ifdef QT5
1313   pixmap.setDevicePixelRatio(device_pixel_ratio);
1314 #endif
1315 
1316   if (ApplicationSettings::self()->transparentDrag()) {
1317     pixmap.fill(Qt::transparent);
1318   } else {
1319     //pixmap.fill(brush().color());
1320     pixmap.fill(view()->backgroundBrush().color());
1321   }
1322   QPainter painter(&pixmap);
1323 
1324   qreal x1 = -rect().height()*sin(theta);
1325   qreal x3 = rect().width()*cos(theta);
1326   qreal x2 = x1+x3;
1327   qreal dx;
1328 
1329   dx = qMin(qreal(0.0), x1);
1330   dx = qMin(x2,dx);
1331   dx = qMin(x3,dx);
1332 
1333   qreal y1 = rect().height()*cos(theta);
1334   qreal y3 = rect().width()*sin(theta);
1335   qreal y2 = y1+y3;
1336   qreal dy;
1337 
1338   dy = qMin(qreal(0.0), y1);
1339   dy = qMin(y2,dy);
1340   dy = qMin(y3,dy);
1341 
1342   painter.translate(-dx,-dy);
1343   painter.rotate(rotationAngle());
1344   painter.translate(-rect().left(), -rect().top());
1345 
1346   painter.setPen(pen());
1347   //painter.setBrush(brush());
1348 
1349   QBrush brush_hold = brush();
1350   setBrush(Qt::NoBrush);
1351   paint(&painter);
1352   setBrush(brush_hold);
1353 
1354   // TODO also paint annotations
1355   paintChildItems(painter);
1356   painter.end();
1357 
1358   drag->setPixmap(pixmap);
1359   mimeData->setImageData(pixmap.toImage());
1360   drag->setMimeData(mimeData);
1361 
1362   qreal hx = new_hotspot.toPoint().x()-rect().left();
1363   qreal hy = new_hotspot.toPoint().y()-rect().top();
1364   qreal hx_r = hx * cos(theta) - hy * sin(theta);
1365   qreal hy_r = hy * cos(theta) + hx * sin(theta);
1366   drag->setHotSpot(QPoint(hx_r-dx,hy_r-dy));
1367 
1368   dropHotSpot = QPoint(hx_r-dx-w/2-1,hy_r-dy-h/2-1);
1369 
1370   hide();
1371   Qt::DropActions dact = Qt::MoveAction;
1372   Qt::DropAction dropAction = drag->exec(dact);
1373   if (dropAction != Qt::MoveAction) {
1374     show();
1375   }
1376   kstApp->mainWindow()->document()->setChanged(true);
1377 
1378 }
1379 
paintChildItems(QPainter & painter)1380 void ViewItem::paintChildItems(QPainter &painter) {
1381   QList<QGraphicsItem*> children = childItems();
1382   foreach(QGraphicsItem* child, children) {
1383     ViewItem* item = dynamic_cast<ViewItem*>(child);
1384     if (item) {
1385       painter.save();
1386       painter.translate(item->pos().x(),
1387                         item->pos().y());
1388       painter.rotate(item->rotationAngle());
1389       item->paint(&painter);
1390       item->paintChildItems(painter);
1391       painter.restore();
1392     }
1393   }
1394 
1395 }
1396 
mouseMoveEvent(QGraphicsSceneMouseEvent * event)1397 void ViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
1398   if (view()->viewMode() == View::Data) {
1399     event->ignore();
1400     return;
1401   }
1402 
1403 #ifdef KST_ENABLE_DD
1404   if (!dragStartPosition.isNull() && event->buttons() & Qt::LeftButton) {
1405     if (view()->mouseMode() == View::Move) {
1406       startDragging(event->widget(), dragStartPosition.toPoint());
1407       return;
1408     }
1409   }
1410 #endif
1411 
1412   if (view()->mouseMode() == View::Default) {
1413     if (gripMode() == ViewItem::Move || activeGrip() == NoGrip) {
1414       view()->setMouseMode(View::Move);
1415       view()->undoStack()->beginMacro(tr("Move"));
1416     } else if (gripMode() == ViewItem::Resize) {
1417       view()->setMouseMode(View::Resize);
1418       view()->undoStack()->beginMacro(tr("Resize"));
1419     } else if (gripMode() == ViewItem::Scale) {
1420       view()->setMouseMode(View::Scale);
1421       view()->undoStack()->beginMacro(tr("Scale"));
1422     } else if (gripMode() == ViewItem::Rotate) {
1423       view()->setMouseMode(View::Rotate);
1424       view()->undoStack()->beginMacro(tr("Rotate"));
1425     }
1426   }
1427 
1428   if (activeGrip() == NoGrip)
1429     return QGraphicsRectItem::mouseMoveEvent(event);
1430 
1431   QPointF p = event->pos();
1432   QPointF s = event->scenePos();
1433 
1434   if (gripMode() == ViewItem::Rotate) {
1435     switch(_activeGrip) {
1436     case TopLeftGrip:
1437         rotateTowards(topLeftGrip().controlPointRect().center(), p); break;
1438     case TopRightGrip:
1439         rotateTowards(topRightGrip().controlPointRect().center(), p); break;
1440     case BottomRightGrip:
1441         rotateTowards(bottomRightGrip().controlPointRect().center(), p); break;
1442     case BottomLeftGrip:
1443         rotateTowards(bottomLeftGrip().controlPointRect().center(), p); break;
1444     case TopMidGrip:
1445         rotateTowards(topMidGrip().controlPointRect().center(), p); break;
1446     case RightMidGrip:
1447         rotateTowards(rightMidGrip().controlPointRect().center(), p); break;
1448     case BottomMidGrip:
1449         rotateTowards(bottomMidGrip().controlPointRect().center(), p); break;
1450     case LeftMidGrip:
1451         rotateTowards(leftMidGrip().controlPointRect().center(), p); break;
1452     case NoGrip:
1453       break;
1454     }
1455   } else if (gripMode() == ViewItem::Resize) {
1456 
1457     switch(_activeGrip) {
1458     case TopLeftGrip:
1459         resizeTopLeft(p - topLeftGrip().controlPointRect().center()); break;
1460     case TopRightGrip:
1461         resizeTopRight(p - topRightGrip().controlPointRect().center()); break;
1462     case BottomRightGrip:
1463         resizeBottomRight(p - bottomRightGrip().controlPointRect().center()); break;
1464     case BottomLeftGrip:
1465         resizeBottomLeft(p - bottomLeftGrip().controlPointRect().center()); break;
1466     case TopMidGrip:
1467         resizeTop(p.y() - topMidGrip().controlPointRect().center().y()); break;
1468     case RightMidGrip:
1469         resizeRight(p.x() - rightMidGrip().controlPointRect().center().x()); break;
1470     case BottomMidGrip:
1471         resizeBottom(p.y() - bottomMidGrip().controlPointRect().center().y()); break;
1472     case LeftMidGrip:
1473         resizeLeft(p.x() - leftMidGrip().controlPointRect().center().x()); break;
1474     case NoGrip:
1475       break;
1476     }
1477 
1478   } else if (gripMode() == ViewItem::Scale) {
1479 
1480     switch(_activeGrip) {
1481     case TopLeftGrip:
1482         setTopLeft(s); break;
1483     case TopRightGrip:
1484         setTopRight(s); break;
1485     case BottomRightGrip:
1486         setBottomRight(s); break;
1487     case BottomLeftGrip:
1488         setBottomLeft(s); break;
1489     case TopMidGrip:
1490         setTop(s.y()); break;
1491     case RightMidGrip:
1492         setRight(s.x()); break;
1493     case BottomMidGrip:
1494         setBottom(s.y()); break;
1495     case LeftMidGrip:
1496         setLeft(s.x()); break;
1497     case NoGrip:
1498       break;
1499     }
1500   }
1501   updateRelativeSize(true);
1502 }
1503 
1504 
resizeTopLeft(const QPointF & offset)1505 void ViewItem::resizeTopLeft(const QPointF &offset) {
1506   const qreal oldAspect = rect().width() / rect().height();
1507 
1508   QRectF r = rect();
1509   QPointF o = _lockAspectRatio ? lockOffset(offset, oldAspect, false) : offset;
1510   r.setTopLeft(r.topLeft() + o);
1511   if (!r.isValid()) return;
1512 
1513   const qreal newAspect = r.width() / r.height();
1514   Q_ASSERT_X(_lockAspectRatio ? qFuzzyCompare(newAspect, oldAspect) : true,
1515               "lockAspect error", QString(QString::number(newAspect) + "!=" + QString::number(oldAspect)).toLatin1().constData());
1516   Q_UNUSED(newAspect);
1517   setViewRect(r);
1518 }
1519 
1520 
resizeTopRight(const QPointF & offset)1521 void ViewItem::resizeTopRight(const QPointF &offset) {
1522   const qreal oldAspect = rect().width() / rect().height();
1523 
1524   QRectF r = rect();
1525   QPointF o = _lockAspectRatio ? lockOffset(offset, oldAspect, true) : offset;
1526   r.setTopRight(r.topRight() + o);
1527   if (!r.isValid()) return;
1528 
1529   const qreal newAspect = r.width() / r.height();
1530   Q_ASSERT_X(_lockAspectRatio ? qFuzzyCompare(newAspect, oldAspect) : true,
1531               "lockAspect error", QString(QString::number(newAspect) + "!=" + QString::number(oldAspect)).toLatin1().constData());
1532   Q_UNUSED(newAspect);
1533   setViewRect(r);
1534 }
1535 
1536 
resizeBottomLeft(const QPointF & offset)1537 void ViewItem::resizeBottomLeft(const QPointF &offset) {
1538   const qreal oldAspect = rect().width() / rect().height();
1539 
1540   QRectF r = rect();
1541   QPointF o = _lockAspectRatio ? lockOffset(offset, oldAspect, true) : offset;
1542   r.setBottomLeft(r.bottomLeft() + o);
1543   if (!r.isValid()) return;
1544 
1545   const qreal newAspect = r.width() / r.height();
1546   Q_ASSERT_X(_lockAspectRatio ? qFuzzyCompare(newAspect, oldAspect) : true,
1547               "lockAspect error", QString(QString::number(newAspect) + "!=" + QString::number(oldAspect)).toLatin1().constData());
1548   Q_UNUSED(newAspect);
1549   setViewRect(r);
1550 }
1551 
1552 
resizeBottomRight(const QPointF & offset)1553 void ViewItem::resizeBottomRight(const QPointF &offset) {
1554   const qreal oldAspect = rect().width() / rect().height();
1555   QRectF r = rect();
1556   QPointF o = _lockAspectRatio ? lockOffset(offset, oldAspect, false) : offset;
1557   r.setBottomRight(r.bottomRight() + o);
1558   if (!r.isValid()) return;
1559 
1560   const qreal newAspect = r.width() / r.height();
1561   Q_ASSERT_X(_lockAspectRatio ? qFuzzyCompare(newAspect, oldAspect) : true,
1562               "lockAspect error", QString(QString::number(newAspect) + "!=" + QString::number(oldAspect)).toLatin1().constData());
1563   Q_UNUSED(newAspect);
1564   setViewRect(r);
1565 }
1566 
1567 
resizeTop(qreal offset)1568 void ViewItem::resizeTop(qreal offset) {
1569   QRectF r = rect();
1570   r.setTop(r.top() + offset);
1571   if (!r.isValid()) return;
1572   setViewRect(r);
1573 }
1574 
1575 
resizeBottom(qreal offset)1576 void ViewItem::resizeBottom(qreal offset) {
1577   QRectF r = rect();
1578   r.setBottom(r.bottom() + offset);
1579   if (!r.isValid()) return;
1580   setViewRect(r);
1581 }
1582 
1583 
resizeLeft(qreal offset)1584 void ViewItem::resizeLeft(qreal offset) {
1585   QRectF r = rect();
1586   r.setLeft(r.left() + offset);
1587   if (!r.isValid()) return;
1588   setViewRect(r);
1589 }
1590 
1591 
resizeRight(qreal offset)1592 void ViewItem::resizeRight(qreal offset) {
1593   QRectF r = rect();
1594   r.setRight(r.right() + offset);
1595   if (!r.isValid()) return;
1596   setViewRect(r);
1597 }
1598 
1599 
setTopLeft(const QPointF & point)1600 void ViewItem::setTopLeft(const QPointF &point) {
1601   QPointF p = point;
1602 
1603   QPointF anchor = selectTransform().map(rect().bottomRight());
1604 
1605   QRectF from = selectBoundingRect();
1606   QRectF to = from;
1607 
1608   to.setTopLeft(p);
1609   from.moveBottomRight(anchor);
1610   to.moveBottomRight(anchor);
1611   transformToRect(from, to);
1612 }
1613 
1614 
setTopRight(const QPointF & point)1615 void ViewItem::setTopRight(const QPointF &point) {
1616   QPointF p = point;
1617 
1618   QPointF anchor = selectTransform().map(rect().bottomLeft());
1619 
1620   QRectF from = selectBoundingRect();
1621   QRectF to = from;
1622 
1623   to.setTopRight(p);
1624   from.moveBottomLeft(anchor);
1625   to.moveBottomLeft(anchor);
1626   transformToRect(from, to);
1627 }
1628 
1629 
setBottomLeft(const QPointF & point)1630 void ViewItem::setBottomLeft(const QPointF &point) {
1631   QPointF p = point;
1632 
1633   QPointF anchor = selectTransform().map(rect().topRight());
1634 
1635   QRectF from = selectBoundingRect();
1636   QRectF to = from;
1637 
1638   to.setBottomLeft(p);
1639   from.moveTopRight(anchor);
1640   to.moveTopRight(anchor);
1641   transformToRect(from, to);
1642 }
1643 
1644 
setBottomRight(const QPointF & point)1645 void ViewItem::setBottomRight(const QPointF &point) {
1646   QPointF p = point;
1647 
1648   QPointF anchor = selectTransform().map(rect().topLeft());
1649 
1650   QRectF from = selectBoundingRect();
1651   QRectF to = from;
1652 
1653   to.setBottomRight(p);
1654   from.moveTopLeft(anchor);
1655   to.moveTopLeft(anchor);
1656   transformToRect(from, to);
1657 }
1658 
1659 
setTop(qreal y)1660 void ViewItem::setTop(qreal y) {
1661   QPointF anchor = selectTransform().map(rect().bottomLeft());
1662 
1663   QRectF from = selectBoundingRect();
1664   QRectF to = from;
1665 
1666   to.setTop(y);
1667   from.moveBottomLeft(anchor);
1668   to.moveBottomLeft(anchor);
1669   transformToRect(from, to);
1670 }
1671 
1672 
setBottom(qreal y)1673 void ViewItem::setBottom(qreal y) {
1674 
1675   QPointF anchor = selectTransform().map(rect().topLeft());
1676 
1677   QRectF from = selectBoundingRect();
1678   QRectF to = from;
1679 
1680   to.setBottom(y);
1681   from.moveTopLeft(anchor);
1682   to.moveTopLeft(anchor);
1683   transformToRect(from, to);
1684 }
1685 
1686 
setLeft(qreal x)1687 void ViewItem::setLeft(qreal x) {
1688 
1689   QPointF anchor = selectTransform().map(rect().topRight());
1690 
1691   QRectF from = selectBoundingRect();
1692   QRectF to = from;
1693 
1694   to.setLeft(x);
1695   from.moveTopRight(anchor);
1696   to.moveTopRight(anchor);
1697   transformToRect(from, to);
1698 }
1699 
1700 
setRight(qreal x)1701 void ViewItem::setRight(qreal x) {
1702 
1703   QPointF anchor = selectTransform().map(rect().topLeft());
1704 
1705   QRectF from = selectBoundingRect();
1706   QRectF to = from;
1707 
1708   to.setRight(x);
1709   from.moveTopLeft(anchor);
1710   to.moveTopLeft(anchor);
1711   transformToRect(from, to);
1712 }
1713 
1714 
selectTransform() const1715 QTransform ViewItem::selectTransform() const {
1716 
1717   /* Converts a point on the rect() to a point on the selectBoundingRect()
1718      or the inverse by using selectTransform().inverted().
1719   */
1720 
1721   QRectF from = rect();
1722   QRectF to = selectBoundingRect();
1723   QTransform rt = _rotationTransform.inverted(); //inverse rotation so far
1724 
1725   QPolygonF from_ = QPolygonF(rt.map(from));
1726   from_.pop_back(); //get rid of last closed point
1727 
1728   QPolygonF to_ = QPolygonF(mapFromScene(to));
1729   to_.pop_back(); //get rid of last closed point
1730 
1731   QTransform select;
1732   QTransform::quadToQuad(from_, to_, select);
1733 
1734   return _rotationTransform.inverted() * select * transform();
1735 }
1736 
1737 
transformToRect(const QRectF & from,const QRectF & to)1738 bool ViewItem::transformToRect(const QRectF &from, const QRectF &to) {
1739   //Not sure how to handle yet
1740   if (!to.isValid()) {
1741     return false;
1742   }
1743 
1744   QPolygonF from_(from);
1745   from_.pop_back(); //get rid of last closed point
1746   QPolygonF to_(to);
1747   to_.pop_back(); //get rid of last closed point
1748   return transformToRect(from_, to_);
1749 }
1750 
1751 
transformToRect(const QPolygonF & from,const QPolygonF & to)1752 bool ViewItem::transformToRect(const QPolygonF &from, const QPolygonF &to) {
1753 
1754   QTransform t;
1755   bool success = QTransform::quadToQuad(from, to, t);
1756 
1757   t = transform() * t;
1758 
1759   if (success) setTransform(t, false);
1760   return success;
1761 }
1762 
1763 
rotateTowards(const QPointF & corner,const QPointF & point)1764 void ViewItem::rotateTowards(const QPointF &corner, const QPointF &point) {
1765 
1766   QPointF origin = centerOfRotation();
1767   if (origin == corner || origin == point)
1768     return;
1769 
1770   _normalLine = QLineF(origin, corner);
1771   _rotationLine = QLineF(origin, point);
1772 
1773   qreal angle1 = ::acos(_normalLine.dx() / _normalLine.length());
1774   if (_normalLine.dy() >= 0)
1775       angle1 = TWO_PI - angle1;
1776 
1777   qreal angle2 = ::acos(_rotationLine.dx() / _rotationLine.length());
1778   if (_rotationLine.dy() >= 0)
1779       angle2 = TWO_PI - angle2;
1780 
1781   qreal angle = RAD2DEG * (angle1 - angle2);
1782 
1783   QTransform t;
1784   t.translate(origin.x(), origin.y());
1785   t.rotate(angle);
1786   t.translate(-origin.x(), -origin.y());
1787 
1788   _rotationTransform = t * _rotationTransform;
1789 
1790   setTransform(t, true);
1791 }
1792 
normalizePosition()1793 void ViewItem::normalizePosition() {
1794 
1795   qreal parentWidth = parentRect().width();
1796   qreal parentHeight = parentRect().height();
1797   qreal parentX = parentRect().x();
1798   qreal parentY = parentRect().y();
1799 
1800   qreal w = relativeWidth() * parentWidth;
1801   qreal h = relativeHeight() * parentHeight;
1802 
1803   setPos(parentX + relativeCenter().x()*parentWidth,
1804          parentY + relativeCenter().y()*parentHeight);
1805 
1806 
1807   setViewRect(-w/2, -h/2, w, h);
1808 
1809   QTransform transform;
1810   transform.rotate(rotationAngle());
1811 
1812   setTransform(transform);
1813   //updateRelativeSize();
1814   //updateViewItemParent();
1815 
1816 }
1817 
1818 
lockOffset(const QPointF & offset,qreal ratio,bool oddCorner) const1819 QPointF ViewItem::lockOffset(const QPointF &offset, qreal ratio, bool oddCorner) const {
1820   qreal x;
1821   qreal y;
1822   bool xKey;
1823 
1824   if (offset.x() < 0 && offset.y() > 0) {
1825     xKey = true;
1826     x = offset.x();
1827     y = x == 0 ? 0 : (1 / ratio) * x;
1828   } else if (offset.y() < 0 && offset.x() > 0) {
1829     xKey = false;
1830     y = offset.y();
1831     x = y == 0 ? 0 : ratio * y;
1832   } else if (qAbs(offset.x()) < qAbs(offset.y())) {
1833     xKey = true;
1834     x = offset.x();
1835     y = x == 0 ? 0 : (1 / ratio) * x;
1836   } else {
1837     xKey = false;
1838     y = offset.y();
1839     x = y == 0 ? 0 : ratio * y;
1840   }
1841 
1842   QPointF o = offset;
1843   if (oddCorner) {
1844     o = QPointF(!xKey ? -x : x,
1845                 xKey ? -y : y);
1846   } else {
1847     o = QPointF(x, y);
1848   }
1849 
1850   return o;
1851 }
1852 
1853 
updateViewItemParent(bool force_toplevel)1854 bool ViewItem::updateViewItemParent(bool force_toplevel) {
1855   if (lockParent() || skipNextParentCheck()) {
1856     setSkipNextParentCheck(false);
1857     return false;
1858   }
1859   //First get a list of all items that collide with this one
1860   QList<QGraphicsItem*> collisions = collidingItems(Qt::IntersectsItemShape);
1861 
1862   bool topLevel = !parentItem();
1863   QPointF origin = mapToScene(QPointF(0,0));
1864 
1865 #if DEBUG_REPARENT
1866   qDebug() << "updateViewItemParent" << this
1867            << "topLevel:" << (topLevel ? "true" : "false")
1868            << "origin:" << origin
1869            << "rect:" << rect()
1870            << "collision count:" << collisions.count();
1871 #endif
1872 
1873   //Doesn't collide then reparent to top-level
1874   if (collisions.isEmpty() && !topLevel) {
1875 #if DEBUG_REPARENT
1876     qDebug() << "reparent to topLevel";
1877 
1878     qDebug() << "before transform"
1879              << "origin:" << mapToScene(QPointF(0,0));
1880 #endif
1881 
1882     /*bring the old parent's transform with us*/
1883     setTransform(parentItem()->transform(), true);
1884 
1885 #if DEBUG_REPARENT
1886     qDebug() << "after transform"
1887              << "origin:" << mapToScene(QPointF(0,0));
1888 #endif
1889 
1890     setParentViewItem(0);
1891     setPos(mapToParent(mapFromScene(origin)) + pos() - mapToParent(QPointF(0,0)));
1892     updateRelativeSize();
1893 
1894 #if DEBUG_REPARENT
1895     qDebug() << "after new parent"
1896              << "origin:" << mapToScene(QPointF(0,0));
1897 #endif
1898 
1899     return true;
1900   }
1901 
1902   if (!force_toplevel) {
1903     //Look for collisions that completely contain us
1904     foreach (QGraphicsItem *item, collisions) {
1905       ViewItem *viewItem = dynamic_cast<ViewItem*>(item);
1906 
1907       if (!viewItem || !viewItem->acceptsChildItems() || isAncestorOf(viewItem) || !collidesWithItem(viewItem, Qt::ContainsItemBoundingRect)) {
1908 #if DEBUG_REPARENT
1909         qDebug() << "rejecting collision" << viewItem << !viewItem->acceptsChildItems() <<
1910                     isAncestorOf(viewItem) << !collidesWithItem(viewItem, Qt::ContainsItemBoundingRect);
1911 #endif
1912         continue;
1913       }
1914 
1915       if (parentItem() == viewItem) { /*already done*/
1916 #if DEBUG_REPARENT
1917         qDebug() << "already in containing parent";
1918 #endif
1919         return false;
1920       }
1921 
1922 #if DEBUG_REPARENT
1923       qDebug() << "reparent to" << viewItem;
1924 
1925       qDebug() << "before transform"
1926                << "origin:" << mapToScene(QPointF(0,0));
1927 #endif
1928 
1929       if (!topLevel) { /*bring the old parent's transform with us*/
1930         setTransform(parentItem()->transform(), true);
1931       }
1932 
1933       /*cancel out the new parent's initial transform*/
1934       setTransform(viewItem->transform().inverted(), true);
1935 
1936 #if DEBUG_REPARENT
1937       qDebug() << "after transform"
1938                << "origin:" << mapToScene(QPointF(0,0));
1939 #endif
1940 
1941       setParentViewItem(viewItem);
1942       setPos(mapToParent(mapFromScene(origin)) + pos() - mapToParent(QPointF(0,0)));
1943       updateRelativeSize(true);
1944 
1945 #if DEBUG_REPARENT
1946       qDebug() << "after new parent"
1947                << "origin:" << mapToScene(QPointF(0,0));
1948 #endif
1949 
1950       return true;
1951     }
1952   }
1953   //No suitable collisions then reparent to top-level
1954   if (!topLevel) {
1955 #if DEBUG_REPARENT
1956     qDebug() << "reparent to topLevel";
1957 
1958     qDebug() << "before transform"
1959              << "origin:" << mapToScene(QPointF(0,0));
1960 #endif
1961 
1962     /*bring the old parent's transform with us*/
1963     setTransform(parentItem()->transform(), true);
1964 
1965 #if DEBUG_REPARENT
1966     qDebug() << "after transform"
1967              << "origin:" << mapToScene(QPointF(0,0));
1968 #endif
1969 
1970     setParentViewItem(0);
1971     setPos(mapToParent(mapFromScene(origin)) + pos() - mapToParent(QPointF(0,0)));
1972     updateRelativeSize();
1973 
1974 #if DEBUG_REPARENT
1975     qDebug() << "after new parent"
1976              << "origin:" << mapToScene(QPointF(0,0));
1977 #endif
1978 
1979     return true;
1980   }
1981   return false;
1982 }
1983 
1984 
updateDataRelativeRect(bool force)1985 void ViewItem::updateDataRelativeRect(bool force) {
1986   CartesianRenderItem* plot = dynamic_cast<CartesianRenderItem*>(parentViewItem());
1987   if (plot) {
1988     if ((!lockPosToData()) || force) {
1989       qreal rotation = rotationAngle();
1990       QTransform transform;
1991       setTransform(transform);
1992       QPointF top_left = mapToParent(rect().topLeft());
1993       QPointF bottom_right = mapToParent(rect().bottomRight());
1994       QRectF localRect(top_left, bottom_right);
1995       _dataRelativeRect = plot->plotItem()->mapToProjection(localRect);
1996       transform.rotate(rotation);
1997       setTransform(transform);
1998     }
1999   }
2000 }
2001 
updateRelativeSize(bool force_data)2002 void ViewItem::updateRelativeSize(bool force_data) {
2003   if (parentViewItem()) {
2004     QPointF P;
2005     qreal parentHeight = parentViewItem()->height() == 0 ? 1 : parentViewItem()->height();
2006     qreal parentWidth  = parentViewItem()->width() == 0 ? 1 : parentViewItem()->width();
2007     _parentRelativeHeight = (height() / parentHeight);
2008     _parentRelativeWidth = (width() / parentWidth);
2009 
2010     P =  mapToParent(rect().center()) - parentViewItem()->rect().topLeft();
2011     _parentRelativeCenter =  QPointF(P.x() / parentWidth,
2012                                      P.y() / parentHeight);
2013     P =  mapToParent(rect().topLeft()) - parentViewItem()->rect().topLeft();
2014     _parentRelativePosition =  QPointF(P.x() / parentWidth,
2015                                        P.y() / parentHeight);
2016     P =  mapToParent(rect().bottomLeft()) - parentViewItem()->rect().topLeft();
2017     _parentRelativeLeft = QPointF(P.x() / parentWidth,
2018                                       P.y() / parentHeight);
2019     P =  mapToParent(rect().bottomRight()) - parentViewItem()->rect().topLeft();
2020     _parentRelativeRight =  QPointF(P.x() / parentWidth,
2021                                     P.y() / parentHeight);
2022     updateDataRelativeRect(force_data);
2023    } else if (view()) {
2024     QPointF P;
2025     _parentRelativeHeight = (height() / view()->height());
2026     _parentRelativeWidth = (width() / view()->width());
2027     P =  mapToParent(rect().center()) - view()->rect().topLeft();
2028     _parentRelativeCenter =  QPointF(P.x() / view()->width(),
2029                                      P.y() / view()->height());
2030     P =  mapToParent(rect().topLeft()) - view()->rect().topLeft();
2031     _parentRelativePosition =  QPointF(P.x() / view()->width(),
2032                                        P.y() / view()->height());
2033     P =  mapToParent(rect().bottomLeft()) - view()->rect().topLeft();
2034     _parentRelativeLeft =  QPointF(P.x() / view()->width(),
2035                                    P.y() / view()->height());
2036     P =  mapToParent(rect().bottomRight()) - view()->rect().topLeft();
2037     _parentRelativeRight =  QPointF(P.x() / view()->width(),
2038                                    P.y() / view()->height());
2039   } else {
2040     _parentRelativeHeight = 0;
2041     _parentRelativeWidth = 0;
2042     _parentRelativeCenter = QPointF(0, 0);
2043     _parentRelativePosition = QPointF(0, 0);
2044     _parentRelativeLeft = QPointF(0, 0);
2045     _parentRelativeRight = QPointF(0, 0);
2046   }
2047 
2048   emit relativeSizeUpdated();
2049 }
2050 
2051 
updateChildGeometry(const QRectF & oldParentRect,const QRectF & newParentRect)2052 void ViewItem::updateChildGeometry(const QRectF &oldParentRect, const QRectF &newParentRect) {
2053   Q_UNUSED(oldParentRect);
2054 
2055   QRectF itemRect = rect();
2056   //Lock aspect ratio for rotating objects or children with a lockedAspectRatio
2057   //FIXME is the child rotated with respect to the parent is the real question...
2058   if (transform().isRotating() || lockAspectRatio()) {
2059     if (!_fixedSize) {
2060       qreal newHeight = relativeHeight() * newParentRect.height();
2061       qreal newWidth = relativeWidth() * newParentRect.width();
2062 
2063       qreal aspectRatio = rect().width() / rect().height();
2064       if ((newWidth / newHeight) > aspectRatio) {
2065         // newWidth is too large.  Use newHeight as key.
2066         newWidth = newHeight * aspectRatio;
2067       } else {
2068         // newHeight is either too large, or perfect.  use newWidth as key.
2069         newHeight = newWidth / aspectRatio;
2070       }
2071       itemRect.setBottom(itemRect.top() + newHeight);
2072       itemRect.setRight(itemRect.left() + newWidth);
2073     }
2074     QPointF newCenter = newParentRect.topLeft() + QPointF(newParentRect.width() * _parentRelativeCenter.x(), newParentRect.height() * _parentRelativeCenter.y());
2075 
2076     QRectF r = itemRect;
2077     r.moveCenter(mapFromParent(newCenter));
2078 
2079     QPointF centerOffset = mapToParent(r.topLeft()) - mapToParent(itemRect.topLeft());
2080     setPos(pos() + centerOffset);
2081   } else {
2082     qreal newHeight = relativeHeight() * newParentRect.height();
2083     qreal newWidth = relativeWidth() * newParentRect.width();
2084 
2085     QPointF newTopLeft = newParentRect.topLeft() - itemRect.topLeft() +
2086                          QPointF(newParentRect.width() * _parentRelativePosition.x(),
2087                                  newParentRect.height() * _parentRelativePosition.y());
2088 
2089     itemRect.setWidth(newWidth);
2090     itemRect.setHeight(newHeight);
2091     setPos(newTopLeft);
2092   }
2093 
2094   setViewRect(itemRect, true);
2095 }
2096 
2097 
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)2098 void ViewItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
2099   if (view()->viewMode() == View::Data) {
2100     event->ignore();
2101     return;
2102   }
2103 }
2104 
2105 
mousePressEvent(QGraphicsSceneMouseEvent * event)2106 void ViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
2107   if (view()->viewMode() == View::Data) {
2108     event->ignore();
2109     return;
2110   }
2111 
2112   const QPointF p = event->pos();
2113 
2114   dragStartPosition = p;
2115 
2116   if (isAllowed(TopLeftGrip) && topLeftGrip().contains(p)) {
2117     setActiveGrip(TopLeftGrip);
2118   } else if (isAllowed(TopRightGrip) && topRightGrip().contains(p)) {
2119     setActiveGrip(TopRightGrip);
2120   } else if (isAllowed(BottomRightGrip) && bottomRightGrip().contains(p)) {
2121     setActiveGrip(BottomRightGrip);
2122   } else if (isAllowed(BottomLeftGrip) && bottomLeftGrip().contains(p)) {
2123     setActiveGrip(BottomLeftGrip);
2124   } else if (isAllowed(TopMidGrip) && topMidGrip().contains(p)) {
2125     setActiveGrip(TopMidGrip);
2126   } else if (isAllowed(RightMidGrip) && rightMidGrip().contains(p)) {
2127     setActiveGrip(RightMidGrip);
2128   } else if (isAllowed(BottomMidGrip) && bottomMidGrip().contains(p)) {
2129     setActiveGrip(BottomMidGrip);
2130   } else if (isAllowed(LeftMidGrip) && leftMidGrip().contains(p)) {
2131     setActiveGrip(LeftMidGrip);
2132   } else {
2133     setActiveGrip(NoGrip);
2134   }
2135 
2136   if (!grips().contains(event->pos()) && event->button() & Qt::LeftButton) {
2137     setGripMode(nextGripMode(_gripMode));
2138   }
2139 
2140   QGraphicsRectItem::mousePressEvent(event);
2141 }
2142 
2143 
nextGripMode(GripMode currentMode) const2144 ViewItem::GripMode ViewItem::nextGripMode(GripMode currentMode) const {
2145   if (!(_allowedGripModes & (Resize | Rotate | Scale)))
2146     return currentMode;
2147 
2148   switch (currentMode) {
2149   case Move:
2150     if (isAllowed(Resize))
2151       return Resize;
2152     else
2153       return nextGripMode(Resize);
2154     break;
2155   case Resize:
2156     if (isAllowed(Scale))
2157       return Scale;
2158     else
2159       return nextGripMode(Scale);
2160     break;
2161   case Scale:
2162     if (isAllowed(Rotate))
2163       return Rotate;
2164     else
2165       return nextGripMode(Rotate);
2166     break;
2167   case Rotate:
2168     if (isAllowed(Resize))
2169       return Resize;
2170     else
2171       return nextGripMode(Resize);
2172     break;
2173   default:
2174     break;
2175   }
2176 
2177   return currentMode;
2178 }
2179 
2180 
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)2181 void ViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
2182   if (view()->viewMode() == View::Data) {
2183     event->ignore();
2184     return;
2185   }
2186 
2187   dragStartPosition = QPointF(0, 0);
2188 
2189   if (view()->mouseMode() != View::Default) {
2190     view()->setMouseMode(View::Default);
2191     view()->undoStack()->endMacro();
2192   }
2193   kstApp->mainWindow()->document()->setChanged(true);
2194 
2195   QGraphicsRectItem::mouseReleaseEvent(event);
2196 }
2197 
2198 
hoverMoveEvent(QGraphicsSceneHoverEvent * event)2199 void ViewItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
2200   QGraphicsRectItem::hoverMoveEvent(event);
2201   if (view()->viewMode() == View::Data) {
2202     return;
2203   }
2204   if (isSelected()) {
2205     QPointF p = event->pos();
2206     if ((isAllowed(TopLeftGrip) && topLeftGrip().contains(p)) || (isAllowed(BottomRightGrip) && bottomRightGrip().contains(p))) {
2207       if (gripMode() == ViewItem::Rotate) {
2208         view()->setCursor(Qt::CrossCursor);
2209       } else if (gripMode() == ViewItem::Resize) {
2210         view()->setCursor(Qt::SizeFDiagCursor);
2211       }
2212     } else if ((isAllowed(TopRightGrip) && topRightGrip().contains(p)) || (isAllowed(BottomLeftGrip) && bottomLeftGrip().contains(p))) {
2213       if (gripMode() == ViewItem::Rotate) {
2214         view()->setCursor(Qt::CrossCursor);
2215       } else if (gripMode() == ViewItem::Resize) {
2216         view()->setCursor(Qt::SizeBDiagCursor);
2217       }
2218     } else if ((isAllowed(TopMidGrip) && topMidGrip().contains(p)) || (isAllowed(BottomMidGrip) && bottomMidGrip().contains(p))) {
2219       if (gripMode() == ViewItem::Rotate) {
2220         view()->setCursor(Qt::CrossCursor);
2221       } else if (gripMode() == ViewItem::Resize) {
2222         view()->setCursor(Qt::SizeVerCursor);
2223       }
2224     } else if ((isAllowed(RightMidGrip) && rightMidGrip().contains(p)) || (isAllowed(LeftMidGrip) && leftMidGrip().contains(p))) {
2225       if (gripMode() == ViewItem::Rotate) {
2226         view()->setCursor(Qt::CrossCursor);
2227       } else if (gripMode() == ViewItem::Resize) {
2228         view()->setCursor(Qt::SizeHorCursor);
2229       }
2230     } else {
2231       view()->setCursor(Qt::SizeAllCursor);
2232     }
2233   } else {
2234     //view()->setCursor(Qt::SizeAllCursor);
2235   }
2236 }
2237 
2238 
hoverEnterEvent(QGraphicsSceneHoverEvent * event)2239 void ViewItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
2240   QGraphicsRectItem::hoverMoveEvent(event);
2241   _hovering = true;
2242   update();
2243 }
2244 
2245 
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)2246 void ViewItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
2247   QGraphicsRectItem::hoverMoveEvent(event);
2248   //view()->setCursor(Qt::ArrowCursor);
2249 
2250   _hovering = false;
2251   update();
2252 }
2253 
2254 
itemChange(GraphicsItemChange change,const QVariant & value)2255 QVariant ViewItem::itemChange(GraphicsItemChange change, const QVariant &value)
2256 {
2257   if (change == ItemSelectedChange) {
2258     bool selected = value.toBool();
2259     if (!selected) {
2260       setGripMode(ViewItem::Move);
2261       update();
2262     }
2263   }
2264 
2265   return QGraphicsItem::itemChange(change, value);
2266 }
2267 
moveTo(const QPointF & pos)2268 void ViewItem::moveTo(const QPointF& pos)
2269 {
2270   QPointF newpos = view()->snapPoint(pos);
2271 
2272   if (parentViewItem()) {
2273     newpos -= parentViewItem()->scenePos();
2274   }
2275 
2276   setPos(newpos);
2277   new MoveCommand(this, _originalPosition, pos);
2278   updateViewItemParent();
2279   updateRelativeSize(true);
2280 }
2281 
setItemPos(qreal x,qreal y)2282 void ViewItem::setItemPos(qreal x, qreal y)
2283 {
2284   if (_lockPosToData) {
2285     QRectF dr = dataRelativeRect();
2286     dr.moveCenter(QPointF(x,y));
2287     setDataRelativeRect(dr);
2288     applyDataLockedDimensions();
2289   } else {
2290     QRectF parent_rect = parentRect();
2291     qreal parentWidth = parent_rect.width();
2292     qreal parentHeight = parent_rect.height();
2293     qreal parentX = parent_rect.x();
2294     qreal parentY = parent_rect.y();
2295 
2296     x = x*parentWidth + parentX;
2297     y = y*parentHeight + parentY;
2298 
2299     setPos(x,y);
2300   }
2301 }
2302 
setItemSize(qreal w,qreal h)2303 void ViewItem::setItemSize(qreal w, qreal h)
2304 {
2305   if (_lockPosToData) {
2306     QRectF dr = dataRelativeRect();
2307     QPointF center = dr.center();
2308     dr.setWidth(w);
2309     if (h>0) {
2310       dr.setHeight(h);
2311     }
2312     dr.moveCenter(center);
2313     setDataRelativeRect(dr);
2314     applyDataLockedDimensions();
2315   } else {
2316     QRectF parent_rect = parentRect();
2317     qreal parentWidth = parent_rect.width();
2318     qreal parentHeight = parent_rect.height();
2319 
2320     qreal width = w * parentWidth;
2321     qreal height;
2322 
2323     if (lockAspectRatio()) {
2324       qreal aspectRatio;
2325       if (rect().width() > 0) {
2326         aspectRatio = qreal(rect().height()) / qreal(rect().width());
2327       } else {
2328         aspectRatio = 10000.0;
2329       }
2330       height = width * aspectRatio;
2331     } else  if (h < 0.0) {
2332       height = rect().height();
2333     } else {
2334       height = h * parentHeight;
2335     }
2336 
2337     setViewRect(-width/2, -height/2, width, height);
2338   }
2339 }
2340 
viewMouseModeChanged(View::MouseMode oldMode)2341 void ViewItem::viewMouseModeChanged(View::MouseMode oldMode) {
2342   if (view()->mouseMode() == View::Move) {
2343     _originalPosition = pos();
2344   } else if (view()->mouseMode() == View::Resize ||
2345              view()->mouseMode() == View::Scale ||
2346              view()->mouseMode() == View::Rotate) {
2347     _originalRect = rect();
2348     _originalTransform = transform();
2349   } else if (oldMode == View::Move && _originalPosition != pos()) {
2350 #ifndef KST_ENABLE_DD
2351     moveTo(pos());
2352 #endif
2353   } else if (oldMode == View::Resize && _originalRect != rect()) {
2354     new ResizeCommand(this, _originalRect, rect());
2355     updateViewItemParent();
2356   } else if (oldMode == View::Scale && _originalTransform != transform()) {
2357     new ScaleCommand(this, _originalTransform, transform());
2358 
2359     updateViewItemParent();
2360   } else if (oldMode == View::Rotate && _originalTransform != transform()) {
2361     new RotateCommand(this, _originalTransform, transform());
2362 
2363     updateViewItemParent();
2364   }
2365 }
2366 
2367 
registerShortcut(QAction * action)2368 void ViewItem::registerShortcut(QAction *action) {
2369   Q_ASSERT(action->parent() == this);
2370   view()->grabShortcut(action->shortcut());
2371   _shortcutMap.insert(action->shortcut(), action);
2372 }
2373 
2374 
reRegisterShortcut()2375 void ViewItem::reRegisterShortcut() {
2376   QHashIterator<QString, QAction*> it(_shortcutMap);
2377   while (it.hasNext()) {
2378     it.next();
2379     view()->grabShortcut(it.key());
2380   }
2381 }
2382 
2383 
tryShortcut(const QString & shortcut)2384 bool ViewItem::tryShortcut(const QString &shortcut) {
2385   if (!_shortcutMap.contains(shortcut))
2386     return false;
2387 
2388   QAction *action = _shortcutMap.value(shortcut);
2389   if (!action->isEnabled())
2390     return false;
2391 
2392   action->trigger();
2393   return true;
2394 }
2395 
2396 
checkBox() const2397 QPainterPath ViewItem::checkBox() const {
2398   QRectF bound = selectBoundingRect();
2399   QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width() * 1.25, sizeOfGrip().height() * -.25), sizeOfGrip());
2400   QPainterPath path;
2401   path.addEllipse(grip);
2402   return path;
2403 }
2404 
2405 
tiedZoomCheck() const2406 QPainterPath ViewItem::tiedZoomCheck() const {
2407   QRectF bound = selectBoundingRect();
2408   QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width() * 1.25, sizeOfGrip().height() * -.25), sizeOfGrip());
2409   QPainterPath path;
2410   if (isXTiedZoom() && isYTiedZoom()) {
2411     path.addEllipse(grip);
2412   } else if (isXTiedZoom()) {
2413     path.moveTo(grip.center());
2414     path.arcTo(grip, 225, 180);
2415   } else if (isYTiedZoom()) {
2416     path.moveTo(grip.center());
2417     path.arcTo(grip, 45, 180);
2418   }
2419   return path;
2420 }
2421 
2422 
updateView()2423 void ViewItem::updateView() {
2424   update();
2425 }
2426 
2427 
rotationAngle() const2428 qreal ViewItem::rotationAngle() const {
2429   return 180.0/ONE_PI * atan2(transform().m12(), transform().m11());
2430 }
2431 
2432 
rotationAngleRadians() const2433 qreal ViewItem::rotationAngleRadians() const {
2434   return atan2(transform().m12(), transform().m11());
2435 }
2436 
2437 
setSupportsTiedZoom(const bool supports)2438 void ViewItem::setSupportsTiedZoom(const bool supports) {
2439   if (supports != _supportsTiedZoom) {
2440 
2441     _supportsTiedZoom = supports;
2442 
2443     if (_supportsTiedZoom && ((layoutMargins().width() < tiedZoomSize().width()) || (layoutMargins().height() < tiedZoomSize().height()))) {
2444       setLayoutMargins(layoutMargins().expandedTo(tiedZoomSize()));
2445     }
2446 
2447     if (!_supportsTiedZoom) {
2448       setTiedZoom(false, false, false);
2449     }
2450   }
2451 }
2452 
2453 
setTiedZoom(bool tiedXZoom,bool tiedYZoom,bool checkAllTied)2454 void ViewItem::setTiedZoom(bool tiedXZoom, bool tiedYZoom, bool checkAllTied) {
2455   Q_UNUSED(checkAllTied)
2456   if ((_isXTiedZoom == tiedXZoom) && (_isYTiedZoom == tiedYZoom))
2457     return;
2458 
2459   bool wasTiedZoom = isTiedZoom();
2460 
2461   _isXTiedZoom = tiedXZoom;
2462   _isYTiedZoom = tiedYZoom;
2463 
2464   if (isTiedZoom() && !wasTiedZoom) {
2465     PlotItemManager::self()->addTiedZoomViewItem(this);
2466   } else if (!isTiedZoom() && wasTiedZoom) {
2467     PlotItemManager::self()->removeTiedZoomViewItem(this);
2468   }
2469 
2470   //FIXME ugh, this is expensive, but need to redraw the checkboxes...
2471   update();
2472 }
2473 
_automaticDescriptiveName() const2474 QString ViewItem::_automaticDescriptiveName() const {
2475   return typeName();
2476 }
2477 
descriptionTip() const2478 QString ViewItem::descriptionTip() const {
2479   return typeName();
2480 }
2481 
createScriptInterface()2482 ScriptInterface* ViewItem::createScriptInterface() {
2483   return new ViewItemSI(this);
2484 }
2485 
scriptInterface()2486 ScriptInterface* ViewItem::scriptInterface() {
2487   if (!_interface) {
2488     _interface = createScriptInterface();
2489   }
2490   return _interface;
2491 }
2492 
2493 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,ViewItem * viewItem)2494 QDebug operator<<(QDebug dbg, ViewItem *viewItem) {
2495     dbg.nospace() << viewItem->typeName();
2496     return dbg.space();
2497 }
2498 #endif
2499 
2500 
ViewItemCommand(ViewItem * item,const QString & text,bool addToStack,QUndoCommand * parent)2501 ViewItemCommand::ViewItemCommand(ViewItem *item, const QString &text, bool addToStack, QUndoCommand *parent)
2502     : QUndoCommand(text, parent), _item(item) {
2503   if (addToStack)
2504     _item->view()->undoStack()->push(this);
2505 }
2506 
2507 
~ViewItemCommand()2508 ViewItemCommand::~ViewItemCommand() {
2509 }
2510 
2511 
2512 
CreateCommand(const QString & text,QUndoCommand * parent)2513 CreateCommand::CreateCommand(const QString &text, QUndoCommand *parent)
2514     : ViewCommand(text, false, parent) {
2515 }
2516 
2517 
CreateCommand(View * view,const QString & text,QUndoCommand * parent)2518 CreateCommand::CreateCommand(View *view, const QString &text, QUndoCommand *parent)
2519     : ViewCommand(view, text, false, parent) {
2520 }
2521 
2522 
~CreateCommand()2523 CreateCommand::~CreateCommand() {
2524 }
2525 
2526 
undo()2527 void CreateCommand::undo() {
2528   Q_ASSERT(_item);
2529   _item->hide();
2530 }
2531 
2532 
redo()2533 void CreateCommand::redo() {
2534   Q_ASSERT(_item);
2535   _item->show();
2536 }
2537 
2538 
createItem()2539 void CreateCommand::createItem() {
2540   Q_ASSERT(_item);
2541   Q_ASSERT(_view);
2542 
2543   _view->setMouseMode(View::Create);
2544 
2545   //If the mouseMode is changed again before we're done with creation
2546   //delete ourself.
2547   connect(_view, SIGNAL(mouseModeChanged(View::MouseMode)), _item, SLOT(deleteLater()));
2548   connect(_view, SIGNAL(creationPolygonChanged(View::CreationEvent)),
2549           _item, SLOT(creationPolygonChanged(View::CreationEvent)));
2550   connect(_item, SIGNAL(creationComplete()), this, SLOT(creationComplete()));
2551   //If the item is interrupted while creating itself it will destroy itself
2552   //need to delete this too in response...
2553   connect(_item, SIGNAL(destroyed(QObject*)), this, SLOT(deleteLater()));
2554 }
2555 
2556 
creationComplete()2557 void CreateCommand::creationComplete() {
2558   _view->undoStack()->push(this);
2559   kstApp->mainWindow()->clearDrawingMarker();
2560   kstApp->mainWindow()->document()->setChanged(true);
2561 }
2562 
2563 
undo()2564 void LayoutCommand::undo() {
2565   Q_ASSERT(_layout);
2566   _layout->reset();
2567 }
2568 
2569 
redo()2570 void LayoutCommand::redo() {
2571   Q_ASSERT(_layout);
2572   _layout->apply();
2573 }
2574 
2575 
createLayout(bool preserve,int columns)2576 void LayoutCommand::createLayout(bool preserve, int columns) {
2577   Q_ASSERT(_item);
2578   Q_ASSERT(_item->view());
2579 
2580   QList<ViewItem*> viewItems;
2581   QList<QGraphicsItem*> list = _item->QGraphicsItem::childItems();
2582   if (list.isEmpty()) {
2583     return; //not added to undostack
2584   }
2585 
2586   viewItems = _item->view()->layoutableViewItems();
2587 
2588   if (viewItems.isEmpty()) {
2589     return; //not added to undostack
2590   }
2591 
2592   _layout = new ViewGridLayout(_item);
2593 
2594   FormatGridHelper grid(viewItems, preserve);
2595 
2596   if (columns == 0) {
2597     int n_view_items = viewItems.size();
2598     for (int i_view_item = 0; i_view_item<n_view_items; i_view_item++) {
2599       ViewItem *v = viewItems.at(i_view_item);
2600       struct AutoFormatRC rc = grid.rcList.at(i_view_item);
2601       _layout->addViewItem(v, rc.row, rc.col, rc.row_span, rc.col_span);
2602     }
2603 
2604   } else {
2605     int row = 0;
2606     int col = 0;
2607     int n_view_items = viewItems.size();
2608 
2609     for (int i_view_item = 0; i_view_item<n_view_items; i_view_item++) {
2610       ViewItem *v = viewItems.at(i_view_item);
2611       _layout->addViewItem(v, row, col, 1, 1);
2612       col++;
2613       if (col>=columns) {
2614         col = 0;
2615         row++;
2616       }
2617     }
2618   }
2619   if (qobject_cast<LayoutBoxItem*>(_item)) {
2620     QObject::connect(_layout, SIGNAL(enabledChanged(bool)),
2621                      _item, SLOT(setEnabled(bool)));
2622   }
2623 
2624   _layout->apply();
2625   _item->view()->undoStack()->push(this);
2626 }
2627 
2628 
undo()2629 void AppendLayoutCommand::undo() {
2630   if (_layout) {
2631     _layout->reset();
2632   }
2633 }
2634 
2635 
redo()2636 void AppendLayoutCommand::redo() {
2637   Q_ASSERT(_layout);
2638   _layout->apply();
2639 }
2640 
2641 
appendLayout(CurvePlacement::Layout layout,ViewItem * item,int columns)2642 void AppendLayoutCommand::appendLayout(CurvePlacement::Layout layout, ViewItem* item, int columns) {
2643   Q_ASSERT(_item);
2644   Q_ASSERT(_item->view());
2645   Q_ASSERT(item);
2646 
2647   if (layout == CurvePlacement::Auto) {
2648     columns = 0;
2649   }
2650 
2651   if (layout == CurvePlacement::Custom) layout = CurvePlacement::Protect;
2652   if (layout == CurvePlacement::Protect) {
2653     _layout = new ViewGridLayout(_item);
2654 
2655     QPointF center = _item->view()->sceneRect().center();
2656     center -= QPointF(100.0, 100.0);
2657 
2658     item->setPos(center);
2659     item->setViewRect(0.0, 0.0, 200.0, 200.0);
2660     _item->view()->scene()->addItem(item);
2661     //_item->view()->undoStack()->push(this);
2662     return;
2663   }
2664 
2665 
2666   QList<ViewItem*> viewItems;
2667   viewItems = _item->view()->layoutableViewItems();
2668 
2669   _layout = new ViewGridLayout(_item);
2670 
2671   FormatGridHelper grid(viewItems);
2672 
2673   if (grid.n_cols == columns) {
2674     if (grid.numHoles()<columns) {
2675       columns = 0; // already in correct columns - just line stuff up
2676     }
2677   }
2678 
2679   if (columns == 0) {
2680     int row = -1;
2681     int col = -1;
2682     for (int i_col = 0; i_col<grid.n_cols; i_col++) {
2683       for (int i_row = 0; i_row<grid.n_rows; i_row++) {
2684         if (grid.a[i_row][i_col]==0) {
2685           row = i_row;
2686           col = i_col;
2687           break;
2688         }
2689         if (row>=0) {
2690           break;
2691         }
2692       }
2693     }
2694     if (row<0) { // no empty slots
2695       if (grid.n_rows>grid.n_cols) { // add a column
2696         row = 0;
2697         col = grid.n_cols;
2698       } else { // add a row
2699         row = grid.n_rows;
2700         col = 0;
2701       }
2702     }
2703 
2704     int n_views = viewItems.size();
2705     for (int i_view = 0; i_view<n_views; i_view++) {
2706       ViewItem *v = viewItems.at(i_view);
2707       struct AutoFormatRC rc = grid.rcList.at(i_view);
2708       _layout->addViewItem(v, rc.row, rc.col, rc.row_span, rc.col_span);
2709     }
2710     _item->view()->scene()->addItem(item);
2711     _layout->addViewItem(item, row, col, 1,1);
2712   } else {
2713     int row = 0;
2714     int col = 0;
2715     int n_views = viewItems.size();
2716 
2717     for (int i_view = 0; i_view<n_views; i_view++) {
2718       ViewItem *v = viewItems.at(i_view);
2719       _layout->addViewItem(v, row, col, 1, 1);
2720       col++;
2721       if (col>=columns) {
2722         col = 0;
2723         row++;
2724       }
2725     }
2726     _item->view()->scene()->addItem(item);
2727     _layout->addViewItem(item, row, col, 1,1);
2728     _layout->setColumnCount(columns);
2729   }
2730 
2731   if (qobject_cast<LayoutBoxItem*>(_item)) {
2732     QObject::connect(_layout, SIGNAL(enabledChanged(bool)),
2733                     _item, SLOT(setEnabled(bool)));
2734   }
2735 
2736   _layout->apply();
2737 }
2738 
2739 
undo()2740 void MoveCommand::undo() {
2741   Q_ASSERT(_item);
2742   _item->setPos(_originalPos);
2743 }
2744 
2745 
redo()2746 void MoveCommand::redo() {
2747   Q_ASSERT(_item);
2748   _item->setPos(_newPos);
2749 }
2750 
2751 
undo()2752 void ResizeCommand::undo() {
2753   Q_ASSERT(_item);
2754   _item->setViewRect(_originalRect, true);
2755 }
2756 
2757 
redo()2758 void ResizeCommand::redo() {
2759   Q_ASSERT(_item);
2760   _item->setViewRect(_newRect, true);
2761 }
2762 
2763 
undo()2764 void RemoveCommand::undo() {
2765   Q_ASSERT(_item);
2766   _item->show();
2767 }
2768 
2769 
redo()2770 void RemoveCommand::redo() {
2771   Q_ASSERT(_item);
2772   _item->hide();
2773   // hmmm... view items aren't really deleted!!  if we delete them,
2774   // then we run into trouble with the undo stack.  If we don't, then
2775   // they keep holding onto the curves, preventing purge.
2776 }
2777 
2778 
undo()2779 void RaiseCommand::undo() {
2780   Q_ASSERT(_item);
2781   _item->setZValue(_item->zValue() - 1);
2782 }
2783 
2784 
redo()2785 void RaiseCommand::redo() {
2786   Q_ASSERT(_item);
2787   _item->setZValue(_item->zValue() + 1);
2788 }
2789 
2790 
undo()2791 void LowerCommand::undo() {
2792   Q_ASSERT(_item);
2793   _item->setZValue(_item->zValue() + 1);
2794 }
2795 
2796 
redo()2797 void LowerCommand::redo() {
2798   Q_ASSERT(_item);
2799   _item->setZValue(_item->zValue() - 1);
2800 }
2801 
2802 
undo()2803 void TransformCommand::undo() {
2804   Q_ASSERT(_item);
2805   _item->setTransform(_originalTransform);
2806 }
2807 
2808 
redo()2809 void TransformCommand::redo() {
2810   Q_ASSERT(_item);
2811   _item->setTransform(_newTransform);
2812 }
2813 
2814 
2815 
2816 
MimeDataViewItem()2817 MimeDataViewItem::MimeDataViewItem() : QMimeData() {
2818 }
2819 
downcast(const QMimeData * m)2820 const MimeDataViewItem* MimeDataViewItem::downcast(const QMimeData* m) {
2821   return qobject_cast<const MimeDataViewItem*>(m);
2822 }
2823 
2824 }
2825 
2826 // vim: ts=2 sw=2 et
2827