Warning, file /office/calligra/libs/flake/KoCanvasControllerWidgetViewport_p.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 * 0003 * Copyright (C) 2006-2007, 2009 Thomas Zander <zander@kde.org> 0004 * Copyright (C) 2006 Thorsten Zachmann <zachmann@kde.org> 0005 * Copyright (C) 2007-2010 Boudewijn Rempt <boud@valdyas.org> 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "KoCanvasControllerWidgetViewport_p.h" 0024 #include "KoShape.h" 0025 #include "KoShape_p.h" 0026 #include "KoShapeFactoryBase.h" // for the SHAPE mimetypes 0027 #include "KoShapeRegistry.h" 0028 #include "KoShapeController.h" 0029 #include "KoShapeManager.h" 0030 #include "KoSelection.h" 0031 #include "KoCanvasBase.h" 0032 #include "KoShapeLayer.h" 0033 #include "KoShapePaste.h" 0034 #include "KoShapePaintingContext.h" 0035 #include "KoToolProxy.h" 0036 0037 #include <KoProperties.h> 0038 0039 #include <FlakeDebug.h> 0040 0041 #include <QPainter> 0042 #include <QDragEnterEvent> 0043 0044 #include <limits.h> 0045 #include <stdlib.h> 0046 0047 // ********** Viewport ********** 0048 Viewport::Viewport(KoCanvasControllerWidget *parent) 0049 : QWidget(parent) 0050 , m_draggedShape(0) 0051 , m_drawShadow(false) 0052 , m_canvas(0) 0053 , m_documentOffset(QPoint(0, 0)) 0054 , m_margin(0) 0055 { 0056 setAutoFillBackground(true); 0057 setAcceptDrops(true); 0058 setMouseTracking(true); 0059 m_parent = parent; 0060 } 0061 0062 void Viewport::setCanvas(QWidget *canvas) 0063 { 0064 if (m_canvas) { 0065 m_canvas->hide(); 0066 delete m_canvas; 0067 } 0068 m_canvas = canvas; 0069 if (!canvas) return; 0070 m_canvas->setParent(this); 0071 m_canvas->show(); 0072 if (!m_canvas->minimumSize().isNull()) { 0073 m_documentSize = m_canvas->minimumSize(); 0074 } 0075 resetLayout(); 0076 } 0077 0078 void Viewport::setDocumentSize(const QSize &size) 0079 { 0080 m_documentSize = size; 0081 resetLayout(); 0082 } 0083 0084 void Viewport::documentOffsetMoved(const QPoint &pt) 0085 { 0086 m_documentOffset = pt; 0087 resetLayout(); 0088 } 0089 0090 void Viewport::setDrawShadow(bool drawShadow) 0091 { 0092 m_drawShadow = drawShadow; 0093 } 0094 0095 0096 void Viewport::handleDragEnterEvent(QDragEnterEvent *event) 0097 { 0098 // if not a canvas set then ignore this, makes it possible to assume 0099 // we have a canvas in all the support methods. 0100 if (!(m_parent->canvas() && m_parent->canvas()->canvasWidget())) 0101 return; 0102 0103 // only allow dropping when active layer is editable 0104 KoSelection *selection = m_parent->canvas()->shapeManager()->selection(); 0105 KoShapeLayer *activeLayer = selection->activeLayer(); 0106 if (activeLayer && (!activeLayer->isEditable() || activeLayer->isGeometryProtected())) 0107 return; 0108 0109 const QMimeData *data = event->mimeData(); 0110 if (data->hasFormat(SHAPETEMPLATE_MIMETYPE) || 0111 data->hasFormat(SHAPEID_MIMETYPE)) { 0112 QByteArray itemData; 0113 bool isTemplate = true; 0114 if (data->hasFormat(SHAPETEMPLATE_MIMETYPE)) 0115 itemData = data->data(SHAPETEMPLATE_MIMETYPE); 0116 else { 0117 isTemplate = false; 0118 itemData = data->data(SHAPEID_MIMETYPE); 0119 } 0120 QDataStream dataStream(&itemData, QIODevice::ReadOnly); 0121 QString id; 0122 dataStream >> id; 0123 QString properties; 0124 if (isTemplate) 0125 dataStream >> properties; 0126 0127 // and finally, there is a point. 0128 QPointF offset; 0129 dataStream >> offset; 0130 0131 // The rest of this method is mostly a copy paste from the KoCreateShapeStrategy 0132 // So, lets remove this again when Zagge adds his new class that does this kind of thing. (KoLoadSave) 0133 KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value(id); 0134 if (! factory) { 0135 warnFlake << "Application requested a shape that is not registered '" << 0136 id << "', Ignoring"; 0137 event->ignore(); 0138 return; 0139 } 0140 event->setDropAction(Qt::CopyAction); 0141 event->accept(); 0142 0143 if (isTemplate) { 0144 KoProperties props; 0145 props.load(properties); 0146 m_draggedShape = factory->createShape(&props, m_parent->canvas()->shapeController()->resourceManager()); 0147 } else 0148 m_draggedShape = factory->createDefaultShape(m_parent->canvas()->shapeController()->resourceManager()); 0149 0150 Q_ASSERT(m_draggedShape); 0151 if (!m_draggedShape) return; 0152 0153 if (m_draggedShape->shapeId().isEmpty()) 0154 m_draggedShape->setShapeId(factory->id()); 0155 m_draggedShape->setZIndex(KoShapePrivate::MaxZIndex); 0156 m_draggedShape->setAbsolutePosition(correctPosition(event->pos())); 0157 0158 m_parent->canvas()->shapeManager()->addShape(m_draggedShape); 0159 } 0160 else if (data->hasFormat(KoOdf::mimeType(KoOdf::Text))) { 0161 KoShapeManager *sm = m_parent->canvas()->shapeManager(); 0162 KoShapePaste paste(m_parent->canvas(), sm->selection()->activeLayer()); 0163 if (paste.paste(KoOdf::Text, data)) { 0164 QList<KoShape *> shapes = paste.pastedShapes(); 0165 if (shapes.count() == 1) { 0166 m_draggedShape = shapes.first(); 0167 m_draggedShape->setZIndex(KoShapePrivate::MaxZIndex); 0168 event->setDropAction(Qt::CopyAction); 0169 } 0170 event->accept(); 0171 } 0172 } else { 0173 event->ignore(); 0174 } 0175 } 0176 0177 void Viewport::handleDropEvent(QDropEvent *event) 0178 { 0179 if (!m_draggedShape) { 0180 m_parent->canvas()->toolProxy()->dropEvent(event, correctPosition(event->pos())); 0181 return; 0182 } 0183 0184 repaint(m_draggedShape); 0185 m_parent->canvas()->shapeManager()->remove(m_draggedShape); // remove it to not interfere with z-index calc. 0186 0187 m_draggedShape->setPosition(QPointF(0, 0)); // always save position. 0188 QPointF newPos = correctPosition(event->pos()); 0189 m_parent->canvas()->clipToDocument(m_draggedShape, newPos); // ensure the shape is dropped inside the document. 0190 m_draggedShape->setAbsolutePosition(newPos); 0191 KUndo2Command * cmd = m_parent->canvas()->shapeController()->addShape(m_draggedShape); 0192 if (cmd) { 0193 m_parent->canvas()->addCommand(cmd); 0194 KoSelection *selection = m_parent->canvas()->shapeManager()->selection(); 0195 0196 // repaint selection before selecting newly create shape 0197 foreach(KoShape * shape, selection->selectedShapes()) 0198 shape->update(); 0199 0200 selection->deselectAll(); 0201 selection->select(m_draggedShape); 0202 } else 0203 delete m_draggedShape; 0204 0205 m_draggedShape = 0; 0206 } 0207 0208 QPointF Viewport::correctPosition(const QPoint &point) const 0209 { 0210 QWidget *canvasWidget = m_parent->canvas()->canvasWidget(); 0211 Q_ASSERT(canvasWidget); // since we should not allow drag if there is not. 0212 QPoint correctedPos(point.x() - canvasWidget->x(), point.y() - canvasWidget->y()); 0213 correctedPos += m_documentOffset; 0214 return m_parent->canvas()->viewToDocument(correctedPos); 0215 } 0216 0217 void Viewport::handleDragMoveEvent(QDragMoveEvent *event) 0218 { 0219 if (!m_draggedShape) { 0220 m_parent->canvas()->toolProxy()->dragMoveEvent(event, correctPosition(event->pos())); 0221 return; 0222 } 0223 0224 m_draggedShape->update(); 0225 repaint(m_draggedShape); 0226 m_draggedShape->setAbsolutePosition(correctPosition(event->pos())); 0227 m_draggedShape->update(); 0228 repaint(m_draggedShape); 0229 } 0230 0231 void Viewport::repaint(KoShape *shape) 0232 { 0233 QRect rect = m_parent->canvas()->viewConverter()->documentToView(shape->boundingRect()).toRect(); 0234 QWidget *canvasWidget = m_parent->canvas()->canvasWidget(); 0235 Q_ASSERT(canvasWidget); // since we should not allow drag if there is not. 0236 rect.moveLeft(rect.left() + canvasWidget->x() - m_documentOffset.x()); 0237 rect.moveTop(rect.top() + canvasWidget->y() - m_documentOffset.y()); 0238 rect.adjust(-2, -2, 2, 2); // adjust for antialias 0239 update(rect); 0240 } 0241 0242 void Viewport::handleDragLeaveEvent(QDragLeaveEvent *event) 0243 { 0244 if (m_draggedShape) { 0245 repaint(m_draggedShape); 0246 m_parent->canvas()->shapeManager()->remove(m_draggedShape); 0247 delete m_draggedShape; 0248 m_draggedShape = 0; 0249 } else { 0250 m_parent->canvas()->toolProxy()->dragLeaveEvent(event); 0251 } 0252 } 0253 0254 void Viewport::handlePaintEvent(QPainter &painter, QPaintEvent *event) 0255 { 0256 Q_UNUSED(event); 0257 // Draw the shadow around the canvas. 0258 if (m_parent->canvas() && m_parent->canvas()->canvasWidget() && m_drawShadow) { 0259 QWidget *canvas = m_parent->canvas()->canvasWidget(); 0260 painter.setPen(QPen(Qt::black, 0)); 0261 QRect rect(canvas->x(), canvas->y(), canvas->width(), canvas->height()); 0262 rect.adjust(-1, -1, 0, 0); 0263 painter.drawRect(rect); 0264 painter.drawLine(rect.right() + 2, rect.top() + 2, rect.right() + 2, rect.bottom() + 2); 0265 painter.drawLine(rect.left() + 2, rect.bottom() + 2, rect.right() + 2, rect.bottom() + 2); 0266 } 0267 if (m_draggedShape) { 0268 const KoViewConverter *vc = m_parent->canvas()->viewConverter(); 0269 0270 painter.save(); 0271 QWidget *canvasWidget = m_parent->canvas()->canvasWidget(); 0272 Q_ASSERT(canvasWidget); // since we should not allow drag if there is not. 0273 painter.translate(canvasWidget->x() - m_documentOffset.x(), 0274 canvasWidget->y() - m_documentOffset.y()); 0275 QPointF offset = vc->documentToView(m_draggedShape->position()); 0276 painter.setOpacity(0.6); 0277 painter.translate(offset.x(), offset.y()); 0278 painter.setRenderHint(QPainter::Antialiasing); 0279 KoShapePaintingContext paintContext; //FIXME 0280 m_draggedShape->paint(painter, *vc, paintContext); 0281 painter.restore(); 0282 } 0283 } 0284 0285 void Viewport::resetLayout() 0286 { 0287 // Determine the area we have to show 0288 QRect viewRect(m_documentOffset, size()); 0289 0290 const int viewH = viewRect.height(); 0291 const int viewW = viewRect.width(); 0292 0293 const int docH = m_documentSize.height(); 0294 const int docW = m_documentSize.width(); 0295 0296 int moveX = 0; 0297 int moveY = 0; 0298 0299 int resizeW = viewW; 0300 int resizeH = viewH; 0301 0302 // debugFlake <<"viewH:" << viewH << endl 0303 // << "docH: " << docH << endl 0304 // << "viewW: " << viewW << endl 0305 // << "docW: " << docW << endl; 0306 0307 if (viewH == docH && viewW == docW) { 0308 // Do nothing 0309 resizeW = docW; 0310 resizeH = docH; 0311 } else if (viewH > docH && viewW > docW) { 0312 // Show entire canvas centered 0313 moveX = (viewW - docW) / 2; 0314 moveY = (viewH - docH) / 2; 0315 resizeW = docW; 0316 resizeH = docH; 0317 } else if (viewW > docW) { 0318 // Center canvas horizontally 0319 moveX = (viewW - docW) / 2; 0320 resizeW = docW; 0321 0322 int marginTop = m_margin - m_documentOffset.y(); 0323 int marginBottom = viewH - (m_documentSize.height() - m_documentOffset.y()); 0324 0325 if (marginTop > 0) moveY = marginTop; 0326 if (marginTop > 0) resizeH = viewH - marginTop; 0327 if (marginBottom > 0) resizeH = viewH - marginBottom; 0328 } else if (viewH > docH) { 0329 // Center canvas vertically 0330 moveY = (viewH - docH) / 2; 0331 resizeH = docH; 0332 0333 int marginLeft = m_margin - m_documentOffset.x(); 0334 int marginRight = viewW - (m_documentSize.width() - m_documentOffset.x()); 0335 0336 if (marginLeft > 0) moveX = marginLeft; 0337 if (marginLeft > 0) resizeW = viewW - marginLeft; 0338 if (marginRight > 0) resizeW = viewW - marginRight; 0339 } else { 0340 // Take care of the margin around the canvas 0341 int marginTop = m_margin - m_documentOffset.y(); 0342 int marginLeft = m_margin - m_documentOffset.x(); 0343 int marginRight = viewW - (m_documentSize.width() - m_documentOffset.x()); 0344 int marginBottom = viewH - (m_documentSize.height() - m_documentOffset.y()); 0345 0346 if (marginTop > 0) moveY = marginTop; 0347 if (marginLeft > 0) moveX = marginLeft; 0348 0349 if (marginTop > 0) resizeH = viewH - marginTop; 0350 if (marginLeft > 0) resizeW = viewW - marginLeft; 0351 if (marginRight > 0) resizeW = viewW - marginRight; 0352 if (marginBottom > 0) resizeH = viewH - marginBottom; 0353 } 0354 if (m_parent->canvasMode() == KoCanvasController::AlignTop) { 0355 // have up to m_margin pixels at top. 0356 moveY = qMin(m_margin, moveY); 0357 } 0358 if (m_canvas) { 0359 QRect geom; 0360 if (m_parent->canvasMode() == KoCanvasController::Infinite) 0361 geom = QRect(0, 0, viewW, viewH); 0362 else 0363 geom = QRect(moveX, moveY, resizeW, resizeH); 0364 if (m_canvas->geometry() != geom) { 0365 m_canvas->setGeometry(geom); 0366 m_canvas->update(); 0367 } 0368 } 0369 if (m_drawShadow) { 0370 update(); 0371 } 0372 0373 emit sizeChanged(); 0374 #if 0 0375 debugFlake <<"View port geom:" << geometry(); 0376 if (m_canvas) 0377 debugFlake <<"Canvas widget geom:" << m_canvas->geometry(); 0378 #endif 0379 }