KoZoomAction.cpp 9.26 KB
Newer Older
1 2 3
/*  This file is part of the KDE libraries
    Copyright (C) 2004 Ariya Hidayat <ariya@kde.org>
    Copyright (C) 2006 Peter Simonsson <peter.simonsson@gmail.com>
C. Boemann's avatar
C. Boemann committed
4
    Copyright (C) 2006-2007 C. Boemann <cbo@boemann.dk>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/
#include "KoZoomAction.h"
#include "KoZoomMode.h"
22
#include "KoZoomWidget.h"
23

24 25
#include <KoIcon.h>

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
#include <QString>
#include <QLocale>
#include <QStringList>
#include <QRegExp>
#include <QList>
#include <QSlider>
#include <QLineEdit>
#include <QToolButton>
#include <QLabel>
#include <QGridLayout>
#include <QMenu>
#include <QStatusBar>
#include <QButtonGroup>
#include <QComboBox>

41

42
#include <klocalizedstring.h>
43
#include <WidgetsDebug.h>
44 45 46

#include <math.h>

47
class Q_DECL_HIDDEN KoZoomAction::Private
48 49
{
public:
50

51 52 53 54 55 56 57
    Private(KoZoomAction *_parent)
        : parent(_parent)
        , minimumZoomValue(-1)
        , maximumZoomValue(-1)
    {}

    KoZoomAction *parent;
58

59
    KoZoomMode::Modes zoomModes;
60
    QList<qreal> sliderLookup;
61 62 63

    qreal effectiveZoom;

64 65
    QList<qreal> generateSliderZoomLevels() const;
    QList<qreal> filterMenuZoomLevels(const QList<qreal> &zoomLevels) const;
66 67 68

    qreal minimumZoomValue;
    qreal maximumZoomValue;
69 70
};

71 72 73 74
QList<qreal> KoZoomAction::Private::generateSliderZoomLevels() const
{
    QList<qreal> zoomLevels;

75
    qreal defaultZoomStep = sqrt(2.0);
76 77 78 79 80 81 82 83 84 85

    zoomLevels << 0.25 / 2.0;
    zoomLevels << 0.25 / 1.5;
    zoomLevels << 0.25;
    zoomLevels << 1.0 / 3.0;
    zoomLevels << 0.5;
    zoomLevels << 2.0 / 3.0;
    zoomLevels << 1.0;

    for (qreal zoom = zoomLevels.first() / defaultZoomStep;
86
         zoom > parent->minimumZoom();
87 88 89 90 91 92
         zoom /= defaultZoomStep) {

        zoomLevels.prepend(zoom);
    }

    for (qreal zoom = zoomLevels.last() * defaultZoomStep;
93
         zoom < parent->maximumZoom();
94 95 96 97 98 99 100 101 102 103 104 105
         zoom *= defaultZoomStep) {

        zoomLevels.append(zoom);
    }

    return zoomLevels;
}

QList<qreal> KoZoomAction::Private::filterMenuZoomLevels(const QList<qreal> &zoomLevels) const
{
    QList<qreal> filteredZoomLevels;

106
    Q_FOREACH (qreal zoom, zoomLevels) {
107 108 109 110 111 112 113 114
        if (zoom >= 0.2 && zoom <= 10) {
            filteredZoomLevels << zoom;
        }
    }

    return filteredZoomLevels;
}

115
KoZoomAction::KoZoomAction(KoZoomMode::Modes zoomModes, const QString& text, QObject *parent)
116
    : KSelectAction(text, parent)
117
    , d(new Private(this))
118 119
{
    d->zoomModes = zoomModes;
120
    setIcon(koIcon("zoom-original"));
121 122 123
    setEditable( true );
    setMaxComboViewCount( 15 );

124
    d->sliderLookup = d->generateSliderZoomLevels();
125

126 127 128
    d->effectiveZoom = 1.0;
    regenerateItems(d->effectiveZoom, true);

129
    connect( this, SIGNAL(triggered(QString)), SLOT(triggered(QString)) );
130 131 132 133 134 135 136
}

KoZoomAction::~KoZoomAction()
{
    delete d;
}

137 138 139 140 141
qreal KoZoomAction::effectiveZoom() const
{
    return d->effectiveZoom;
}

142
void KoZoomAction::setZoom(qreal zoom)
143 144
{
    setEffectiveZoom(zoom);
145
    regenerateItems(d->effectiveZoom, true);
146 147
}

148
void KoZoomAction::triggered(const QString& text)
149 150 151 152
{
    QString zoomString = text;
    zoomString = zoomString.remove( '&' );

153
    KoZoomMode::Mode mode = KoZoomMode::toMode(zoomString);
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    int zoom = 0;

    if( mode == KoZoomMode::ZOOM_CONSTANT ) {
        bool ok;
        QRegExp regexp( ".*(\\d+).*" ); // "Captured" non-empty sequence of digits
        int pos = regexp.indexIn( zoomString );

        if( pos > -1 ) {
            zoom = regexp.cap( 1 ).toInt( &ok );

            if( !ok ) {
                zoom = 0;
            }
        }
    }

    emit zoomChanged( mode, zoom/100.0 );
}

void KoZoomAction::setZoomModes( KoZoomMode::Modes zoomModes )
{
    d->zoomModes = zoomModes;
    regenerateItems( d->effectiveZoom );
}

void KoZoomAction::regenerateItems(const qreal zoom, bool asCurrent)
{
181 182 183 184
    QList<qreal> zoomLevels = d->filterMenuZoomLevels(d->sliderLookup);

    if( !zoomLevels.contains( zoom ) )
        zoomLevels << zoom;
185

186
    std::sort(zoomLevels.begin(), zoomLevels.end());
187 188 189

    // update items with new sorted zoom values
    QStringList values;
190
    if(d->zoomModes & KoZoomMode::ZOOM_WIDTH) {
191 192
        values << KoZoomMode::toString(KoZoomMode::ZOOM_WIDTH);
    }
193
    if(d->zoomModes & KoZoomMode::ZOOM_PAGE) {
194 195 196
        values << KoZoomMode::toString(KoZoomMode::ZOOM_PAGE);
    }

197
    Q_FOREACH (qreal value, zoomLevels) {
198 199 200 201
        const qreal valueInPercent = value * 100;
        const int precision = (value > 10.0) ? 0 : 1;

        values << i18n("%1%", QLocale().toString(valueInPercent, 'f', precision));
202 203 204 205
    }

    setItems( values );

206
    emit zoomLevelsChanged(values);
207 208 209

    if(asCurrent)
    {
210 211 212 213 214
        const qreal zoomInPercent = zoom * 100;
        // TODO: why zoomInPercent and not zoom here? different from above
        const int precision = (zoomInPercent > 10.0) ? 0 : 1;

        const QString valueString = i18n("%1%", QLocale().toString(zoomInPercent, 'f', precision));
215 216 217

        setCurrentAction(valueString);

218
        emit currentZoomLevelChanged(valueString);
219 220 221 222 223 224 225
    }
}

void KoZoomAction::sliderValueChanged(int value)
{
    setZoom(d->sliderLookup[value]);

226
    emit zoomChanged(KoZoomMode::ZOOM_CONSTANT, d->sliderLookup[value]);
227 228
}

229 230 231 232 233 234 235 236 237 238 239
qreal KoZoomAction::nextZoomLevel() const
{
    const qreal eps = 1e-5;
    int i = 0;
    while (d->effectiveZoom > d->sliderLookup[i] - eps &&
           i < d->sliderLookup.size() - 1) i++;

    return qMax(d->effectiveZoom, d->sliderLookup[i]);
}

qreal KoZoomAction::prevZoomLevel() const
240
{
241 242 243 244 245 246
    const qreal eps = 1e-5;
    int i = d->sliderLookup.size() - 1;
    while (d->effectiveZoom < d->sliderLookup[i] + eps && i > 0) i--;

    return qMin(d->effectiveZoom, d->sliderLookup[i]);
}
247

248 249 250
void KoZoomAction::zoomIn()
{
    qreal zoom = nextZoomLevel();
251

252 253
    if (zoom > d->effectiveZoom) {
        setZoom(zoom);
254
        emit zoomChanged(KoZoomMode::ZOOM_CONSTANT, d->effectiveZoom);
255
    }
256 257 258 259
}

void KoZoomAction::zoomOut()
{
260
    qreal zoom = prevZoomLevel();
261

262 263
    if (zoom < d->effectiveZoom) {
        setZoom(zoom);
264
        emit zoomChanged(KoZoomMode::ZOOM_CONSTANT, d->effectiveZoom);
265
    }
266 267
}

268
QWidget * KoZoomAction::createWidget(QWidget *parent)
269
{
270
    KoZoomWidget* zoomWidget = new KoZoomWidget(parent, d->sliderLookup.size() - 1);
271 272 273 274 275
    connect(this, SIGNAL(zoomLevelsChanged(QStringList)), zoomWidget, SLOT(setZoomLevels(QStringList)));
    connect(this, SIGNAL(currentZoomLevelChanged(QString)), zoomWidget, SLOT(setCurrentZoomLevel(QString)));
    connect(this, SIGNAL(sliderChanged(int)), zoomWidget, SLOT(setSliderValue(int)));
    connect(this, SIGNAL(aspectModeChanged(bool)), zoomWidget, SLOT(setAspectMode(bool)));
    connect(zoomWidget, SIGNAL(sliderValueChanged(int)), this, SLOT(sliderValueChanged(int)));
276
    connect(zoomWidget, SIGNAL(zoomLevelChanged(QString)), this, SLOT(triggered(QString)));
277 278 279
    connect(zoomWidget, SIGNAL(aspectModeChanged(bool)), this, SIGNAL(aspectModeChanged(bool)));
    connect(zoomWidget, SIGNAL(zoomedToSelection()), this, SIGNAL(zoomedToSelection()));
    connect(zoomWidget, SIGNAL(zoomedToAll()), this, SIGNAL(zoomedToAll()));
280
    regenerateItems( d->effectiveZoom, true );
281 282
    syncSliderWithZoom();
    return zoomWidget;
283 284 285 286 287 288
}

void KoZoomAction::setEffectiveZoom(qreal zoom)
{
    if(d->effectiveZoom == zoom)
        return;
289

290
    zoom = clampZoom(zoom);
291
    d->effectiveZoom = zoom;
292
    syncSliderWithZoom();
293 294
}

295
void KoZoomAction::setSelectedZoomMode(KoZoomMode::Mode mode)
296 297 298 299
{
    QString modeString(KoZoomMode::toString(mode));
    setCurrentAction(modeString);

300
    emit currentZoomLevelChanged(modeString);
301 302
}

303 304
void KoZoomAction::setAspectMode(bool status)
{
305 306 307 308 309 310 311 312 313 314
    emit aspectModeChanged(status);
}

void KoZoomAction::syncSliderWithZoom()
{
    const qreal eps = 1e-5;
    int i = d->sliderLookup.size() - 1;
    while (d->effectiveZoom < d->sliderLookup[i] + eps && i > 0) i--;
    
    emit sliderChanged(i);
315 316
}

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
qreal KoZoomAction::minimumZoom()
{
    if (d->minimumZoomValue < 0) {
        return KoZoomMode::minimumZoom();
    }
    return d->minimumZoomValue;
}

qreal KoZoomAction::maximumZoom()
{
    if (d->maximumZoomValue < 0) {
        return KoZoomMode::maximumZoom();
    }
    return d->maximumZoomValue;
}

qreal KoZoomAction::clampZoom(qreal zoom)
{
    return qMin(maximumZoom(), qMax(minimumZoom(), zoom));
}

void KoZoomAction::setMinimumZoom(qreal zoom)
{
    Q_ASSERT(zoom > 0.0f);
    KoZoomMode::setMinimumZoom(zoom);
    d->minimumZoomValue = zoom;
    d->generateSliderZoomLevels();
    d->sliderLookup = d->generateSliderZoomLevels();
    regenerateItems(d->effectiveZoom, true);
    syncSliderWithZoom();
}

void KoZoomAction::setMaximumZoom(qreal zoom)
{
    Q_ASSERT(zoom > 0.0f);
    KoZoomMode::setMaximumZoom(zoom);
    d->maximumZoomValue = zoom;
    d->sliderLookup = d->generateSliderZoomLevels();
    regenerateItems(d->effectiveZoom, true);
    syncSliderWithZoom();
}