Warning, file /office/calligra/libs/widgets/KoZoomAction.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 libraries
0002     Copyright (C) 2004 Ariya Hidayat <ariya@kde.org>
0003     Copyright (C) 2006 Peter Simonsson <peter.simonsson@gmail.com>
0004     Copyright (C) 2006-2007 C. Boemann <cbo@boemann.dk>
0005 
0006     This library is free software; you can redistribute it and/or
0007     modify it under the terms of the GNU Library General Public
0008     License version 2 as published by the Free Software Foundation.
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 #include "KoZoomAction.h"
0021 #include "KoZoomMode.h"
0022 #include "KoZoomWidget.h"
0023 
0024 #include <KoIcon.h>
0025 
0026 #include <QString>
0027 #include <QLocale>
0028 #include <QStringList>
0029 #include <QRegExp>
0030 #include <QList>
0031 #include <QSlider>
0032 #include <QLineEdit>
0033 #include <QToolButton>
0034 #include <QLabel>
0035 #include <QGridLayout>
0036 #include <QMenu>
0037 #include <QStatusBar>
0038 #include <QButtonGroup>
0039 #include <QComboBox>
0040 
0041 
0042 #include <klocalizedstring.h>
0043 #include <WidgetsDebug.h>
0044 
0045 #include <math.h>
0046 #include <algorithm>
0047 
0048 class Q_DECL_HIDDEN KoZoomAction::Private
0049 {
0050 public:
0051 
0052     Private(KoZoomAction *_parent)
0053         : parent(_parent)
0054         , minimumZoomValue(-1)
0055         , maximumZoomValue(-1)
0056     {}
0057 
0058     KoZoomAction *parent;
0059 
0060     KoZoomMode::Modes zoomModes;
0061     QList<qreal> sliderLookup;
0062 
0063     qreal effectiveZoom;
0064 
0065     KoZoomAction::SpecialButtons specialButtons;
0066 
0067     QList<qreal> generateSliderZoomLevels() const;
0068     QList<qreal> filterMenuZoomLevels(const QList<qreal> &zoomLevels) const;
0069 
0070     qreal minimumZoomValue;
0071     qreal maximumZoomValue;
0072 };
0073 
0074 QList<qreal> KoZoomAction::Private::generateSliderZoomLevels() const
0075 {
0076     QList<qreal> zoomLevels;
0077 
0078     qreal defaultZoomStep = sqrt(2.0);
0079 
0080     zoomLevels << 0.25 / 2.0;
0081     zoomLevels << 0.25 / 1.5;
0082     zoomLevels << 0.25;
0083     zoomLevels << 1.0 / 3.0;
0084     zoomLevels << 0.5;
0085     zoomLevels << 2.0 / 3.0;
0086     zoomLevels << 1.0;
0087 
0088     for (qreal zoom = zoomLevels.first() / defaultZoomStep;
0089          zoom > parent->minimumZoom();
0090          zoom /= defaultZoomStep) {
0091 
0092         zoomLevels.prepend(zoom);
0093     }
0094 
0095     for (qreal zoom = zoomLevels.last() * defaultZoomStep;
0096          zoom < parent->maximumZoom();
0097          zoom *= defaultZoomStep) {
0098 
0099         zoomLevels.append(zoom);
0100     }
0101 
0102     return zoomLevels;
0103 }
0104 
0105 QList<qreal> KoZoomAction::Private::filterMenuZoomLevels(const QList<qreal> &zoomLevels) const
0106 {
0107     QList<qreal> filteredZoomLevels;
0108 
0109     foreach(qreal zoom, zoomLevels) {
0110         if (zoom >= 0.2 && zoom <= 10) {
0111             filteredZoomLevels << zoom;
0112         }
0113     }
0114 
0115     return filteredZoomLevels;
0116 }
0117 
0118 KoZoomAction::KoZoomAction(KoZoomMode::Modes zoomModes, const QString& text, QObject *parent)
0119     : KSelectAction(text, parent)
0120     , d(new Private(this))
0121 {
0122     d->zoomModes = zoomModes;
0123     d->specialButtons = nullptr;
0124     setIcon(koIcon("zoom-original"));
0125     setEditable( true );
0126     setMaxComboViewCount( 15 );
0127 
0128     d->sliderLookup = d->generateSliderZoomLevels();
0129 
0130     d->effectiveZoom = 1.0;
0131     regenerateItems(d->effectiveZoom, true);
0132 
0133     connect( this, SIGNAL(triggered(QString)), SLOT(triggered(QString)) );
0134 }
0135 
0136 KoZoomAction::~KoZoomAction()
0137 {
0138     delete d;
0139 }
0140 
0141 qreal KoZoomAction::effectiveZoom() const
0142 {
0143     return d->effectiveZoom;
0144 }
0145 
0146 void KoZoomAction::setZoom(qreal zoom)
0147 {
0148     setEffectiveZoom(zoom);
0149     regenerateItems(d->effectiveZoom, true);
0150 }
0151 
0152 void KoZoomAction::triggered(const QString& text)
0153 {
0154     QString zoomString = text;
0155     zoomString = zoomString.remove( '&' );
0156 
0157     KoZoomMode::Mode mode = KoZoomMode::toMode(zoomString);
0158     int zoom = 0;
0159 
0160     if( mode == KoZoomMode::ZOOM_CONSTANT ) {
0161         bool ok;
0162         QRegExp regexp( ".*(\\d+).*" ); // "Captured" non-empty sequence of digits
0163         int pos = regexp.indexIn( zoomString );
0164 
0165         if( pos > -1 ) {
0166             zoom = regexp.cap( 1 ).toInt( &ok );
0167 
0168             if( !ok ) {
0169                 zoom = 0;
0170             }
0171         }
0172     }
0173 
0174     emit zoomChanged( mode, zoom/100.0 );
0175 }
0176 
0177 void KoZoomAction::setZoomModes( KoZoomMode::Modes zoomModes )
0178 {
0179     d->zoomModes = zoomModes;
0180     regenerateItems( d->effectiveZoom );
0181 }
0182 
0183 void KoZoomAction::regenerateItems(const qreal zoom, bool asCurrent)
0184 {
0185     QList<qreal> zoomLevels = d->filterMenuZoomLevels(d->sliderLookup);
0186 
0187     if( !zoomLevels.contains( zoom ) )
0188         zoomLevels << zoom;
0189 
0190     std::sort(zoomLevels.begin(), zoomLevels.end());
0191 
0192     // update items with new sorted zoom values
0193     QStringList values;
0194     if(d->zoomModes & KoZoomMode::ZOOM_WIDTH) {
0195         values << KoZoomMode::toString(KoZoomMode::ZOOM_WIDTH);
0196     }
0197     if(d->zoomModes & KoZoomMode::ZOOM_TEXT) {
0198         values << KoZoomMode::toString(KoZoomMode::ZOOM_TEXT);
0199     }
0200     if(d->zoomModes & KoZoomMode::ZOOM_PAGE) {
0201         values << KoZoomMode::toString(KoZoomMode::ZOOM_PAGE);
0202     }
0203 
0204     foreach(qreal value, zoomLevels) {
0205         const qreal valueInPercent = value * 100;
0206         const int precision = (value > 10.0) ? 0 : 1;
0207 
0208         values << i18n("%1%", QLocale().toString(valueInPercent, 'f', precision));
0209     }
0210 
0211     setItems( values );
0212 
0213     emit zoomLevelsChanged(values);
0214 
0215     if(asCurrent)
0216     {
0217         const qreal zoomInPercent = zoom * 100;
0218         // TODO: why zoomInPercent and not zoom here? different from above
0219         const int precision = (zoomInPercent > 10.0) ? 0 : 1;
0220 
0221         const QString valueString = i18n("%1%", QLocale().toString(zoomInPercent, 'f', precision));
0222 
0223         setCurrentAction(valueString);
0224 
0225         emit currentZoomLevelChanged(valueString);
0226     }
0227 }
0228 
0229 void KoZoomAction::sliderValueChanged(int value)
0230 {
0231     setZoom(d->sliderLookup[value]);
0232 
0233     emit zoomChanged(KoZoomMode::ZOOM_CONSTANT, d->sliderLookup[value]);
0234 }
0235 
0236 qreal KoZoomAction::nextZoomLevel() const
0237 {
0238     const qreal eps = 1e-5;
0239     int i = 0;
0240     while (d->effectiveZoom > d->sliderLookup[i] - eps &&
0241            i < d->sliderLookup.size() - 1) i++;
0242 
0243     return qMax(d->effectiveZoom, d->sliderLookup[i]);
0244 }
0245 
0246 qreal KoZoomAction::prevZoomLevel() const
0247 {
0248     const qreal eps = 1e-5;
0249     int i = d->sliderLookup.size() - 1;
0250     while (d->effectiveZoom < d->sliderLookup[i] + eps && i > 0) i--;
0251 
0252     return qMin(d->effectiveZoom, d->sliderLookup[i]);
0253 }
0254 
0255 void KoZoomAction::zoomIn()
0256 {
0257     qreal zoom = nextZoomLevel();
0258 
0259     if (zoom > d->effectiveZoom) {
0260         setZoom(zoom);
0261         emit zoomChanged(KoZoomMode::ZOOM_CONSTANT, d->effectiveZoom);
0262     }
0263 }
0264 
0265 void KoZoomAction::zoomOut()
0266 {
0267     qreal zoom = prevZoomLevel();
0268 
0269     if (zoom < d->effectiveZoom) {
0270         setZoom(zoom);
0271         emit zoomChanged(KoZoomMode::ZOOM_CONSTANT, d->effectiveZoom);
0272     }
0273 }
0274 
0275 QWidget * KoZoomAction::createWidget(QWidget *parent)
0276 {
0277     KoZoomWidget* zoomWidget = new KoZoomWidget(parent, d->specialButtons, d->sliderLookup.size() - 1);
0278     connect(this, SIGNAL(zoomLevelsChanged(QStringList)), zoomWidget, SLOT(setZoomLevels(QStringList)));
0279     connect(this, SIGNAL(currentZoomLevelChanged(QString)), zoomWidget, SLOT(setCurrentZoomLevel(QString)));
0280     connect(this, SIGNAL(sliderChanged(int)), zoomWidget, SLOT(setSliderValue(int)));
0281     connect(this, SIGNAL(aspectModeChanged(bool)), zoomWidget, SLOT(setAspectMode(bool)));
0282     connect(zoomWidget, SIGNAL(sliderValueChanged(int)), this, SLOT(sliderValueChanged(int)));
0283     connect(zoomWidget, SIGNAL(zoomLevelChanged(QString)), this, SLOT(triggered(QString)));
0284     connect(zoomWidget, SIGNAL(aspectModeChanged(bool)), this, SIGNAL(aspectModeChanged(bool)));
0285     connect(zoomWidget, SIGNAL(zoomedToSelection()), this, SIGNAL(zoomedToSelection()));
0286     connect(zoomWidget, SIGNAL(zoomedToAll()), this, SIGNAL(zoomedToAll()));
0287     regenerateItems( d->effectiveZoom, true );
0288     syncSliderWithZoom();
0289     return zoomWidget;
0290 }
0291 
0292 void KoZoomAction::setEffectiveZoom(qreal zoom)
0293 {
0294     if(d->effectiveZoom == zoom)
0295         return;
0296 
0297     zoom = clampZoom(zoom);
0298     d->effectiveZoom = zoom;
0299     syncSliderWithZoom();
0300 }
0301 
0302 void KoZoomAction::setSelectedZoomMode(KoZoomMode::Mode mode)
0303 {
0304     QString modeString(KoZoomMode::toString(mode));
0305     setCurrentAction(modeString);
0306 
0307     emit currentZoomLevelChanged(modeString);
0308 }
0309 
0310 void KoZoomAction::setSpecialButtons( SpecialButtons buttons )
0311 {
0312     d->specialButtons = buttons;
0313 }
0314 
0315 void KoZoomAction::setAspectMode(bool status)
0316 {
0317     emit aspectModeChanged(status);
0318 }
0319 
0320 void KoZoomAction::syncSliderWithZoom()
0321 {
0322     const qreal eps = 1e-5;
0323     int i = d->sliderLookup.size() - 1;
0324     while (d->effectiveZoom < d->sliderLookup[i] + eps && i > 0) i--;
0325     
0326     emit sliderChanged(i);
0327 }
0328 
0329 qreal KoZoomAction::minimumZoom()
0330 {
0331     if (d->minimumZoomValue < 0) {
0332         return KoZoomMode::minimumZoom();
0333     }
0334     return d->minimumZoomValue;
0335 }
0336 
0337 qreal KoZoomAction::maximumZoom()
0338 {
0339     if (d->maximumZoomValue < 0) {
0340         return KoZoomMode::maximumZoom();
0341     }
0342     return d->maximumZoomValue;
0343 }
0344 
0345 qreal KoZoomAction::clampZoom(qreal zoom)
0346 {
0347     return qMin(maximumZoom(), qMax(minimumZoom(), zoom));
0348 }
0349 
0350 void KoZoomAction::setMinimumZoom(qreal zoom)
0351 {
0352     Q_ASSERT(zoom > 0.0f);
0353     KoZoomMode::setMinimumZoom(zoom);
0354     d->minimumZoomValue = zoom;
0355     d->generateSliderZoomLevels();
0356     d->sliderLookup = d->generateSliderZoomLevels();
0357     regenerateItems(d->effectiveZoom, true);
0358     syncSliderWithZoom();
0359 }
0360 
0361 void KoZoomAction::setMaximumZoom(qreal zoom)
0362 {
0363     Q_ASSERT(zoom > 0.0f);
0364     KoZoomMode::setMaximumZoom(zoom);
0365     d->maximumZoomValue = zoom;
0366     d->sliderLookup = d->generateSliderZoomLevels();
0367     regenerateItems(d->effectiveZoom, true);
0368     syncSliderWithZoom();
0369 }