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