File indexing completed on 2024-12-22 04:17:49

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2007 The University of Toronto                        *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  ***************************************************************************/
0012 
0013 #include "viewitem.h"
0014 #include "applicationsettings.h"
0015 #include "viewitemdialog.h"
0016 #include "viewgridlayout.h"
0017 #include "plotitem.h"
0018 #include "sharedaxisboxitem.h"
0019 #include "plotitemmanager.h"
0020 #include "document.h"
0021 #include "datacollection.h"
0022 #include "formatgridhelper.h"
0023 #include "dialogdefaults.h"
0024 #include "cartesianrenderitem.h"
0025 #include "viewitemscriptinterface.h"
0026 
0027 #include "layoutboxitem.h"
0028 
0029 #include <math.h>
0030 
0031 #include <QMenu>
0032 #include <QDebug>
0033 #include <QLabel>
0034 #include <QHBoxLayout>
0035 #include <QWidgetAction>
0036 #include <QGraphicsScene>
0037 #include <QGraphicsSceneContextMenuEvent>
0038 #include <QInputDialog>
0039 #include <QDrag>
0040 #include <QMimeData>
0041 #include <QtAlgorithms>
0042 
0043 static const qreal ONE_PI = 3.14159265358979323846264338327950288419717;
0044 static qreal TWO_PI = 2.0 * ONE_PI;
0045 static qreal RAD2DEG = 180.0 / ONE_PI;
0046 static const int DRAWING_ZORDER = 500;
0047 
0048 #define DEBUG_GEOMETRY 0
0049 #define DEBUG_REPARENT 0
0050 
0051 // enable drag & drop
0052 #define KST_ENABLE_DD
0053 
0054 namespace Kst {
0055 
0056 ViewItem::ViewItem(View *parentView) :
0057     QObject(parentView),
0058     NamedObject(),
0059     _isXTiedZoom(false),
0060     _isYTiedZoom(false),
0061     _plotMaximized(false),
0062     _activeGrip(NoGrip),
0063     _parentRelativeHeight(0),
0064     _parentRelativeWidth(0),
0065     _gripMode(Move),
0066     _allowedGripModes(Move | Resize | Rotate /*| Scale*/),
0067     _creationState(None),
0068     _typeName("View Item"),
0069     _zoomOnlyMode(View::ZoomOnlyDisabled),
0070     _supportsTiedZoom(false),
0071     _fixedSize(false),
0072     _lockAspectRatio(false),
0073     _lockAspectRatioFixed(false),
0074     _hasStaticGeometry(false),
0075     _lockParent(false),
0076     _skipNextParentCheck(false),
0077     _allowsLayout(true),
0078     _hovering(false),
0079     _acceptsChildItems(true),
0080     _acceptsContextMenuEvents(true),
0081     _updatingLayout(false),
0082     _highlighted(false),
0083     _allowedGrips(TopLeftGrip | TopRightGrip | BottomRightGrip | BottomLeftGrip |
0084                 TopMidGrip | RightMidGrip | BottomMidGrip | LeftMidGrip),
0085     _lockPosToData(false),
0086     _editDialog(0),
0087     _interface(0),
0088     _dpi(71.0)
0089 {
0090   _initializeShortName();
0091   setZValue(DRAWING_ZORDER);
0092   setAcceptsHoverEvents(true);
0093   setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable);
0094   connect(parentView, SIGNAL(mouseModeChanged(View::MouseMode)),
0095           this, SLOT(viewMouseModeChanged(View::MouseMode)));
0096   connect(parentView, SIGNAL(viewModeChanged(View::ViewMode)),
0097           this, SLOT(updateView()));
0098 
0099   connect(this, SIGNAL(geometryChanged()), parentView, SLOT(viewChanged()));
0100 
0101   setLayoutMargins(ApplicationSettings::self()->layoutMargins());
0102   setLayoutSpacing(ApplicationSettings::self()->layoutSpacing());
0103 
0104   // Add actions common to all view objects
0105   // create them here in the constructor so we
0106   // can register shortcuts.
0107   _editAction = new QAction(tr("Edit"), this);
0108   _editAction->setShortcut(Qt::Key_E);
0109   registerShortcut(_editAction);
0110   connect(_editAction, SIGNAL(triggered()), this, SLOT(edit()));
0111 
0112   _deleteAction = new QAction(tr("Delete"), this);
0113   _deleteAction->setShortcut(Qt::Key_Delete);
0114   registerShortcut(_deleteAction);
0115   connect(_deleteAction, SIGNAL(triggered()), this, SLOT(remove()));
0116 
0117   _raiseAction = new QAction(tr("Raise"), this);
0118   connect(_raiseAction, SIGNAL(triggered()), this, SLOT(raise()));
0119 
0120   _lowerAction = new QAction(tr("Lower"), this);
0121   connect(_lowerAction, SIGNAL(triggered()), this, SLOT(lower()));
0122 
0123   _autoLayoutAction = new QAction(tr("Automatic"), this);
0124   _autoLayoutAction->setShortcut(Qt::Key_U);
0125   registerShortcut(_autoLayoutAction);
0126   connect(_autoLayoutAction, SIGNAL(triggered()), this, SLOT(createAutoLayout()));
0127 
0128   _protectedLayoutAction = new QAction(tr("Protect Layout"), this);
0129   connect(_protectedLayoutAction, SIGNAL(triggered()), this, SLOT(createProtectedLayout()));
0130 
0131   _customLayoutAction = new QAction(tr("Columns"), this);
0132   connect(_customLayoutAction, SIGNAL(triggered()), this, SLOT(createCustomLayout()));
0133 
0134   _oneColumnLayoutAction = new QAction(tr("1 Column"), this);
0135   _oneColumnLayoutAction->setShortcut(Qt::Key_1);
0136   registerShortcut(_oneColumnLayoutAction);
0137   connect(_oneColumnLayoutAction, SIGNAL(triggered()), this, SLOT(createOneColLayout()));
0138 
0139   _twoColumnLayoutAction = new QAction(tr("2 Columns"), this);
0140   _twoColumnLayoutAction->setShortcut(Qt::Key_2);
0141   registerShortcut(_twoColumnLayoutAction);
0142   connect(_twoColumnLayoutAction, SIGNAL(triggered()), this, SLOT(createTwoColLayout()));
0143 
0144   _threeColumnLayoutAction = new QAction(tr("3 Columns"), this);
0145   _threeColumnLayoutAction->setShortcut(Qt::Key_3);
0146   registerShortcut(_threeColumnLayoutAction);
0147   connect(_threeColumnLayoutAction, SIGNAL(triggered()), this, SLOT(createThreeColLayout()));
0148 
0149   _lockPosToDataAction = new QAction(tr("&Lock Position to Data"),this);
0150   _lockPosToDataAction->setCheckable(true);
0151   connect(_lockPosToDataAction, SIGNAL(toggled(bool)), this, SLOT(setLockPosToData(bool)));
0152 
0153   // only drop plots onto TabBar
0154   setAcceptDrops(false);
0155 
0156 }
0157 
0158 
0159 ViewItem::~ViewItem() {
0160 }
0161 
0162 void ViewItem::_initializeShortName() {
0163   _shortName = 'D'+QString::number(_viewitemnum);
0164   if (_viewitemnum>max_viewitemnum)
0165     max_viewitemnum = _viewitemnum;
0166   _viewitemnum++;
0167 
0168 }
0169 
0170 
0171 void ViewItem::save(QXmlStreamWriter &xml) {
0172 
0173   // when saving, check to see if your parent is a cartesianrenderitem.
0174   // if so, we'll need to adjust to take into account that when loaded,
0175   // the object will be created in a cartesian render item with no plot
0176   // borders, and then resized.
0177   // this keeps line end points in the right place.
0178   CartesianRenderItem *cri = dynamic_cast<CartesianRenderItem *>(parentItem());
0179   QTransform tr;
0180   qreal w = _parentRelativeWidth;
0181   if (cri) {
0182     QRectF cri_rect = cri->rect();
0183     QRectF plot_rect = cri->parentRect();
0184     qreal oldL = relativeWidth()*cri_rect.width();
0185 
0186     qreal r0 = rotationAngleRadians();
0187     qreal dy = oldL*sin(r0)*plot_rect.height()/cri_rect.height();
0188     qreal dx = oldL*cos(r0)*plot_rect.width()/cri_rect.width();
0189     qreal r1 = atan2(dy, dx);
0190 
0191     w = sqrt(dy*dy + dx*dx)/plot_rect.width();
0192 
0193     tr.rotateRadians(r1);
0194   } else {
0195     tr = transform();
0196   }
0197 
0198   xml.writeAttribute("name", typeName());
0199   xml.writeStartElement("position");
0200   xml.writeAttribute("x", QVariant(pos().x()).toString());
0201   xml.writeAttribute("y", QVariant(pos().y()).toString());
0202   xml.writeAttribute("z", QVariant(zValue()).toString());
0203   xml.writeEndElement();
0204   xml.writeStartElement("rect");
0205   xml.writeAttribute("x", QVariant(viewRect().x()).toString());
0206   xml.writeAttribute("y", QVariant(viewRect().y()).toString());
0207   xml.writeAttribute("width", QVariant(viewRect().width()).toString());
0208   xml.writeAttribute("height", QVariant(viewRect().height()).toString());
0209   xml.writeEndElement();
0210   xml.writeStartElement("relativesize");
0211   xml.writeAttribute("width", QVariant(w).toString());
0212   xml.writeAttribute("height", QVariant(_parentRelativeHeight).toString());
0213   xml.writeAttribute("centerx", QVariant(_parentRelativeCenter.x()).toString());
0214   xml.writeAttribute("centery", QVariant(_parentRelativeCenter.y()).toString());
0215   xml.writeAttribute("posx", QVariant(_parentRelativePosition.x()).toString());
0216   xml.writeAttribute("posy", QVariant(_parentRelativePosition.y()).toString());
0217   xml.writeAttribute("leftx", QVariant(_parentRelativeLeft.x()).toString());
0218   xml.writeAttribute("lefty", QVariant(_parentRelativeLeft.y()).toString());
0219   xml.writeAttribute("rightx", QVariant(_parentRelativeRight.x()).toString());
0220   xml.writeAttribute("righty", QVariant(_parentRelativeRight.y()).toString());
0221   xml.writeAttribute("fixaspect", QVariant(_lockAspectRatio).toString());
0222   xml.writeAttribute("lockpostodata", QVariant(_lockPosToData).toString());
0223   if (_lockPosToData) { // meaningless if not locked: why pollute the file?
0224     xml.writeAttribute("datarect_x", QVariant(_dataRelativeRect.x()).toString());
0225     xml.writeAttribute("datarect_y", QVariant(_dataRelativeRect.y()).toString());
0226     xml.writeAttribute("datarect_width", QVariant(_dataRelativeRect.width()).toString());
0227     xml.writeAttribute("datarect_height", QVariant(_dataRelativeRect.height()).toString());
0228   }
0229   xml.writeEndElement();
0230 
0231   xml.writeStartElement("transform");
0232   xml.writeAttribute("m11", QVariant(tr.m11()).toString());
0233   xml.writeAttribute("m12", QVariant(tr.m12()).toString());
0234   xml.writeAttribute("m13", QVariant(tr.m13()).toString());
0235   xml.writeAttribute("m21", QVariant(tr.m21()).toString());
0236   xml.writeAttribute("m22", QVariant(tr.m22()).toString());
0237   xml.writeAttribute("m23", QVariant(tr.m23()).toString());
0238   xml.writeAttribute("m31", QVariant(tr.m31()).toString());
0239   xml.writeAttribute("m32", QVariant(tr.m32()).toString());
0240   xml.writeAttribute("m33", QVariant(tr.m33()).toString());
0241   xml.writeEndElement();
0242   xml.writeStartElement("pen");
0243   xml.writeAttribute("style", QVariant((int)pen().style()).toString());
0244   xml.writeAttribute("width", QVariant(storedPen().widthF()).toString());
0245   xml.writeAttribute("miterlimit", QVariant(pen().miterLimit()).toString());
0246   xml.writeAttribute("cap", QVariant(pen().capStyle()).toString());
0247   xml.writeAttribute("joinStyle", QVariant(pen().joinStyle()).toString());
0248   xml.writeStartElement("brush");
0249   xml.writeAttribute("color", pen().brush().color().name());
0250   xml.writeAttribute("alpha", QString::number(pen().brush().color().alphaF()));
0251   xml.writeAttribute("style", QVariant((int)pen().brush().style()).toString());
0252   xml.writeEndElement();
0253   xml.writeEndElement();
0254   xml.writeStartElement("brush");
0255   xml.writeAttribute("color", brush().color().name());
0256   xml.writeAttribute("alpha", QString::number(brush().color().alphaF()));
0257   xml.writeAttribute("style", QVariant((int)brush().style()).toString());
0258   if (brush().gradient()) {
0259     QString stopList;
0260     foreach(const QGradientStop &stop, brush().gradient()->stops()) {
0261       qreal point = (qreal)stop.first;
0262       QColor color = (QColor)stop.second;
0263 
0264       stopList += QString::number(point);
0265       stopList += ',';
0266       stopList += color.name();
0267       stopList += ',';
0268     }
0269     xml.writeAttribute("gradient", stopList);
0270   }
0271   xml.writeEndElement();
0272 
0273   QList<QGraphicsItem*> list = QGraphicsItem::childItems();
0274   foreach (QGraphicsItem *item, list) {
0275     ViewItem *viewItem = dynamic_cast<ViewItem*>(item);
0276     if (!viewItem)
0277       continue;
0278 
0279     viewItem->save(xml);
0280   }
0281 }
0282 
0283 void ViewItem::applyDialogDefaultsFill(bool default_no_fill) {
0284   if (hasBrush()) {
0285     //set the brush
0286     QBrush brush = dialogDefaultsBrush(defaultsGroupName(), default_no_fill);
0287     setBrush(brush);
0288   }
0289 }
0290 
0291 void ViewItem::applyDialogDefaultsStroke(bool default_no_pen) {
0292   if (hasStroke()) {
0293     // set the pen
0294     QPen pen = dialogDefaultsPen(defaultsGroupName(), default_no_pen);
0295     storePen(pen);
0296   }
0297 }
0298 
0299 void ViewItem::applyDialogDefaultsLockPosToData() {
0300   setLockPosToData(dialogDefaultsLockPosToData(defaultsGroupName()));
0301 }
0302 
0303 void ViewItem::setLockPosToData(bool lockPosToData) {
0304   _lockPosToData = lockPosToData;
0305   _lockPosToDataAction->setChecked(lockPosToData);
0306   emit(relativeSizeUpdated());
0307 }
0308 
0309 
0310 QRectF ViewItem::parentRect() const {
0311   if (parentViewItem()) {
0312     return parentViewItem()->rect().normalized();
0313   } else if (view()) {
0314     return view()->rect();
0315   } else {
0316     Q_ASSERT_X(false,"parent test", "item has no parentview item");
0317   }
0318   return QRectF(0,0,1,1); // shouldn't get here
0319 }
0320 
0321 
0322 void ViewItem::applyDataLockedDimensions() {
0323   PlotRenderItem *render_item = dynamic_cast<PlotRenderItem *>(parentViewItem());
0324   if (render_item) {
0325     qreal parentWidth = render_item->width();
0326     qreal parentHeight = render_item->height();
0327     qreal parentX = render_item->rect().x();
0328     qreal parentY = render_item->rect().y();
0329 
0330     qreal aspectRatio;
0331     if (rect().width() > 0) {
0332       aspectRatio = qreal(rect().height()) / qreal(rect().width());
0333     } else {
0334       aspectRatio = 10000.0;
0335     }
0336 
0337     qreal relativeWidth = _dataRelativeRect.width()/(render_item->plotItem()->xMax() - render_item->plotItem()->xMin());
0338     qreal relativeHeight = _dataRelativeRect.height()/(render_item->plotItem()->yMax() - render_item->plotItem()->yMin());
0339     qreal relativeX = (_dataRelativeRect.center().x() - render_item->plotItem()->xMin())/
0340         (render_item->plotItem()->xMax() - render_item->plotItem()->xMin());
0341     qreal relativeY = (_dataRelativeRect.center().y() - render_item->plotItem()->yMin())/
0342         (render_item->plotItem()->yMax() - render_item->plotItem()->yMin());
0343 
0344     qreal width = relativeWidth * parentWidth;
0345     qreal height;
0346     if (lockAspectRatio()) {
0347       height = width * aspectRatio;
0348     } else {
0349       height = relativeHeight * parentHeight;
0350     }
0351     setPos(parentX + relativeX*parentWidth, parentY + (1.0-relativeY)*parentHeight);
0352     setViewRect(-width/2, -height/2, width, height);
0353 
0354     updateRelativeSize();
0355 
0356   } else {
0357     qDebug() << "apply data locked dimensions called without a render item (!)";
0358   }
0359 }
0360 
0361 bool ViewItem::parse(QXmlStreamReader &xml, bool &validChildTag) {
0362   bool knownTag = false;
0363   QString expectedTag;
0364   if (xml.isStartElement()) {
0365     expectedTag = xml.name().toString();
0366     QXmlStreamAttributes attrs = xml.attributes();
0367     QStringRef av;
0368     if (xml.name().toString() == "name") {
0369       knownTag = true;
0370       av = attrs.value("name");
0371       if (!av.isNull()) {
0372         setTypeName(av.toString());
0373      }
0374     } else if (xml.name().toString() == "position") {
0375       knownTag = true;
0376       qreal x = 0, y = 0, z = DRAWING_ZORDER;
0377       av = attrs.value("x");
0378       if (!av.isNull()) {
0379         x = av.toString().toDouble();
0380       }
0381       av = attrs.value("y");
0382       if (!av.isNull()) {
0383         y = av.toString().toDouble();
0384      }
0385      setPos(x, y);
0386 
0387      av = attrs.value("z");
0388      if (!av.isNull()) {
0389        z = av.toString().toDouble();
0390      }
0391      setZValue(z);
0392 
0393     } else if (xml.name().toString() == "brush") {
0394       knownTag = true;
0395       QBrush brush;
0396       av = attrs.value("gradient");
0397       if (!av.isNull()) {
0398         QStringList stopInfo = av.toString().split(',', QString::SkipEmptyParts);
0399         QLinearGradient gradient(1,0,0,0);
0400         gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
0401         for (int i = 0; i < stopInfo.size(); i+=2) {
0402           gradient.setColorAt(stopInfo.at(i).toDouble(), QColor(stopInfo.at(i+1)));
0403         }
0404         brush = QBrush(gradient);
0405       } else {
0406         av = attrs.value("color");
0407         if (!av.isNull()) {
0408           brush.setColor(QColor(av.toString()));
0409         }
0410         av = attrs.value("style");
0411         if (!av.isNull()) {
0412           brush.setStyle((Qt::BrushStyle)av.toString().toInt());
0413         }
0414         av = attrs.value("alpha");
0415         if (!av.isNull()) {
0416           qreal alpha = av.toString().toDouble();
0417           QColor c = brush.color();
0418           c.setAlphaF(alpha);
0419           brush.setColor(c);
0420         }
0421       }
0422       setBrush(brush);
0423     } else if (xml.name().toString() == "pen") {
0424       knownTag = true;
0425       QPen pen;
0426       av = attrs.value("style");
0427       if (!av.isNull()) {
0428         pen.setStyle((Qt::PenStyle)av.toString().toInt());
0429       }
0430       av = attrs.value("width");
0431       if (!av.isNull()) {
0432         pen.setWidthF(av.toString().toDouble());
0433       }
0434       av = attrs.value("miterlimit");
0435       if (!av.isNull()) {
0436         pen.setMiterLimit(av.toString().toDouble());
0437       }
0438       av = attrs.value("cap");
0439       if (!av.isNull()) {
0440         pen.setCapStyle((Qt::PenCapStyle)av.toString().toInt());
0441       }
0442       av = attrs.value("joinstyle");
0443       if (!av.isNull()) {
0444         pen.setJoinStyle((Qt::PenJoinStyle)av.toString().toInt());
0445       }
0446       xml.readNext();
0447       xml.readNext();
0448       if (xml.isStartElement() && (xml.name().toString() == "brush")) {
0449         QBrush penBrush;
0450         attrs = xml.attributes();
0451         av = attrs.value("color");
0452         if (!av.isNull()) {
0453             penBrush.setColor(QColor(av.toString()));
0454         }
0455         av = attrs.value("alpha");
0456         if (!av.isNull()) {
0457           qreal alpha = av.toString().toDouble();
0458           QColor c = penBrush.color();
0459           c.setAlphaF(alpha);
0460           penBrush.setColor(c);
0461         }
0462 
0463         av = attrs.value("style");
0464         if (!av.isNull()) {
0465           penBrush.setStyle((Qt::BrushStyle)av.toString().toInt());
0466         }
0467         pen.setBrush(penBrush);
0468         xml.readNext();
0469         if (!xml.isEndElement() || (xml.name().toString() != "brush")) {
0470           expectedTag = "InvalidTag";
0471         }
0472         xml.readNext();
0473       }
0474       storePen(pen);
0475     } else if (xml.name().toString() == "rect") {
0476       knownTag = true;
0477       qreal x = 0, y = 0, w = 10, h = 10;
0478       av = attrs.value("width");
0479       if (!av.isNull()) {
0480         w = av.toString().toDouble();
0481       }
0482       av = attrs.value("height");
0483       if (!av.isNull()) {
0484         h = av.toString().toDouble();
0485       }
0486       av = attrs.value("x");
0487       if (!av.isNull()) {
0488          x = av.toString().toDouble();
0489       }
0490       av = attrs.value("y");
0491       if (!av.isNull()) {
0492         y = av.toString().toDouble();
0493       }
0494       setViewRect(QRectF(QPointF(x, y), QSizeF(w, h)));
0495     } else if (xml.name().toString() == "relativesize") {
0496       knownTag = true;
0497       qreal width = 0, height = 0, centerx = 0, centery = 0, posx = 0, posy = 0;
0498       qreal leftx = -1.0, lefty = -1.0, rightx = -1.0, righty = -1.0;
0499       bool lock_aspect_ratio = false;
0500       av = attrs.value("width");
0501       if (!av.isNull()) {
0502         width = av.toString().toDouble();
0503       }
0504       av = attrs.value("height");
0505       if (!av.isNull()) {
0506         height = av.toString().toDouble();
0507       }
0508       av = attrs.value("centerx");
0509       if (!av.isNull()) {
0510         centerx = av.toString().toDouble();
0511       }
0512       av = attrs.value("centery");
0513       if (!av.isNull()) {
0514         centery = av.toString().toDouble();
0515       }
0516       av = attrs.value("posx");
0517       if (!av.isNull()) {
0518         posx = av.toString().toDouble();
0519       }
0520       av = attrs.value("posy");
0521       if (!av.isNull()) {
0522         posy = av.toString().toDouble();
0523       }
0524       av = attrs.value("leftx");
0525       if (!av.isNull()) {
0526         leftx = av.toString().toDouble();
0527       }
0528       av = attrs.value("lefty");
0529       if (!av.isNull()) {
0530         lefty = av.toString().toDouble();
0531       }
0532       av = attrs.value("rightx");
0533       if (!av.isNull()) {
0534         rightx = av.toString().toDouble();
0535       }
0536       av = attrs.value("righty");
0537       if (!av.isNull()) {
0538         righty = av.toString().toDouble();
0539       }
0540       av = attrs.value("fixaspect");
0541       if (!av.isNull()) {
0542         lock_aspect_ratio = QVariant(av.toString()).toBool();
0543       }
0544       if (rightx <-0.99) { // old kst file: generate from center
0545         rightx = centerx + width/2.0;
0546         leftx  = centerx - width/2.0;
0547         righty = centery + height/2.0;
0548         lefty  = centery + height/2.0;
0549       }
0550       setRelativeWidth(width);
0551       setRelativeHeight(height);
0552       setRelativeCenter(QPointF(centerx, centery));
0553       setRelativePosition(QPointF(posx, posy));
0554       setRelativeLeft(QPointF(leftx, lefty));
0555       setRelativeRight(QPointF(rightx, righty));
0556       setLockAspectRatio(lock_aspect_ratio);
0557 
0558       av = attrs.value("lockpostodata");
0559       if (!av.isNull()) {
0560         bool lock_pos_to_data = QVariant(av.toString()).toBool();
0561         setLockPosToData(lock_pos_to_data);
0562         if (lock_pos_to_data) {
0563           qreal x=0, y=0, w=0.1, h=0.1;
0564           av = attrs.value("datarect_x");
0565           if (!av.isNull()) {
0566             x = av.toString().toDouble();
0567           }
0568           av = attrs.value("datarect_y");
0569           if (!av.isNull()) {
0570             y = av.toString().toDouble();
0571           }
0572           av = attrs.value("datarect_width");
0573           if (!av.isNull()) {
0574             w = av.toString().toDouble();
0575           }
0576           av = attrs.value("datarect_height");
0577           if (!av.isNull()) {
0578             h = av.toString().toDouble();
0579           }
0580           _dataRelativeRect = QRectF(x,y,w,h);
0581         }
0582       } else {
0583         setLockPosToData(false);
0584       }
0585     } else if (xml.name().toString() == "transform") {
0586       knownTag = true;
0587       qreal m11 = 1.0, m12 = 0, m13 = 0, m21 = 0, m22 = 1.0, m23 = 0, m31 = 0, m32= 0, m33 = 1.0;
0588       av = attrs.value("m11");
0589       if (!av.isNull()) {
0590         m11 = av.toString().toDouble();
0591       }
0592       av = attrs.value("m12");
0593       if (!av.isNull()) {
0594         m12 = av.toString().toDouble();
0595       }
0596       av = attrs.value("m13");
0597       if (!av.isNull()) {
0598         m13 = av.toString().toDouble();
0599       }
0600       av = attrs.value("m21");
0601       if (!av.isNull()) {
0602         m21 = av.toString().toDouble();
0603       }
0604       av = attrs.value("m22");
0605       if (!av.isNull()) {
0606         m22 = av.toString().toDouble();
0607       }
0608       av = attrs.value("m23");
0609       if (!av.isNull()) {
0610         m23 = av.toString().toDouble();
0611       }
0612       av = attrs.value("m31");
0613       if (!av.isNull()) {
0614         m31 = av.toString().toDouble();
0615       }
0616       av = attrs.value("m32");
0617       if (!av.isNull()) {
0618         m32 = av.toString().toDouble();
0619       }
0620       av = attrs.value("m33");
0621       if (!av.isNull()) {
0622         m33 = av.toString().toDouble();
0623       }
0624       setTransform(QTransform(m11, m12, m13, m21, m22, m23, m31, m32, m33));
0625     }
0626   }
0627 
0628   if (knownTag) {
0629     xml.readNext();
0630     if (xml.isEndElement()) {
0631       if ((xml.name().toString() == expectedTag) ) {
0632       validChildTag = true;
0633       }
0634     }
0635   }
0636   return knownTag;
0637 }
0638 
0639 View *ViewItem::view() const {
0640   return qobject_cast<View*>(QObject::parent());
0641 }
0642 
0643 void ViewItem::setView(View* parentView) {
0644   QObject::setParent(parentView);
0645   reRegisterShortcut();
0646 
0647   QList<QGraphicsItem*> list = QGraphicsItem::childItems();
0648   foreach (QGraphicsItem *item, list) {
0649     ViewItem *viewItem = dynamic_cast<ViewItem*>(item);
0650     if (viewItem) {
0651       viewItem->setView(parentView);
0652     }
0653   }
0654 }
0655 
0656 
0657 ViewItem *ViewItem::parentViewItem() const {
0658   return dynamic_cast<ViewItem*>(parentItem());
0659 }
0660 
0661 
0662 void ViewItem::setParentViewItem(ViewItem* parent) {
0663   QGraphicsItem::setParentItem(parent);
0664   updateRelativeSize(true);
0665 }
0666 
0667 
0668 ViewItem::GripMode ViewItem::gripMode() const {
0669   return _gripMode;
0670 }
0671 
0672 
0673 void ViewItem::setGripMode(GripMode mode) {
0674   _gripMode = mode;
0675   update();
0676 }
0677 
0678 
0679 ViewItem::GripModes ViewItem::allowedGripModes() const {
0680   return _allowedGripModes;
0681 }
0682 
0683 
0684 void ViewItem::setAllowedGripModes(GripModes modes) {
0685   _allowedGripModes = modes;
0686 }
0687 
0688 
0689 bool ViewItem::isAllowed(GripMode mode) const {
0690   return _allowedGripModes & mode;
0691 }
0692 
0693 
0694 QRectF ViewItem::viewRect() const {
0695   return rect();
0696 }
0697 
0698 
0699 void ViewItem::setViewRect(const QRectF &viewRect, bool automaticChange) {
0700   QRectF oldViewRect = rect();
0701 
0702   if (oldViewRect == viewRect)
0703     return;
0704 
0705   setRect(viewRect);
0706 
0707   emit geometryChanged();
0708 
0709   if (!automaticChange) {
0710     updateRelativeSize();
0711   }
0712 
0713   foreach (QGraphicsItem *item, QGraphicsItem::childItems()) {
0714     if (item->parentItem() != this)
0715       continue;
0716 
0717     ViewItem *viewItem = dynamic_cast<ViewItem*>(item);
0718 
0719     if (!viewItem)
0720       continue;
0721 
0722     if (viewItem->hasStaticGeometry())
0723       continue;
0724 
0725     viewItem->setSkipNextParentCheck(true);
0726     viewItem->updateChildGeometry(oldViewRect, viewRect);
0727   }
0728 }
0729 
0730 
0731 void ViewItem::setViewRect(qreal x, qreal y, qreal width, qreal height, bool automaticChange) {
0732   setViewRect(QRectF(x, y, width, height), automaticChange);
0733 }
0734 
0735 
0736 QSizeF ViewItem::sizeOfGrip() const {
0737   if (!view())
0738     return QSizeF();
0739 
0740   int base = _dpi*11.0/96.0 ;
0741 
0742   return view()->mapToScene(QRect(0, 0, base, base)).boundingRect().size();
0743 }
0744 
0745 
0746 QPainterPath ViewItem::topLeftGrip() const {
0747   QRectF bound = gripBoundingRect();
0748   QRectF grip = QRectF(bound.topLeft(), sizeOfGrip());
0749   QPainterPath path;
0750   if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move)
0751     path.addRect(grip);
0752   else
0753     path.addEllipse(grip);
0754 
0755   return path;
0756 }
0757 
0758 
0759 QPainterPath ViewItem::topRightGrip() const {
0760   QRectF bound = gripBoundingRect();
0761   QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width(), 0), sizeOfGrip());
0762   QPainterPath path;
0763   if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move)
0764     path.addRect(grip);
0765   else
0766     path.addEllipse(grip);
0767 
0768   return path;
0769 }
0770 
0771 
0772 QPainterPath ViewItem::bottomRightGrip() const {
0773   QRectF bound = gripBoundingRect();
0774   QRectF grip = QRectF(bound.bottomRight() - QPointF(sizeOfGrip().width(), sizeOfGrip().height()), sizeOfGrip());
0775   QPainterPath path;
0776   if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move)
0777     path.addRect(grip);
0778   else
0779     path.addEllipse(grip);
0780 
0781   return path;
0782 }
0783 
0784 
0785 QPainterPath ViewItem::bottomLeftGrip() const {
0786   QRectF bound = gripBoundingRect();
0787   QRectF grip = QRectF(bound.bottomLeft() - QPointF(0, sizeOfGrip().height()), sizeOfGrip());
0788   QPainterPath path;
0789   if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move)
0790     path.addRect(grip);
0791   else
0792     path.addEllipse(grip);
0793 
0794   return path;
0795 }
0796 
0797 
0798 QPainterPath ViewItem::topMidGrip() const {
0799   if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio)
0800     return QPainterPath();
0801 
0802   QRectF bound = gripBoundingRect();
0803   QRectF grip = QRectF(bound.topLeft(), sizeOfGrip());
0804   grip.moveCenter(QPointF(bound.center().x(), grip.center().y()));
0805 
0806   QPainterPath path;
0807   path.addRect(grip);
0808 
0809   return path;
0810 }
0811 
0812 
0813 QPainterPath ViewItem::rightMidGrip() const {
0814   if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio)
0815     return QPainterPath();
0816 
0817   QRectF bound = gripBoundingRect();
0818   QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width(), 0), sizeOfGrip());
0819   grip.moveCenter(QPointF(grip.center().x(), bound.center().y()));
0820 
0821   QPainterPath path;
0822   path.addRect(grip);
0823 
0824   return path;
0825 }
0826 
0827 
0828 QPainterPath ViewItem::bottomMidGrip() const {
0829   if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio)
0830     return QPainterPath();
0831 
0832   QRectF bound = gripBoundingRect();
0833   QRectF grip = QRectF(bound.bottomLeft() - QPointF(0, sizeOfGrip().height()), sizeOfGrip());
0834   grip.moveCenter(QPointF(bound.center().x(), grip.center().y()));
0835 
0836   QPainterPath path;
0837   path.addRect(grip);
0838 
0839   return path;
0840 }
0841 
0842 
0843 QPainterPath ViewItem::leftMidGrip() const {
0844   if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio)
0845     return QPainterPath();
0846 
0847   QRectF bound = gripBoundingRect();
0848   QRectF grip = QRectF(bound.topLeft(), sizeOfGrip());
0849   grip.moveCenter(QPointF(grip.center().x(), bound.center().y()));
0850 
0851   QPainterPath path;
0852   path.addRect(grip);
0853 
0854   return path;
0855 }
0856 
0857 
0858 QPainterPath ViewItem::grips() const {
0859   QPainterPath grips;
0860   grips.addPath(topLeftGrip());
0861   grips.addPath(topRightGrip());
0862   grips.addPath(bottomRightGrip());
0863   grips.addPath(bottomLeftGrip());
0864   grips.addPath(topMidGrip());
0865   grips.addPath(rightMidGrip());
0866   grips.addPath(bottomMidGrip());
0867   grips.addPath(leftMidGrip());
0868   return grips;
0869 }
0870 
0871 
0872 ViewItem::ActiveGrip ViewItem::activeGrip() const {
0873   return _activeGrip;
0874 }
0875 
0876 
0877 void ViewItem::setActiveGrip(ActiveGrip grip) {
0878   _activeGrip = grip;
0879 }
0880 
0881 
0882 ViewItem::ActiveGrips ViewItem::allowedGrips() const {
0883   return _allowedGrips;
0884 }
0885 
0886 
0887 void ViewItem::setAllowedGrips(ActiveGrips grips) {
0888   _allowedGrips = grips;
0889 }
0890 
0891 
0892 bool ViewItem::isAllowed(ActiveGrip grip) const {
0893   return _allowedGrips & grip;
0894 }
0895 
0896 
0897 QRectF ViewItem::selectBoundingRect() const {
0898   return rect();
0899 }
0900 
0901 
0902 QRectF ViewItem::gripBoundingRect() const {
0903   QRectF bound = selectBoundingRect();
0904   bound.setTopLeft(bound.topLeft() - QPointF(sizeOfGrip().width() / 2.0, sizeOfGrip().height() / 2.0));
0905   bound.setWidth(bound.width() + sizeOfGrip().width() / 2.0);
0906   bound.setHeight(bound.height() + sizeOfGrip().height() / 2.0);
0907   return bound;
0908 }
0909 
0910 
0911 QRectF ViewItem::boundingRect() const {
0912   bool inCreation = false;
0913   if (view()) /* false when exiting */
0914     inCreation = view()->mouseMode() == View::Create;
0915   if ((!isSelected() && !isHovering()) || inCreation)
0916     return QGraphicsRectItem::boundingRect();
0917 
0918   QPolygonF gripBound = gripBoundingRect();
0919   return QRectF(gripBound[0], gripBound[2]);
0920 }
0921 
0922 
0923 QPainterPath ViewItem::shape() const {
0924   if ((!isSelected() && !isHovering()) || (view()->mouseMode() == View::Create))
0925     return itemShape();
0926 
0927   QPainterPath selectPath;
0928   selectPath.setFillRule(Qt::WindingFill);
0929 
0930   selectPath.addPolygon(rect());
0931 
0932   selectPath.addPath(grips());
0933   return selectPath;
0934 }
0935 
0936 bool ViewItem::isMaximized() {
0937   if (_plotMaximized) {
0938     return true;
0939   } else if (parentViewItem()) {
0940     return parentViewItem()->isMaximized();
0941   } else {
0942     return false;
0943   }
0944 }
0945 
0946 void ViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
0947   Q_UNUSED(option);
0948   Q_UNUSED(widget);
0949   if ((!isMaximized()) && view()->childMaximized()) {
0950     return;
0951   }
0952 
0953   _dpi = painter->device()->logicalDpiX();
0954 
0955   QPen rescaled_pen(_storedPen);
0956   rescaled_pen.setWidthF(Curve::lineDim(painter->window(),rescaled_pen.widthF()));
0957   setPen(rescaled_pen);
0958 
0959   painter->save();
0960   painter->setPen(pen());
0961   painter->setBrush(brush());
0962   if (_lockPosToData) {
0963     PlotRenderItem *render_item = dynamic_cast<PlotRenderItem *>(parentViewItem());
0964     if (render_item) {
0965       QPolygonF PF = mapFromParent(render_item->rect());
0966       QPainterPath path;
0967       path.addPolygon(PF);
0968       painter->setClipPath(path);
0969     }
0970   }
0971   paint(painter); //this is the overload that subclasses should use...
0972   if (!view()->isPrinting() && !view()->childMaximized()) {
0973     painter->setPen(Qt::DotLine);
0974     painter->setBrush(Qt::NoBrush);
0975     if ((isSelected() || isHovering())
0976         && view()->mouseMode() != View::Create
0977         && view()->viewMode() != View::Data) {
0978       painter->drawPath(shape());
0979       if (_gripMode == Resize)
0980         painter->fillPath(grips(), Qt::blue);
0981       else if (_gripMode == Scale)
0982         painter->fillPath(grips(), Qt::black);
0983       else if (_gripMode == Rotate)
0984         painter->fillPath(grips(), Qt::red);
0985       else if (_gripMode == Move)
0986         painter->fillPath(grips(), Qt::transparent);
0987     } else if (isHighlighted()) {
0988       QColor highlightColor(QColor(255, 255, 0, 120));
0989       painter->fillPath(shape(), highlightColor);
0990     }
0991     if (supportsTiedZoom()) {
0992       painter->save();
0993       painter->setPen(Qt::black);
0994       painter->setRenderHint(QPainter::Antialiasing, true);
0995       painter->fillPath(checkBox(), Qt::white);
0996       if (isHovering()) {
0997         QRectF check = checkBox().controlPointRect();
0998         check.setSize(QSizeF(check.width() / 3.5, check.height() / 3.5));
0999         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 
1039 void ViewItem::paint(QPainter *painter) {
1040   Q_UNUSED(painter);
1041 }
1042 
1043 
1044 void ViewItem::edit() {
1045   if (!_editDialog) {
1046     _editDialog = new ViewItemDialog(this, kstApp->mainWindow());
1047   }
1048   _editDialog->show();
1049   _editDialog->raise();
1050 }
1051 
1052 
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 
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 
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 
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 
1102 void ViewItem::raise() {
1103   RaiseCommand *up = new RaiseCommand(this);
1104   up->redo();
1105 }
1106 
1107 
1108 void ViewItem::lower() {
1109   LowerCommand *down = new LowerCommand(this);
1110   down->redo();
1111 }
1112 
1113 
1114 void ViewItem::remove() {
1115   RemoveCommand *remove = new RemoveCommand(this);
1116   remove->redo();
1117 }
1118 
1119 
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 
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 
1223 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 
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 
1278 bool ViewItem::dataPosLockable() const {
1279   return bool(dynamic_cast<PlotRenderItem *>(parentViewItem()));
1280 }
1281 
1282 void ViewItem::addToMenuForContextEvent(QMenu &menu) {
1283   Q_UNUSED(menu);
1284 }
1285 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
1715 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 
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 
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 
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 
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 
1819 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 
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 
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 
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 
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 
2098 void ViewItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
2099   if (view()->viewMode() == View::Data) {
2100     event->ignore();
2101     return;
2102   }
2103 }
2104 
2105 
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 
2144 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 
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 
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 
2239 void ViewItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
2240   QGraphicsRectItem::hoverMoveEvent(event);
2241   _hovering = true;
2242   update();
2243 }
2244 
2245 
2246 void ViewItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
2247   QGraphicsRectItem::hoverMoveEvent(event);
2248   //view()->setCursor(Qt::ArrowCursor);
2249 
2250   _hovering = false;
2251   update();
2252 }
2253 
2254 
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 
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 
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 
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 
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 
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 
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 
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 
2397 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 
2406 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 
2423 void ViewItem::updateView() {
2424   update();
2425 }
2426 
2427 
2428 qreal ViewItem::rotationAngle() const {
2429   return 180.0/ONE_PI * atan2(transform().m12(), transform().m11());
2430 }
2431 
2432 
2433 qreal ViewItem::rotationAngleRadians() const {
2434   return atan2(transform().m12(), transform().m11());
2435 }
2436 
2437 
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 
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 
2474 QString ViewItem::_automaticDescriptiveName() const {
2475   return typeName();
2476 }
2477 
2478 QString ViewItem::descriptionTip() const {
2479   return typeName();
2480 }
2481 
2482 ScriptInterface* ViewItem::createScriptInterface() {
2483   return new ViewItemSI(this);
2484 }
2485 
2486 ScriptInterface* ViewItem::scriptInterface() {
2487   if (!_interface) {
2488     _interface = createScriptInterface();
2489   }
2490   return _interface;
2491 }
2492 
2493 #ifndef QT_NO_DEBUG_STREAM
2494 QDebug operator<<(QDebug dbg, ViewItem *viewItem) {
2495     dbg.nospace() << viewItem->typeName();
2496     return dbg.space();
2497 }
2498 #endif
2499 
2500 
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 
2508 ViewItemCommand::~ViewItemCommand() {
2509 }
2510 
2511 
2512 
2513 CreateCommand::CreateCommand(const QString &text, QUndoCommand *parent)
2514     : ViewCommand(text, false, parent) {
2515 }
2516 
2517 
2518 CreateCommand::CreateCommand(View *view, const QString &text, QUndoCommand *parent)
2519     : ViewCommand(view, text, false, parent) {
2520 }
2521 
2522 
2523 CreateCommand::~CreateCommand() {
2524 }
2525 
2526 
2527 void CreateCommand::undo() {
2528   Q_ASSERT(_item);
2529   _item->hide();
2530 }
2531 
2532 
2533 void CreateCommand::redo() {
2534   Q_ASSERT(_item);
2535   _item->show();
2536 }
2537 
2538 
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 
2557 void CreateCommand::creationComplete() {
2558   _view->undoStack()->push(this);
2559   kstApp->mainWindow()->clearDrawingMarker();
2560   kstApp->mainWindow()->document()->setChanged(true);
2561 }
2562 
2563 
2564 void LayoutCommand::undo() {
2565   Q_ASSERT(_layout);
2566   _layout->reset();
2567 }
2568 
2569 
2570 void LayoutCommand::redo() {
2571   Q_ASSERT(_layout);
2572   _layout->apply();
2573 }
2574 
2575 
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 
2629 void AppendLayoutCommand::undo() {
2630   if (_layout) {
2631     _layout->reset();
2632   }
2633 }
2634 
2635 
2636 void AppendLayoutCommand::redo() {
2637   Q_ASSERT(_layout);
2638   _layout->apply();
2639 }
2640 
2641 
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 
2740 void MoveCommand::undo() {
2741   Q_ASSERT(_item);
2742   _item->setPos(_originalPos);
2743 }
2744 
2745 
2746 void MoveCommand::redo() {
2747   Q_ASSERT(_item);
2748   _item->setPos(_newPos);
2749 }
2750 
2751 
2752 void ResizeCommand::undo() {
2753   Q_ASSERT(_item);
2754   _item->setViewRect(_originalRect, true);
2755 }
2756 
2757 
2758 void ResizeCommand::redo() {
2759   Q_ASSERT(_item);
2760   _item->setViewRect(_newRect, true);
2761 }
2762 
2763 
2764 void RemoveCommand::undo() {
2765   Q_ASSERT(_item);
2766   _item->show();
2767 }
2768 
2769 
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 
2779 void RaiseCommand::undo() {
2780   Q_ASSERT(_item);
2781   _item->setZValue(_item->zValue() - 1);
2782 }
2783 
2784 
2785 void RaiseCommand::redo() {
2786   Q_ASSERT(_item);
2787   _item->setZValue(_item->zValue() + 1);
2788 }
2789 
2790 
2791 void LowerCommand::undo() {
2792   Q_ASSERT(_item);
2793   _item->setZValue(_item->zValue() + 1);
2794 }
2795 
2796 
2797 void LowerCommand::redo() {
2798   Q_ASSERT(_item);
2799   _item->setZValue(_item->zValue() - 1);
2800 }
2801 
2802 
2803 void TransformCommand::undo() {
2804   Q_ASSERT(_item);
2805   _item->setTransform(_originalTransform);
2806 }
2807 
2808 
2809 void TransformCommand::redo() {
2810   Q_ASSERT(_item);
2811   _item->setTransform(_newTransform);
2812 }
2813 
2814 
2815 
2816 
2817 MimeDataViewItem::MimeDataViewItem() : QMimeData() {
2818 }
2819 
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