File indexing completed on 2024-04-28 04:20:22

0001 // REFACTOR: Clean up bits of this file
0002 
0003 /*
0004    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0005    All rights reserved.
0006 
0007    Redistribution and use in source and binary forms, with or without
0008    modification, are permitted provided that the following conditions
0009    are met:
0010 
0011    1. Redistributions of source code must retain the above copyright
0012       notice, this list of conditions and the following disclaimer.
0013    2. Redistributions in binary form must reproduce the above copyright
0014       notice, this list of conditions and the following disclaimer in the
0015       documentation and/or other materials provided with the distribution.
0016 
0017    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0018    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0019    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0020    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0021    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0022    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0023    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0024    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0025    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0026    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0027 */
0028 
0029 
0030 #include "mainWindow/kpMainWindow.h"
0031 #include "kpMainWindowPrivate.h"
0032 #include "kpLogCategories.h"
0033 
0034 #include <QRegularExpression>
0035 #include <QScrollBar>
0036 
0037 #include <KSelectAction>
0038 #include <KStandardAction>
0039 #include <KActionCollection>
0040 #include <KLocalizedString>
0041 
0042 #include "kpDefs.h"
0043 #include "document/kpDocument.h"
0044 #include "kpThumbnail.h"
0045 #include "tools/kpTool.h"
0046 #include "widgets/toolbars/kpToolToolBar.h"
0047 #include "views/kpUnzoomedThumbnailView.h"
0048 #include "views/manager/kpViewManager.h"
0049 #include "kpViewScrollableContainer.h"
0050 #include "generic/kpWidgetMapper.h"
0051 #include "views/kpZoomedView.h"
0052 #include "views/kpZoomedThumbnailView.h"
0053 
0054 static int ZoomLevelFromString (const QString &stringIn)
0055 {
0056 #if DEBUG_KP_MAIN_WINDOW
0057     qCDebug(kpLogMainWindow) << "kpMainWindow_View.cpp:ZoomLevelFromString(" << stringIn << ")";
0058 #endif
0059 
0060     // Remove any non-digits kdelibs sometimes adds behind our back :( e.g.:
0061     //
0062     // 1. kdelibs adds accelerators to actions' text directly
0063     // 2. ',' is automatically added to change "1000%" to "1,000%"
0064     QString string = stringIn;
0065     string.remove(QRegularExpression(QStringLiteral("[^0-9]")));
0066 #if DEBUG_KP_MAIN_WINDOW
0067     qCDebug(kpLogMainWindow) << "\twithout non-digits='" << string << "'";
0068 #endif
0069 
0070     // Convert zoom level to number.
0071     bool ok = false;
0072     int zoomLevel = string.toInt (&ok);
0073 #if DEBUG_KP_MAIN_WINDOW
0074     qCDebug(kpLogMainWindow) << "\tzoomLevel=" << zoomLevel;
0075 #endif
0076 
0077     if (!ok || zoomLevel < kpView::MinZoomLevel || zoomLevel > kpView::MaxZoomLevel) {
0078         return 0;  // error
0079     }
0080 
0081     return zoomLevel;
0082 }
0083 
0084 //---------------------------------------------------------------------
0085 
0086 static QString ZoomLevelToString (int zoomLevel)
0087 {
0088     return i18n ("%1%", zoomLevel);
0089 }
0090 
0091 //---------------------------------------------------------------------
0092 
0093 // private
0094 void kpMainWindow::setupViewMenuZoomActions ()
0095 {
0096     KActionCollection *ac = actionCollection ();
0097 
0098 
0099     d->actionActualSize = KStandardAction::actualSize (this, SLOT (slotActualSize()), ac);
0100     d->actionFitToPage = KStandardAction::fitToPage (this, SLOT (slotFitToPage()), ac);
0101     d->actionFitToWidth = KStandardAction::fitToWidth (this, SLOT (slotFitToWidth()), ac);
0102     d->actionFitToHeight = KStandardAction::fitToHeight (this, SLOT (slotFitToHeight()), ac);
0103 
0104 
0105     d->actionZoomIn = KStandardAction::zoomIn (this, SLOT (slotZoomIn()), ac);
0106     d->actionZoomOut = KStandardAction::zoomOut (this, SLOT (slotZoomOut()), ac);
0107 
0108 
0109     d->actionZoom = ac->add <KSelectAction> (QStringLiteral("view_zoom_to"));
0110     d->actionZoom->setText (i18n ("&Zoom"));
0111 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0112     connect (d->actionZoom,
0113              static_cast<void (KSelectAction::*)(QAction*)>(&KSelectAction::triggered),
0114              this, &kpMainWindow::slotZoom);
0115 #else
0116     connect (d->actionZoom,
0117              &KSelectAction::actionTriggered,
0118              this, &kpMainWindow::slotZoom);
0119 #endif
0120     d->actionZoom->setEditable (true);
0121 
0122     // create the zoom list for the 1st call to zoomTo() below
0123     d->zoomList.append (10); d->zoomList.append (25); d->zoomList.append (33);
0124     d->zoomList.append (50); d->zoomList.append (67); d->zoomList.append (75);
0125     d->zoomList.append (100);
0126     d->zoomList.append (200); d->zoomList.append (300);
0127     d->zoomList.append (400); d->zoomList.append (600); d->zoomList.append (800);
0128     d->zoomList.append (1000); d->zoomList.append (1200); d->zoomList.append (1600);
0129     d->zoomList.append (2400); d->zoomList.append (3200); d->zoomList.append (4000);
0130     d->zoomList.append (5000); d->zoomList.append (6000); d->zoomList.append (7000);
0131     d->zoomList.append (10000); d->zoomList.append (15000); d->zoomList.append (20000);
0132 }
0133 
0134 //---------------------------------------------------------------------
0135 
0136 // private
0137 void kpMainWindow::enableViewMenuZoomDocumentActions (bool enable)
0138 {
0139     d->actionActualSize->setEnabled (enable);
0140     d->actionFitToPage->setEnabled (enable);
0141     d->actionFitToWidth->setEnabled (enable);
0142     d->actionFitToHeight->setEnabled (enable);
0143 
0144     d->actionZoomIn->setEnabled (enable);
0145     d->actionZoomOut->setEnabled (enable);
0146     d->actionZoom->setEnabled (enable);
0147 
0148 
0149     // TODO: for the time being, assume that we start at zoom 100%
0150     //       with no grid
0151 
0152     // This function is only called when a new document is created
0153     // or an existing document is closed.  So the following will
0154     // always be correct:
0155 
0156     zoomTo (100);
0157 }
0158 
0159 //---------------------------------------------------------------------
0160 
0161 // private
0162 void kpMainWindow::sendZoomListToActionZoom ()
0163 {
0164     QStringList items;
0165 
0166     const QList <int>::ConstIterator zoomListEnd (d->zoomList.end ());
0167     for (QList <int>::ConstIterator it = d->zoomList.constBegin ();
0168          it != zoomListEnd;
0169          ++it)
0170     {
0171         items << ::ZoomLevelToString (*it);
0172     }
0173 
0174     // Work around a KDE bug - KSelectAction::setItems() enables the action.
0175     // David Faure said it won't be fixed because it's a feature used by
0176     // KRecentFilesAction.
0177     bool e = d->actionZoom->isEnabled ();
0178     d->actionZoom->setItems (items);
0179     if (e != d->actionZoom->isEnabled ()) {
0180         d->actionZoom->setEnabled (e);
0181     }
0182 }
0183 
0184 //---------------------------------------------------------------------
0185 
0186 // private
0187 void kpMainWindow::zoomToPre (int zoomLevel)
0188 {
0189     // We're called quite early in the init process and/or when there might
0190     // not be a document or a view so we have a lot of "if (ptr)" guards.
0191 
0192 #if DEBUG_KP_MAIN_WINDOW
0193     qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPre(" << zoomLevel << ")";
0194 #endif
0195 
0196     zoomLevel = qBound (kpView::MinZoomLevel, zoomLevel, kpView::MaxZoomLevel);
0197 
0198     int index = 0;
0199     QList <int>::Iterator it = d->zoomList.begin ();
0200 
0201     while (index < d->zoomList.count () && zoomLevel > *it)
0202     {
0203         it++;
0204         index++;
0205     }
0206 
0207     if (zoomLevel != *it) {
0208         d->zoomList.insert (it, zoomLevel);
0209     }
0210 
0211     // OPT: We get called twice on startup.  sendZoomListToActionZoom() is very slow.
0212     sendZoomListToActionZoom ();
0213 
0214 #if DEBUG_KP_MAIN_WINDOW
0215     qCDebug(kpLogMainWindow) << "\tsetCurrentItem(" << index << ")";
0216 #endif
0217     d->actionZoom->setCurrentItem (index);
0218 #if DEBUG_KP_MAIN_WINDOW
0219     qCDebug(kpLogMainWindow) << "\tcurrentItem="
0220               << d->actionZoom->currentItem ()
0221               << " action="
0222               << d->actionZoom->action (d->actionZoom->currentItem ())
0223               << " checkedAction"
0224               << d->actionZoom->selectableActionGroup ()->checkedAction ();
0225 #endif
0226 
0227 
0228     if (viewMenuDocumentActionsEnabled ())
0229     {
0230         d->actionActualSize->setEnabled (zoomLevel != 100);
0231 
0232         d->actionZoomIn->setEnabled (d->actionZoom->currentItem () < d->zoomList.count () - 1);
0233         d->actionZoomOut->setEnabled (d->actionZoom->currentItem () > 0);
0234     }
0235 
0236 
0237     // TODO: Is this actually needed?
0238     if (d->viewManager) {
0239         d->viewManager->setQueueUpdates ();
0240     }
0241 
0242     if (d->scrollView)
0243     {
0244         d->scrollView->setUpdatesEnabled (false);
0245     }
0246 }
0247 
0248 //---------------------------------------------------------------------
0249 
0250 // private
0251 void kpMainWindow::zoomToPost ()
0252 {
0253 #if DEBUG_KP_MAIN_WINDOW && 1
0254     qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPost()";
0255 #endif
0256 
0257     if (d->mainView)
0258     {
0259         actionShowGridUpdate ();
0260         updateMainViewGrid ();
0261 
0262         // Since Zoom Level KSelectAction on ToolBar grabs focus after changing
0263         // Zoom, switch back to the Main View.
0264         // TODO: back to the last view
0265         d->mainView->setFocus ();
0266 
0267     }
0268 
0269 
0270     // The view magnified and moved beneath the cursor
0271     if (tool ()) {
0272         tool ()->somethingBelowTheCursorChanged ();
0273     }
0274 
0275 
0276     if (d->scrollView)
0277     {
0278         // TODO: setUpdatesEnabled() should really return to old value
0279         //       - not necessarily "true"
0280         d->scrollView->setUpdatesEnabled (true);
0281     }
0282 
0283     if (d->viewManager && d->viewManager->queueUpdates ()/*just in case*/) {
0284         d->viewManager->restoreQueueUpdates ();
0285     }
0286 
0287     setStatusBarZoom (d->mainView ? d->mainView->zoomLevelX () : 0);
0288 
0289 #if DEBUG_KP_MAIN_WINDOW && 1
0290     qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPost() done";
0291 #endif
0292 }
0293 
0294 //---------------------------------------------------------------------
0295 
0296 // private
0297 void kpMainWindow::zoomTo (int zoomLevel, bool centerUnderCursor)
0298 {
0299     zoomToPre (zoomLevel);
0300 
0301 
0302     if (d->scrollView && d->mainView)
0303     {
0304     #if DEBUG_KP_MAIN_WINDOW && 1
0305         qCDebug(kpLogMainWindow) << "\tscrollView   contentsX=" << d->scrollView->horizontalScrollBar()->value ()
0306                    << " contentsY=" << d->scrollView->verticalScrollBar()->value ()
0307                    << " contentsWidth=" << d->scrollView->widget()->width ()
0308                    << " contentsHeight=" << d->scrollView->widget()->height ()
0309                    << " visibleWidth=" << d->scrollView->viewport()->width ()
0310                    << " visibleHeight=" << d->scrollView->viewport()->height ()
0311                    << " oldZoomX=" << d->mainView->zoomLevelX ()
0312                    << " oldZoomY=" << d->mainView->zoomLevelY ()
0313                    << " newZoom=" << zoomLevel;
0314     #endif
0315 
0316         // TODO: when changing from no scrollbars to scrollbars, Qt lies about
0317         //       visibleWidth() & visibleHeight() (doesn't take into account the
0318         //       space taken by the would-be scrollbars) until it updates the
0319         //       scrollview; hence the centering is off by about 5-10 pixels.
0320 
0321         // TODO: Use visibleRect() for greater accuracy?
0322         //       Or use kpAbstractScrollAreaUtils::EstimateUsableArea()
0323         //       instead of ScrollView::visible{Width,Height}(), as
0324         //       per zoomToRect()?
0325 
0326         int viewX, viewY;
0327 
0328         bool targetDocAvail = false;
0329         double targetDocX = -1, targetDocY = -1;
0330 
0331         if (centerUnderCursor &&
0332             d->viewManager && d->viewManager->viewUnderCursor ())
0333         {
0334             kpView *const vuc = d->viewManager->viewUnderCursor ();
0335             QPoint viewPoint = vuc->mouseViewPoint ();
0336 
0337             // vuc->transformViewToDoc() returns QPoint which only has int
0338             // accuracy so we do X and Y manually.
0339             targetDocX = vuc->transformViewToDocX (viewPoint.x ());
0340             targetDocY = vuc->transformViewToDocY (viewPoint.y ());
0341             targetDocAvail = true;
0342 
0343             if (vuc != d->mainView) {
0344                 viewPoint = vuc->transformViewToOtherView (viewPoint, d->mainView);
0345             }
0346 
0347             viewX = viewPoint.x ();
0348             viewY = viewPoint.y ();
0349         }
0350         else
0351         {
0352             viewX = d->scrollView->horizontalScrollBar()->value () +
0353                         qMin (d->mainView->width (),
0354                               d->scrollView->viewport()->width ()) / 2;
0355             viewY = d->scrollView->verticalScrollBar()->value () +
0356                         qMin (d->mainView->height (),
0357                               d->scrollView->viewport()->height ()) / 2;
0358         }
0359 
0360 
0361         int newCenterX = viewX * zoomLevel / d->mainView->zoomLevelX ();
0362         int newCenterY = viewY * zoomLevel / d->mainView->zoomLevelY ();
0363 
0364         // Do the zoom.
0365         d->mainView->setZoomLevel (zoomLevel, zoomLevel);
0366 
0367     #if DEBUG_KP_MAIN_WINDOW && 1
0368         qCDebug(kpLogMainWindow) << "\tvisibleWidth=" << d->scrollView->viewport()->width ()
0369                     << " visibleHeight=" << d->scrollView->viewport()->height ();
0370         qCDebug(kpLogMainWindow) << "\tnewCenterX=" << newCenterX
0371                     << " newCenterY=" << newCenterY;
0372     #endif
0373 
0374         d->scrollView->horizontalScrollBar()->setValue(newCenterX - (d->scrollView->viewport()->width() / 2));
0375         d->scrollView->verticalScrollBar()->setValue(newCenterY - (d->scrollView->viewport()->height() / 2));
0376 
0377         if (centerUnderCursor &&
0378             targetDocAvail &&
0379             d->viewManager && d->viewManager->viewUnderCursor ())
0380         {
0381             // Move the mouse cursor so that it is still above the same
0382             // document pixel as before the zoom.
0383 
0384             kpView *const vuc = d->viewManager->viewUnderCursor ();
0385 
0386         #if DEBUG_KP_MAIN_WINDOW
0387             qCDebug(kpLogMainWindow) << "\tcenterUnderCursor: reposition cursor; viewUnderCursor="
0388                        << vuc->objectName ();
0389         #endif
0390 
0391             const auto viewX = vuc->transformDocToViewX (targetDocX);
0392             const auto viewY = vuc->transformDocToViewY (targetDocY);
0393             // Rounding error from zooming in and out :(
0394             // TODO: do everything in terms of tool doc points in type "double".
0395             const QPoint viewPoint (static_cast<int> (viewX), static_cast<int> (viewY));
0396         #if DEBUG_KP_MAIN_WINDOW
0397             qCDebug(kpLogMainWindow) << "\t\tdoc: (" << targetDocX << "," << targetDocY << ")"
0398                        << " viewUnderCursor: (" << viewX << "," << viewY << ")";
0399         #endif
0400 
0401             if (vuc->visibleRegion ().contains (viewPoint))
0402             {
0403                 const QPoint globalPoint =
0404                     kpWidgetMapper::toGlobal (vuc, viewPoint);
0405             #if DEBUG_KP_MAIN_WINDOW
0406                 qCDebug(kpLogMainWindow) << "\t\tglobalPoint=" << globalPoint;
0407             #endif
0408 
0409                 // TODO: Determine some sane cursor flashing indication -
0410                 //       cursor movement is convenient but not conventional.
0411                 //
0412                 //       Major problem: if using QApplication::setOverrideCursor()
0413                 //           and in some stage of flash and window quits.
0414                 //
0415                 //           Or if using kpView::setCursor() and change tool.
0416                 QCursor::setPos (globalPoint);
0417             }
0418             // e.g. Zoom to 200%, scroll mainView to bottom-right.
0419             // Unzoomed Thumbnail shows top-left portion of bottom-right of
0420             // mainView.
0421             //
0422             // Aim cursor at bottom-right of thumbnail and zoom out with
0423             // CTRL+Wheel.
0424             //
0425             // If mainView is now small enough to largely not need scrollbars,
0426             // Unzoomed Thumbnail scrolls to show _top-left_ portion
0427             // _of top-left_ of mainView.
0428             //
0429             // Unzoomed Thumbnail no longer contains the point we zoomed out
0430             // on top of.
0431             else
0432             {
0433             #if DEBUG_KP_MAIN_WINDOW
0434                 qCDebug(kpLogMainWindow) << "\t\twon't move cursor - would get outside view";
0435             #endif
0436 
0437                 // TODO: Sane cursor flashing indication that indicates
0438                 //       that the normal cursor movement didn't happen.
0439             }
0440         }
0441 
0442     #if DEBUG_KP_MAIN_WINDOW && 1
0443         qCDebug(kpLogMainWindow) << "\t\tcheck (contentsX=" << d->scrollView->horizontalScrollBar()->value ()
0444                     << ",contentsY=" << d->scrollView->verticalScrollBar()->value ()
0445                     << ")";
0446     #endif
0447     }
0448 
0449 
0450     zoomToPost ();
0451 }
0452 
0453 //---------------------------------------------------------------------
0454 
0455 // private
0456 void kpMainWindow::zoomToRect (const QRect &normalizedDocRect,
0457         bool accountForGrips,
0458         bool careAboutWidth, bool careAboutHeight)
0459 {
0460 #if DEBUG_KP_MAIN_WINDOW
0461     qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToRect(normalizedDocRect="
0462               << normalizedDocRect
0463               << ",accountForGrips=" << accountForGrips
0464               << ",careAboutWidth=" << careAboutWidth
0465               << ",careAboutHeight=" << careAboutHeight
0466               << ")";
0467 #endif
0468     // You can't care about nothing.
0469     Q_ASSERT (careAboutWidth || careAboutHeight);
0470 
0471     // The size of the scroll view minus the current or future scrollbars.
0472     const QSize usableScrollArea
0473       (d->scrollView->maximumViewportSize().width() - d->scrollView->verticalScrollBar()->sizeHint().width(),
0474        d->scrollView->maximumViewportSize().height() - d->scrollView->horizontalScrollBar()->sizeHint().height());
0475 
0476 #if DEBUG_KP_MAIN_WINDOW
0477     qCDebug(kpLogMainWindow) << "size=" << d->scrollView->maximumViewportSize()
0478               << "scrollbar w=" << d->scrollView->verticalScrollBar()->sizeHint().width()
0479               << "usableSize=" << usableScrollArea;
0480 #endif
0481     // Handle rounding error, mis-estimating the scroll view size and
0482     // cosmic rays.  We do this because we really don't want unnecessary
0483     // scrollbars.  This seems to need to be at least 2 for slotFitToWidth()
0484     // and friends.
0485     // least 2.
0486     // TODO: I might have fixed this but check later.
0487     const int slack = 0;
0488 
0489     // The grip and slack are in view coordinates but are never zoomed.
0490     const int viewWidth =
0491         usableScrollArea.width () -
0492         (accountForGrips ? kpGrip::Size : 0) -
0493         slack;
0494     const int viewHeight =
0495         usableScrollArea.height () -
0496         (accountForGrips ? kpGrip::Size : 0) -
0497         slack;
0498 
0499     // We want the selected document rectangle to fill the scroll view.
0500     //
0501     // The integer arithmetic rounds down, rather than to the nearest zoom
0502     // level, as rounding down guarantees that the view, at the zoom level,
0503     // will fit inside <viewWidth> x <viewHeight>.
0504     const int zoomX =
0505         careAboutWidth ?
0506             qMax (1, viewWidth * 100 / normalizedDocRect.width ()) :
0507             INT_MAX;
0508     const int zoomY =
0509         careAboutHeight ?
0510             qMax (1, viewHeight * 100 / normalizedDocRect.height ()) :
0511             INT_MAX;
0512 
0513     // Since kpView only supports identical horizontal and vertical zooms,
0514     // choose the one that will show the greatest amount of document
0515     // content.
0516     const int zoomLevel = qMin (zoomX, zoomY);
0517 
0518 #if DEBUG_KP_MAIN_WINDOW
0519     qCDebug(kpLogMainWindow) << "\tzoomX=" << zoomX
0520         << " zoomY=" << zoomY
0521         << " -> zoomLevel=" << zoomLevel;
0522 #endif
0523 
0524     zoomToPre (zoomLevel);
0525     {
0526         d->mainView->setZoomLevel (zoomLevel, zoomLevel);
0527 
0528         const QPoint viewPoint =
0529             d->mainView->transformDocToView (normalizedDocRect.topLeft ());
0530 
0531         d->scrollView->horizontalScrollBar()->setValue(viewPoint.x());
0532         d->scrollView->verticalScrollBar()->setValue(viewPoint.y());
0533     }
0534     zoomToPost ();
0535 }
0536 
0537 //---------------------------------------------------------------------
0538 
0539 // public slot
0540 void kpMainWindow::slotActualSize ()
0541 {
0542     zoomTo (100);
0543 }
0544 
0545 //---------------------------------------------------------------------
0546 
0547 // public slot
0548 void kpMainWindow::slotFitToPage ()
0549 {
0550   if ( d->document )
0551   {
0552     zoomToRect (
0553         d->document->rect (),
0554         true/*account for grips*/,
0555         true/*care about width*/, true/*care about height*/);
0556   }
0557 }
0558 
0559 //---------------------------------------------------------------------
0560 
0561 // public slot
0562 void kpMainWindow::slotFitToWidth ()
0563 {
0564   if ( d->document )
0565   {
0566     const QRect docRect (
0567         0/*x*/,
0568         static_cast<int> (d->mainView->transformViewToDocY (d->scrollView->verticalScrollBar()->value ()))/*maintain y*/,
0569                 d->document->width (),
0570                 1/*don't care about height*/);
0571     zoomToRect (
0572         docRect,
0573         true/*account for grips*/,
0574         true/*care about width*/, false/*don't care about height*/);
0575   }
0576 }
0577 
0578 //---------------------------------------------------------------------
0579 
0580 // public slot
0581 void kpMainWindow::slotFitToHeight ()
0582 {
0583   if ( d->document )
0584   {
0585     const QRect docRect (
0586         static_cast<int> (d->mainView->transformViewToDocX (d->scrollView->horizontalScrollBar()->value ()))/*maintain x*/,
0587                 0/*y*/,
0588                 1/*don't care about width*/,
0589                 d->document->height ());
0590     zoomToRect (
0591         docRect,
0592         true/*account for grips*/,
0593         false/*don't care about width*/, true/*care about height*/);
0594   }
0595 }
0596 
0597 //---------------------------------------------------------------------
0598 
0599 // public
0600 void kpMainWindow::zoomIn (bool centerUnderCursor)
0601 {
0602 #if DEBUG_KP_MAIN_WINDOW
0603     qCDebug(kpLogMainWindow) << "kpMainWindow::zoomIn(centerUnderCursor="
0604               << centerUnderCursor << ") currentItem="
0605               << d->actionZoom->currentItem ();
0606 #endif
0607     const int targetItem = d->actionZoom->currentItem () + 1;
0608 
0609     if (targetItem >= static_cast<int> (d->zoomList.count ())) {
0610         return;
0611     }
0612 
0613     d->actionZoom->setCurrentItem (targetItem);
0614 
0615 #if DEBUG_KP_MAIN_WINDOW
0616     qCDebug(kpLogMainWindow) << "\tnew currentItem=" << d->actionZoom->currentItem ();
0617 #endif
0618 
0619     zoomAccordingToZoomAction (centerUnderCursor);
0620 }
0621 
0622 //---------------------------------------------------------------------
0623 
0624 // public
0625 void kpMainWindow::zoomOut (bool centerUnderCursor)
0626 {
0627 #if DEBUG_KP_MAIN_WINDOW
0628     qCDebug(kpLogMainWindow) << "kpMainWindow::zoomOut(centerUnderCursor="
0629               << centerUnderCursor << ") currentItem="
0630               << d->actionZoom->currentItem ();
0631 #endif
0632     const int targetItem = d->actionZoom->currentItem () - 1;
0633 
0634     if (targetItem < 0) {
0635         return;
0636     }
0637 
0638     d->actionZoom->setCurrentItem (targetItem);
0639 
0640 #if DEBUG_KP_MAIN_WINDOW
0641     qCDebug(kpLogMainWindow) << "\tnew currentItem=" << d->actionZoom->currentItem ();
0642 #endif
0643 
0644     zoomAccordingToZoomAction (centerUnderCursor);
0645 }
0646 
0647 //---------------------------------------------------------------------
0648 
0649 // public slot
0650 void kpMainWindow::slotZoomIn ()
0651 {
0652 #if DEBUG_KP_MAIN_WINDOW
0653     qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomIn ()";
0654 #endif
0655 
0656     zoomIn (false/*don't center under cursor*/);
0657 }
0658 
0659 //---------------------------------------------------------------------
0660 
0661 // public slot
0662 void kpMainWindow::slotZoomOut ()
0663 {
0664 #if DEBUG_KP_MAIN_WINDOW
0665     qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomOut ()";
0666 #endif
0667 
0668     zoomOut (false/*don't center under cursor*/);
0669 }
0670 
0671 //---------------------------------------------------------------------
0672 
0673 // public
0674 void kpMainWindow::zoomAccordingToZoomAction (bool centerUnderCursor)
0675 {
0676 #if DEBUG_KP_MAIN_WINDOW
0677     qCDebug(kpLogMainWindow) << "kpMainWindow::zoomAccordingToZoomAction(centerUnderCursor="
0678               << centerUnderCursor
0679               << ") currentItem=" << d->actionZoom->currentItem ()
0680               << " currentText=" << d->actionZoom->currentText ();
0681 #endif
0682 
0683     // This might be a new zoom level the user has typed in.
0684     zoomTo (::ZoomLevelFromString (d->actionZoom->currentText ()),
0685                                    centerUnderCursor);
0686 }
0687 
0688 //---------------------------------------------------------------------
0689 
0690 // private slot
0691 void kpMainWindow::slotZoom ()
0692 {
0693 #if DEBUG_KP_MAIN_WINDOW
0694     qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoom () index=" << d->actionZoom->currentItem ()
0695                << " text='" << d->actionZoom->currentText () << "'";
0696 #endif
0697 
0698     zoomAccordingToZoomAction (false/*don't center under cursor*/);
0699 }
0700 
0701 //---------------------------------------------------------------------