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