File indexing completed on 2024-05-12 15:56:38

0001 /* This file is part of the KDE project
0002  *
0003  * SPDX-FileCopyrightText: 2006, 2008-2009 Thomas Zander <zander@kde.org>
0004  * SPDX-FileCopyrightText: 2006 Peter Simonsson <peter.simonsson@gmail.com>
0005  * SPDX-FileCopyrightText: 2006, 2009 Thorsten Zachmann <zachmann@kde.org>
0006  * SPDX-FileCopyrightText: 2007-2010 Boudewijn Rempt <boud@valdyas.org>
0007  * SPDX-FileCopyrightText: 2007 C. Boemann <cbo@boemann.dk>
0008  * SPDX-FileCopyrightText: 2006-2008 Jan Hambrecht <jaham@gmx.net>
0009  *
0010  * SPDX-License-Identifier: LGPL-2.0-or-later
0011  */
0012 
0013 #include "KoCanvasControllerWidget.h"
0014 #include "KoCanvasControllerWidget_p.h"
0015 
0016 #include "KoCanvasControllerWidgetViewport_p.h"
0017 #include "KoShape.h"
0018 #include "KoViewConverter.h"
0019 #include "KoCanvasBase.h"
0020 #include "KoCanvasObserverBase.h"
0021 #include "KoCanvasSupervisor.h"
0022 #include "KoToolManager_p.h"
0023 
0024 #include <FlakeDebug.h>
0025 #include <QMouseEvent>
0026 #include <QPainter>
0027 #include <QScrollBar>
0028 #include <QEvent>
0029 #include <QDockWidget>
0030 #include <QTimer>
0031 #include <QPointer>
0032 
0033 #include <QOpenGLWidget>
0034 
0035 #include <math.h>
0036 
0037 void KoCanvasControllerWidget::Private::setDocumentOffset()
0038 {
0039     // The margins scroll the canvas widget inside the viewport, not
0040     // the document. The documentOffset is meant to be the value that
0041     // the canvas must add to the update rect in its paint event, to
0042     // compensate.
0043 
0044     QPoint pt(q->horizontalScrollBar()->value(), q->verticalScrollBar()->value());
0045     q->proxyObject->emitMoveDocumentOffset(pt);
0046 
0047     QWidget *canvasWidget = canvas->canvasWidget();
0048 
0049     if (canvasWidget) {
0050         // If it isn't an OpenGL canvas
0051         if (qobject_cast<QOpenGLWidget*>(canvasWidget) == 0) {
0052             QPoint diff = q->documentOffset() - pt;
0053             canvasWidget->scroll(diff.x(), diff.y(), canvasWidget->rect());
0054         }
0055     }
0056 
0057     q->setDocumentOffset(pt);
0058 }
0059 
0060 void KoCanvasControllerWidget::Private::resetScrollBars()
0061 {
0062     // The scrollbar value always points at the top-left corner of the
0063     // bit of image we paint.
0064 
0065     int docH = (int)q->documentSize().height() + q->margin();
0066     int docW = (int)q->documentSize().width() + q->margin();
0067     int drawH = viewportWidget->height();
0068     int drawW = viewportWidget->width();
0069 
0070     QScrollBar *hScroll = q->horizontalScrollBar();
0071     QScrollBar *vScroll = q->verticalScrollBar();
0072 
0073     int horizontalReserve = vastScrollingFactor * drawW;
0074     int verticalReserve = vastScrollingFactor * drawH;
0075 
0076     int xMin = -horizontalReserve;
0077     int yMin = -verticalReserve;
0078 
0079     int xMax = docW - drawW + horizontalReserve;
0080     int yMax = docH - drawH + verticalReserve;
0081 
0082     hScroll->setRange(xMin, xMax);
0083     vScroll->setRange(yMin, yMax);
0084 
0085     int fontheight = QFontMetrics(q->font()).height();
0086 
0087     vScroll->setPageStep(drawH);
0088     vScroll->setSingleStep(fontheight);
0089     hScroll->setPageStep(drawW);
0090     hScroll->setSingleStep(fontheight);
0091 
0092 }
0093 
0094 void KoCanvasControllerWidget::Private::emitPointerPositionChangedSignals(QEvent *event)
0095 {
0096     if (!canvas) return;
0097     if (!canvas->viewConverter()) return;
0098 
0099     QPoint pointerPos;
0100     QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event);
0101     if (mouseEvent) {
0102         pointerPos = mouseEvent->pos();
0103     } else {
0104         QTabletEvent *tabletEvent = dynamic_cast<QTabletEvent*>(event);
0105         if (tabletEvent) {
0106             pointerPos = tabletEvent->pos();
0107         }
0108     }
0109 
0110     QPoint pixelPos = (pointerPos - canvas->documentOrigin()) + q->documentOffset();
0111     QPointF documentPos = canvas->viewConverter()->viewToDocument(pixelPos);
0112 
0113     q->proxyObject->emitDocumentMousePositionChanged(documentPos);
0114     q->proxyObject->emitCanvasMousePositionChanged(pointerPos);
0115 }
0116 
0117 
0118 #include <QTime>
0119 
0120 void KoCanvasControllerWidget::Private::activate()
0121 {
0122     if (!observerProvider) {
0123         return;
0124     }
0125     KoCanvasBase *canvas = q->canvas();
0126     Q_FOREACH (KoCanvasObserverBase *docker, observerProvider->canvasObservers()) {
0127         KoCanvasObserverBase *observer = dynamic_cast<KoCanvasObserverBase*>(docker);
0128         if (observer) {
0129             observer->setObservedCanvas(canvas);
0130         }
0131     }
0132 
0133 }
0134 
0135 void KoCanvasControllerWidget::Private::unsetCanvas()
0136 {
0137     if (!observerProvider) {
0138         return;
0139     }
0140     Q_FOREACH (KoCanvasObserverBase *docker, observerProvider->canvasObservers()) {
0141         KoCanvasObserverBase *observer = dynamic_cast<KoCanvasObserverBase*>(docker);
0142        if (observer) {
0143             if (observer->observedCanvas() == q->canvas()) {
0144                 observer->unsetObservedCanvas();
0145             }
0146         }
0147     }
0148 }
0149 
0150 ////////////
0151 KoCanvasControllerWidget::KoCanvasControllerWidget(KisKActionCollection * actionCollection, KoCanvasSupervisor *observerProvider, QWidget *parent)
0152     : QAbstractScrollArea(parent)
0153     , KoCanvasController(actionCollection)
0154     , d(new Private(this, observerProvider))
0155 {
0156     // We need to set this as QDeclarativeView sets them a bit different from QAbstractScrollArea
0157     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0158 
0159     // And then our own Viewport
0160     d->viewportWidget = new Viewport(this);
0161     setViewport(d->viewportWidget);
0162     d->viewportWidget->setFocusPolicy(Qt::NoFocus);
0163     setFocusPolicy(Qt::NoFocus);
0164     setFrameStyle(0);
0165 
0166     //setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
0167     setAutoFillBackground(false);
0168     /*
0169       Fixes:   apps starting at zero zoom.
0170       Details: Since the document is set on the mainwindow before loading commences the inial show/layout can choose
0171           to set the document to be very small, even to be zero pixels tall.  Setting a sane minimum size on the
0172           widget means we no longer get rounding errors in zooming and we no longer end up with zero-zoom.
0173       Note: KoPage apps should probably startup with a sane document size; for Krita that's impossible
0174      */
0175     setMinimumSize(QSize(50, 50));
0176     setMouseTracking(true);
0177 
0178     connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateCanvasOffsetX()));
0179     connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateCanvasOffsetY()));
0180     connect(d->viewportWidget, SIGNAL(sizeChanged()), this, SLOT(updateCanvasOffsetX()));
0181     connect(proxyObject, SIGNAL(moveDocumentOffset(QPoint)), d->viewportWidget, SLOT(documentOffsetMoved(QPoint)));
0182 }
0183 
0184 KoCanvasControllerWidget::~KoCanvasControllerWidget()
0185 {
0186     delete d;
0187 }
0188 
0189 void KoCanvasControllerWidget::activate()
0190 {
0191     d->activate();
0192 }
0193 
0194 void KoCanvasControllerWidget::scrollContentsBy(int dx, int dy)
0195 {
0196     Q_UNUSED(dx);
0197     Q_UNUSED(dy);
0198     d->setDocumentOffset();
0199 }
0200 
0201 QSizeF KoCanvasControllerWidget::viewportSize() const
0202 {
0203     // Calculate viewport size aligned to device pixels to match KisOpenGLCanvas2.
0204     qreal dpr = viewport()->devicePixelRatioF();
0205     int viewportWidth = static_cast<int>(viewport()->width() * dpr);
0206     int viewportHeight = static_cast<int>(viewport()->height() * dpr);
0207     return QSizeF(viewportWidth / dpr, viewportHeight / dpr);
0208 }
0209 
0210 void KoCanvasControllerWidget::resizeEvent(QResizeEvent *resizeEvent)
0211 {
0212     proxyObject->emitSizeChanged(resizeEvent->size());
0213 
0214     // XXX: When resizing, keep the area we're looking at now in the
0215     // center of the resized view.
0216     resetScrollBars();
0217     d->setDocumentOffset();
0218 }
0219 
0220 void KoCanvasControllerWidget::setCanvas(KoCanvasBase *canvas)
0221 {
0222     if (d->canvas) {
0223         d->unsetCanvas();
0224         proxyObject->emitCanvasRemoved(this);
0225         d->canvas->setCanvasController(0);
0226         d->canvas->canvasWidget()->removeEventFilter(this);
0227     }
0228 
0229     d->canvas = canvas;
0230 
0231     if (d->canvas) {
0232         d->canvas->setCanvasController(this);
0233         changeCanvasWidget(d->canvas->canvasWidget());
0234 
0235         proxyObject->emitCanvasSet(this);
0236         QTimer::singleShot(0, this, SLOT(activate()));
0237 
0238         setPreferredCenterFractionX(0);
0239         setPreferredCenterFractionY(0);
0240     }
0241 }
0242 
0243 KoCanvasBase* KoCanvasControllerWidget::canvas() const
0244 {
0245     if (d->canvas.isNull()) return 0;
0246     return d->canvas;
0247 }
0248 
0249 void KoCanvasControllerWidget::changeCanvasWidget(QWidget *widget)
0250 {
0251     if (d->viewportWidget->canvas()) {
0252         widget->setCursor(d->viewportWidget->canvas()->cursor());
0253         d->viewportWidget->canvas()->removeEventFilter(this);
0254     }
0255 
0256     d->viewportWidget->setCanvas(widget);
0257     setFocusProxy(d->canvas->canvasWidget());
0258 }
0259 
0260 int KoCanvasControllerWidget::visibleHeight() const
0261 {
0262     if (d->canvas == 0)
0263         return 0;
0264     QWidget *canvasWidget = canvas()->canvasWidget();
0265 
0266     int height1;
0267     if (canvasWidget == 0)
0268         height1 = viewport()->height();
0269     else
0270         height1 = qMin(viewport()->height(), canvasWidget->height());
0271     int height2 = height();
0272     return qMin(height1, height2);
0273 }
0274 
0275 int KoCanvasControllerWidget::visibleWidth() const
0276 {
0277     if (d->canvas == 0)
0278         return 0;
0279     QWidget *canvasWidget = canvas()->canvasWidget();
0280 
0281     int width1;
0282     if (canvasWidget == 0)
0283         width1 = viewport()->width();
0284     else
0285         width1 = qMin(viewport()->width(), canvasWidget->width());
0286     int width2 = width();
0287     return qMin(width1, width2);
0288 }
0289 
0290 int KoCanvasControllerWidget::canvasOffsetX() const
0291 {
0292     int offset = -horizontalScrollBar()->value();
0293 
0294     if (d->canvas) {
0295         offset += d->canvas->canvasWidget()->x() + frameWidth();
0296     }
0297 
0298     return offset;
0299 }
0300 
0301 int KoCanvasControllerWidget::canvasOffsetY() const
0302 {
0303     int offset = -verticalScrollBar()->value();
0304 
0305     if (d->canvas) {
0306         offset += d->canvas->canvasWidget()->y() + frameWidth();
0307     }
0308 
0309     return offset;
0310 }
0311 
0312 void KoCanvasControllerWidget::updateCanvasOffsetX()
0313 {
0314     proxyObject->emitCanvasOffsetXChanged(canvasOffsetX());
0315     if (d->ignoreScrollSignals)
0316         return;
0317 
0318     setPreferredCenterFractionX((horizontalScrollBar()->value()
0319                                  + viewport()->width() / 2.0) / documentSize().width());
0320 }
0321 
0322 void KoCanvasControllerWidget::updateCanvasOffsetY()
0323 {
0324     proxyObject->emitCanvasOffsetYChanged(canvasOffsetY());
0325     if (d->ignoreScrollSignals)
0326         return;
0327 
0328     setPreferredCenterFractionY((verticalScrollBar()->value()
0329                                  + verticalScrollBar()->pageStep() / 2.0) / documentSize().height());
0330 }
0331 
0332 void KoCanvasControllerWidget::ensureVisible(KoShape *shape)
0333 {
0334     Q_ASSERT(shape);
0335     ensureVisible(d->canvas->viewConverter()->documentToView(shape->boundingRect()));
0336 }
0337 
0338 void KoCanvasControllerWidget::ensureVisible(const QRectF &rect, bool smooth)
0339 {
0340     QRect currentVisible(-canvasOffsetX(), -canvasOffsetY(), visibleWidth(), visibleHeight());
0341 
0342     QRect viewRect = rect.toRect();
0343     viewRect.translate(d->canvas->documentOrigin());
0344     if (!viewRect.isValid() || currentVisible.contains(viewRect))
0345         return; // its visible. Nothing to do.
0346 
0347     // if we move, we move a little more so the amount of times we have to move is less.
0348     int jumpWidth = smooth ? 0 : currentVisible.width() / 5;
0349     int jumpHeight = smooth ? 0 : currentVisible.height() / 5;
0350     if (!smooth && viewRect.width() + jumpWidth > currentVisible.width())
0351         jumpWidth = 0;
0352     if (!smooth && viewRect.height() + jumpHeight > currentVisible.height())
0353         jumpHeight = 0;
0354 
0355     int horizontalMove = 0;
0356     if (currentVisible.width() <= viewRect.width())      // center view
0357         horizontalMove = viewRect.center().x() - currentVisible.center().x();
0358     else if (currentVisible.x() > viewRect.x())          // move left
0359         horizontalMove = viewRect.x() - currentVisible.x() - jumpWidth;
0360     else if (currentVisible.right() < viewRect.right())  // move right
0361         horizontalMove = viewRect.right() - qMax(0, currentVisible.right() - jumpWidth);
0362 
0363     int verticalMove = 0;
0364     if (currentVisible.height() <= viewRect.height())       // center view
0365         verticalMove = viewRect.center().y() - currentVisible.center().y();
0366     if (currentVisible.y() > viewRect.y())               // move up
0367         verticalMove = viewRect.y() - currentVisible.y() - jumpHeight;
0368     else if (currentVisible.bottom() < viewRect.bottom()) // move down
0369         verticalMove = viewRect.bottom() - qMax(0, currentVisible.bottom() - jumpHeight);
0370 
0371     pan(QPoint(horizontalMove, verticalMove));
0372 }
0373 
0374 void KoCanvasControllerWidget::recenterPreferred()
0375 {
0376     const bool oldIgnoreScrollSignals = d->ignoreScrollSignals;
0377     d->ignoreScrollSignals = true;
0378 
0379     QPointF center = preferredCenter();
0380 
0381     // convert into a viewport based point
0382     center.rx() += d->canvas->canvasWidget()->x() + frameWidth();
0383     center.ry() += d->canvas->canvasWidget()->y() + frameWidth();
0384 
0385     // scroll to a new center point
0386     QPointF topLeft = center - 0.5 * QPointF(viewport()->width(), viewport()->height());
0387     setScrollBarValue(topLeft.toPoint());
0388 
0389     d->ignoreScrollSignals = oldIgnoreScrollSignals;
0390 }
0391 
0392 void KoCanvasControllerWidget::zoomIn(const QPoint &center)
0393 {
0394     zoomBy(center, sqrt(2.0));
0395 }
0396 
0397 void KoCanvasControllerWidget::zoomOut(const QPoint &center)
0398 {
0399     zoomBy(center, sqrt(0.5));
0400 }
0401 
0402 
0403 void KoCanvasControllerWidget::zoomBy(const QPoint &center, qreal zoom)
0404 {
0405     const QPointF oldCenter = preferredCenter();
0406     const QPointF newCenter = center + scrollBarValue();
0407     const QPointF stillPoint = (zoom * newCenter - oldCenter) / (zoom - 1.0);
0408 
0409     proxyObject->emitZoomRelative(zoom, stillPoint);
0410 }
0411 
0412 void KoCanvasControllerWidget::zoomTo(const QRect &viewRect)
0413 {
0414     qreal scale;
0415 
0416     if (1.0 * viewport()->width() / viewRect.width() > 1.0 * viewport()->height() / viewRect.height())
0417         scale = 1.0 * viewport()->height() / viewRect.height();
0418     else
0419         scale = 1.0 * viewport()->width() / viewRect.width();
0420 
0421     zoomBy(viewRect.center(), scale);
0422 }
0423 
0424 void KoCanvasControllerWidget::updateDocumentSize(const QSizeF &sz, bool recalculateCenter)
0425 {
0426     // Don't update if the document-size didn't changed to prevent infinite loops and unneeded updates.
0427     if (KoCanvasController::documentSize() == sz)
0428         return;
0429 
0430     if (!recalculateCenter) {
0431         // assume the distance from the top stays equal and recalculate the center.
0432         setPreferredCenterFractionX(documentSize().width() * preferredCenterFractionX() / sz.width());
0433         setPreferredCenterFractionY(documentSize().height() * preferredCenterFractionY() / sz.height());
0434     }
0435 
0436     const bool oldIgnoreScrollSignals = d->ignoreScrollSignals;
0437     d->ignoreScrollSignals = true;
0438     KoCanvasController::setDocumentSize(sz);
0439     d->viewportWidget->setDocumentSize(sz);
0440     resetScrollBars();
0441 
0442     // Always emit the new offset.
0443     updateCanvasOffsetX();
0444     updateCanvasOffsetY();
0445 
0446     d->ignoreScrollSignals = oldIgnoreScrollSignals;
0447 }
0448 
0449 void KoCanvasControllerWidget::setZoomWithWheel(bool zoom)
0450 {
0451     d->zoomWithWheel = zoom;
0452 }
0453 
0454 void KoCanvasControllerWidget::setVastScrolling(qreal factor)
0455 {
0456     d->vastScrollingFactor = factor;
0457 }
0458 
0459 QPointF KoCanvasControllerWidget::currentCursorPosition() const
0460 {
0461     QWidget *canvasWidget = d->canvas->canvasWidget();
0462     const KoViewConverter *converter = d->canvas->viewConverter();
0463     return converter->viewToDocument(canvasWidget->mapFromGlobal(QCursor::pos()) + d->canvas->canvasController()->documentOffset() - canvasWidget->pos());
0464 }
0465 
0466 void KoCanvasControllerWidget::pan(const QPoint &distance)
0467 {
0468     QPoint sourcePoint = scrollBarValue();
0469     setScrollBarValue(sourcePoint + distance);
0470 }
0471 
0472 void KoCanvasControllerWidget::panUp()
0473 {
0474     pan(QPoint(0, verticalScrollBar()->singleStep()));
0475 }
0476 
0477 void KoCanvasControllerWidget::panDown()
0478 {
0479     pan(QPoint(0, -verticalScrollBar()->singleStep()));
0480 }
0481 
0482 void KoCanvasControllerWidget::panLeft()
0483 {
0484     pan(QPoint(horizontalScrollBar()->singleStep(), 0));
0485 }
0486 
0487 void KoCanvasControllerWidget::panRight()
0488 {
0489     pan(QPoint(-horizontalScrollBar()->singleStep(), 0));
0490 }
0491 
0492 void KoCanvasControllerWidget::setPreferredCenter(const QPointF &viewPoint)
0493 {
0494     setPreferredCenterFractionX(viewPoint.x() / documentSize().width());
0495     setPreferredCenterFractionY(viewPoint.y() / documentSize().height());
0496     recenterPreferred();
0497 }
0498 
0499 QPointF KoCanvasControllerWidget::preferredCenter() const
0500 {
0501     QPointF center;
0502     center.setX(preferredCenterFractionX() * documentSize().width());
0503     center.setY(preferredCenterFractionY() * documentSize().height());
0504     return center;
0505 }
0506 
0507 void KoCanvasControllerWidget::paintEvent(QPaintEvent *event)
0508 {
0509     QPainter gc(viewport());
0510     d->viewportWidget->handlePaintEvent(gc, event);
0511 }
0512 
0513 void KoCanvasControllerWidget::dragEnterEvent(QDragEnterEvent *event)
0514 {
0515     d->viewportWidget->handleDragEnterEvent(event);
0516 }
0517 
0518 void KoCanvasControllerWidget::dropEvent(QDropEvent *event)
0519 {
0520     d->viewportWidget->handleDropEvent(event);
0521 }
0522 
0523 void KoCanvasControllerWidget::dragMoveEvent(QDragMoveEvent *event)
0524 {
0525     d->viewportWidget->handleDragMoveEvent(event);
0526 }
0527 
0528 void KoCanvasControllerWidget::dragLeaveEvent(QDragLeaveEvent *event)
0529 {
0530     d->viewportWidget->handleDragLeaveEvent(event);
0531 }
0532 
0533 void KoCanvasControllerWidget::wheelEvent(QWheelEvent *event)
0534 {
0535     if (d->zoomWithWheel != ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier)) {
0536         const qreal zoomCoeff = event->delta() > 0 ? sqrt(2.0) : sqrt(0.5);
0537         zoomRelativeToPoint(event->pos(), zoomCoeff);
0538 
0539         event->accept();
0540     } else
0541         QAbstractScrollArea::wheelEvent(event);
0542 }
0543 
0544 void KoCanvasControllerWidget::zoomRelativeToPoint(const QPoint &widgetPoint, qreal zoomCoeff)
0545 {
0546     const QPoint offset = scrollBarValue();
0547     const QPoint mousePos(widgetPoint + offset);
0548 
0549     const bool oldIgnoreScrollSignals = d->ignoreScrollSignals;
0550     d->ignoreScrollSignals = true;
0551     proxyObject->emitZoomRelative(zoomCoeff, mousePos);
0552     d->ignoreScrollSignals = oldIgnoreScrollSignals;
0553 }
0554 
0555 bool KoCanvasControllerWidget::focusNextPrevChild(bool)
0556 {
0557     // we always return false meaning the canvas takes keyboard focus, but never gives it away.
0558     return false;
0559 }
0560 
0561 bool KoCanvasControllerWidget::viewportEvent(QEvent *event) {
0562     // Workaround: Don't let QAbstractScrollArea handle Gesture events. Because
0563     // Qt's detection of touch point positions is a bit buggy, it is handled
0564     // with custom algorithms in the KisInputManager. But we must also not let
0565     // the corresponding event propagate to the parent QAbstractScrollArea.
0566     if (event->type() == QEvent::Gesture) {
0567         return false;
0568     }
0569     return QAbstractScrollArea::viewportEvent(event);
0570 }
0571 
0572 void KoCanvasControllerWidget::setMargin(int margin)
0573 {
0574     KoCanvasController::setMargin(margin);
0575     Q_ASSERT(d->viewportWidget);
0576     d->viewportWidget->setMargin(margin);
0577 }
0578 
0579 QPoint KoCanvasControllerWidget::scrollBarValue() const
0580 {
0581     QScrollBar * hBar = horizontalScrollBar();
0582     QScrollBar * vBar = verticalScrollBar();
0583 
0584     return QPoint(hBar->value(), vBar->value());
0585 }
0586 
0587 void KoCanvasControllerWidget::setScrollBarValue(const QPoint &value)
0588 {
0589     QScrollBar * hBar = horizontalScrollBar();
0590     QScrollBar * vBar = verticalScrollBar();
0591 
0592     hBar->setValue(value.x());
0593     vBar->setValue(value.y());
0594 }
0595 
0596 void KoCanvasControllerWidget::resetScrollBars()
0597 {
0598     d->resetScrollBars();
0599 }
0600 
0601 qreal KoCanvasControllerWidget::vastScrollingFactor() const
0602 {
0603     return d->vastScrollingFactor;
0604 }
0605 
0606 KoCanvasControllerWidget::Private *KoCanvasControllerWidget::priv()
0607 {
0608     return d;
0609 }
0610 
0611 //have to include this because of Q_PRIVATE_SLOT
0612 #include "moc_KoCanvasControllerWidget.cpp"