File indexing completed on 2024-05-12 16:30:49

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2008,2010 Jan Hambrecht <jaham@gmx.net>
0003  * Copyright (C) 2010 Boudewijn Rempt <boud@kogmbh.com>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #include "KarbonZoomController.h"
0022 
0023 #include <KarbonCanvas.h>
0024 #include <KoZoomAction.h>
0025 #include <KoCanvasController.h>
0026 #include <KoCanvasBase.h>
0027 #include <KoZoomHandler.h>
0028 #include <KoCanvasResourceManager.h>
0029 #include <KoShapeManager.h>
0030 #include <KoSelection.h>
0031 
0032 #include <kactioncollection.h>
0033 #include <klocalizedstring.h>
0034 
0035 #include <math.h>
0036 
0037 class KarbonZoomController::Private
0038 {
0039 public:
0040     Private()
0041             : canvasController(0), canvas(0), zoomHandler(0), action(0)
0042             , fitMargin(25)
0043     {
0044     }
0045 
0046     ~Private()
0047     {
0048         delete action;
0049     }
0050 
0051     KoCanvasController * canvasController;
0052     KarbonCanvas * canvas;
0053     KoZoomHandler * zoomHandler;
0054     KoZoomAction * action;
0055     QSizeF pageSize;
0056     int fitMargin;
0057 };
0058 
0059 KarbonZoomController::KarbonZoomController(KoCanvasController *controller, KActionCollection *actionCollection, QObject *parent)
0060         : QObject(parent), d(new Private())
0061 {
0062     d->canvasController = controller;
0063 
0064     d->action = new KoZoomAction(KoZoomMode::ZOOM_WIDTH | KoZoomMode::ZOOM_PAGE, i18n("Zoom"), this);
0065     d->action->setSpecialButtons(KoZoomAction::ZoomToSelection | KoZoomAction::ZoomToAll);
0066     connect(d->action, SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)),
0067             this, SLOT(setZoom(KoZoomMode::Mode,qreal)));
0068     connect(d->action, SIGNAL(zoomedToSelection()),
0069             this, SIGNAL(zoomedToSelection()));
0070     connect(d->action, SIGNAL(zoomedToAll()),
0071             this, SIGNAL(zoomedToAll()));
0072 
0073     actionCollection->addAction("view_zoom", d->action);
0074     actionCollection->addAction(KStandardAction::ZoomIn, "zoom_in", this, SLOT(zoomInRelative()));
0075     actionCollection->addAction(KStandardAction::ZoomOut, "zoom_out", this, SLOT(zoomOutRelative()));
0076 
0077     d->canvas = dynamic_cast<KarbonCanvas*>(d->canvasController->canvas());
0078     d->zoomHandler = dynamic_cast<KoZoomHandler*>(const_cast<KoViewConverter*>(d->canvas->viewConverter()));
0079 
0080     connect(d->canvasController->proxyObject, SIGNAL(sizeChanged(QSize)), this, SLOT(setAvailableSize()));
0081     connect(d->canvasController->proxyObject, SIGNAL(zoomRelative(qreal,QPointF)), this, SLOT(requestZoomRelative(qreal,QPointF)));
0082     connect(d->canvasController->proxyObject, SIGNAL(moveDocumentOffset(QPoint)),
0083             d->canvas, SLOT(setDocumentOffset(QPoint)));
0084 
0085     connect(d->canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)),
0086             this, SLOT(canvasResourceChanged(int,QVariant)));
0087 }
0088 
0089 KarbonZoomController::~KarbonZoomController()
0090 {
0091     delete d;
0092 }
0093 
0094 KoZoomAction * KarbonZoomController::zoomAction() const
0095 {
0096     return d->action;
0097 }
0098 
0099 void KarbonZoomController::setZoomMode(KoZoomMode::Mode mode)
0100 {
0101     setZoom(mode, 1.0);
0102 }
0103 
0104 void KarbonZoomController::setZoom(KoZoomMode::Mode mode, qreal zoom)
0105 {
0106     setZoom(mode, zoom, d->canvasController->preferredCenter());
0107 }
0108 
0109 void KarbonZoomController::setZoom(KoZoomMode::Mode mode, qreal zoom, const QPointF &stillPoint)
0110 {
0111     if (d->zoomHandler->zoomMode() == mode && d->zoomHandler->zoom() == zoom)
0112         return; // no change
0113 
0114     qreal oldEffectiveZoom = d->action->effectiveZoom();
0115 
0116     d->zoomHandler->setZoomMode(mode);
0117 
0118     if (mode == KoZoomMode::ZOOM_CONSTANT) {
0119         if (zoom == 0.0) return;
0120         d->action->setZoom(zoom);
0121     } else if (mode == KoZoomMode::ZOOM_WIDTH) {
0122         zoom = (d->canvasController->viewportSize().width() - 2 * d->fitMargin)
0123                / (d->zoomHandler->resolutionX() * d->pageSize.width());
0124         d->action->setSelectedZoomMode(mode);
0125         d->action->setEffectiveZoom(zoom);
0126     } else if (mode == KoZoomMode::ZOOM_PAGE) {
0127         zoom = (d->canvasController->viewportSize().width() - 2 * d->fitMargin)
0128                / (d->zoomHandler->resolutionX() * d->pageSize.width());
0129         zoom = qMin(zoom, (d->canvasController->viewportSize().height() - 2 * d->fitMargin)
0130                     / (d->zoomHandler->resolutionY() * d->pageSize.height()));
0131 
0132         d->action->setSelectedZoomMode(mode);
0133         d->action->setEffectiveZoom(zoom);
0134     }
0135 
0136     d->zoomHandler->setZoom(zoom);
0137 
0138     // Tell the canvasController that the zoom has changed
0139     // Actually canvasController doesn't know about zoom, but the document in pixels
0140     // has change as a result of the zoom change
0141     QRectF documentRect = d->canvas->documentViewRect();
0142     QSizeF viewSize = d->zoomHandler->documentToView(documentRect).size();
0143     d->canvasController->updateDocumentSize(QSize(qRound(viewSize.width()), qRound(viewSize.height())), true);
0144 
0145     d->canvas->adjustOrigin();
0146 
0147     // Finally ask the canvasController to recenter
0148     QPointF documentCenter;
0149     if (mode == KoZoomMode::ZOOM_CONSTANT) {
0150         KoSelection * selection = d->canvas->shapeManager()->selection();
0151         if (selection->count()) {
0152             QPointF docCenter = selection->boundingRect().center();
0153             documentCenter = d->canvas->documentOrigin() + d->zoomHandler->documentToView(docCenter);
0154         } else {
0155             qreal zoomCoeff = d->action->effectiveZoom() / oldEffectiveZoom;
0156             QPointF oldCenter = d->canvasController->preferredCenter();
0157             documentCenter = stillPoint * zoomCoeff - (stillPoint - 1.0 / zoomCoeff * oldCenter);
0158         }
0159     } else {
0160         // center the page rect when change the zoom mode to ZOOM_PAGE or ZOOM_WIDTH
0161         QRectF pageRect(-documentRect.topLeft(), d->pageSize);
0162         documentCenter = d->zoomHandler->documentToView(pageRect.center());
0163     }
0164     d->canvasController->setPreferredCenter(documentCenter);
0165     d->canvas->update();
0166 }
0167 
0168 void KarbonZoomController::setAvailableSize()
0169 {
0170     if (d->zoomHandler->zoomMode() == KoZoomMode::ZOOM_WIDTH)
0171         setZoom(KoZoomMode::ZOOM_WIDTH, -1);
0172     if (d->zoomHandler->zoomMode() == KoZoomMode::ZOOM_PAGE)
0173         setZoom(KoZoomMode::ZOOM_PAGE, -1);
0174 }
0175 
0176 void KarbonZoomController::requestZoomRelative(const qreal factor, const QPointF &stillPoint)
0177 {
0178     qreal zoom = d->zoomHandler->zoom();
0179     setZoom(KoZoomMode::ZOOM_CONSTANT, factor*zoom, stillPoint);
0180 }
0181 
0182 void KarbonZoomController::requestZoomBy(const qreal factor)
0183 {
0184     qreal zoom = d->zoomHandler->zoom();
0185     setZoom(KoZoomMode::ZOOM_CONSTANT, factor*zoom);
0186 }
0187 
0188 void KarbonZoomController::setPageSize(const QSizeF &pageSize)
0189 {
0190     if (d->pageSize == pageSize)
0191         return;
0192     d->pageSize = pageSize;
0193 
0194     if (d->zoomHandler->zoomMode() == KoZoomMode::ZOOM_WIDTH)
0195         setZoom(KoZoomMode::ZOOM_WIDTH, -1);
0196     if (d->zoomHandler->zoomMode() == KoZoomMode::ZOOM_PAGE)
0197         setZoom(KoZoomMode::ZOOM_PAGE, -1);
0198 }
0199 
0200 void KarbonZoomController::canvasResourceChanged(int key, const QVariant &value)
0201 {
0202     if (key == KoCanvasResourceManager::PageSize) {
0203         setPageSize(value.toSizeF());
0204 
0205         // Tell the canvasController that the document in pixels
0206         // has changed as a result of the page layout change
0207         QRectF documentRect = d->canvas->documentViewRect();
0208         QSizeF viewSize = d->zoomHandler->documentToView(documentRect).size();
0209         d->canvasController->updateDocumentSize(QSize(qRound(viewSize.width()), qRound(viewSize.height())), true);
0210         d->canvas->adjustOrigin();
0211         d->canvas->update();
0212     }
0213 }
0214 
0215 void KarbonZoomController::zoomInRelative()
0216 {
0217     requestZoomBy(sqrt(2.0));
0218 
0219 }
0220 
0221 void KarbonZoomController::zoomOutRelative()
0222 {
0223     requestZoomBy(sqrt(0.5));
0224 }
0225