pageview.cpp 118 KB
Newer Older
1
/***************************************************************************
2
 *   Copyright (C) 2004-2005 by Enrico Ros <eros.kde@email.it>             *
Albert Astals Cid's avatar
Albert Astals Cid committed
3
 *   Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es>       *
4
 *                                                                         *
5
 *   With portions of code from kpdf/kpdf_pagewidget.cc by:                *
6 7 8 9 10 11
 *     Copyright (C) 2002 by Wilco Greven <greven@kde.org>                 *
 *     Copyright (C) 2003 by Christophe Devriese                           *
 *                           <Christophe.Devriese@student.kuleuven.ac.be>  *
 *     Copyright (C) 2003 by Laurent Montel <montel@kde.org>               *
 *     Copyright (C) 2003 by Dirk Mueller <mueller@kde.org>                *
 *     Copyright (C) 2004 by James Ots <kde@jamesots.com>                  *
12 13 14 15 16 17 18
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

Albert Astals Cid's avatar
Albert Astals Cid committed
19 20
#include "pageview.h"

21
// qt/kde includes
22
#include <qcursor.h>
23
#include <qevent.h>
24
#include <qimage.h>
25 26
#include <qpainter.h>
#include <qtimer.h>
27
#include <qset.h>
28
#include <qscrollbar.h>
29
#include <qtooltip.h>
Enrico Ros's avatar
Enrico Ros committed
30 31
#include <qapplication.h>
#include <qclipboard.h>
32 33 34 35
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusConnectionInterface>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusReply>
36

37
#include <kaction.h>
Laurent Montel's avatar
Laurent Montel committed
38
#include <kstandardaction.h>
39
#include <kactioncollection.h>
40
#include <kmenu.h>
41
#include <klocale.h>
42
#include <kfiledialog.h>
Pino Toscano's avatar
Pino Toscano committed
43
#include <kglobal.h>
44
#include <kglobalsettings.h>
Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
45 46
#include <kselectaction.h>
#include <ktoggleaction.h>
47
#include <ktoolinvocation.h>
48
#include <kdebug.h>
49
#include <kmessagebox.h>
Laurent Montel's avatar
Laurent Montel committed
50
#include <kicon.h>
Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
51

52
// system includes
53
#include <math.h>
54
#include <stdlib.h>
55

56
// local includes
57
#include "formwidgets.h"
58
#include "pageviewutils.h"
59
#include "pagepainter.h"
60
#include "core/annotations.h"
61
#include "annotwindow.h"
Pino Toscano's avatar
Pino Toscano committed
62
#include "guiutils.h"
63
#include "annotationpopup.h"
64
#include "pageviewannotator.h"
65
#include "toolaction.h"
Pino Toscano's avatar
Pino Toscano committed
66
#include "core/action.h"
67
#include "core/document.h"
68
#include "core/form.h"
69
#include "core/page.h"
70
#include "core/misc.h"
71
#include "core/generator.h"
72
#include "settings.h"
73

74 75
static int pageflags = PagePainter::Accessibility | PagePainter::EnhanceLinks |
                       PagePainter::EnhanceImages | PagePainter::Highlights |
76
                       PagePainter::TextSelection | PagePainter::Annotations;
77

78 79 80 81
// structure used internally by PageView for data storage
class PageViewPrivate
{
public:
82 83 84 85
    PageViewPrivate( PageView *qq );

    FormWidgetsController* formWidgetsController();

86
    // the document, pageviewItems and the 'visible cache'
87
    PageView *q;
88
    Okular::Document * document;
89 90
    QVector< PageViewItem * > items;
    QLinkedList< PageViewItem * > visibleItems;
91

92
    // view layout (columns and continuous in Settings), zoom and mouse
93 94 95 96
    PageView::ZoomMode zoomMode;
    float zoomFactor;
    PageView::MouseMode mouseMode;
    QPoint mouseGrabPos;
97
    QPoint mousePressPos;
98
    QPoint mouseSelectPos;
99 100
    bool mouseMidZooming;
    int mouseMidLastY;
101
    bool mouseSelecting;
102
    QRect mouseSelectionRect;
103
    QColor mouseSelectionColor;
104
    bool mouseTextSelecting;
105
    QSet< int > pagesWithTextSelection;
106
    bool mouseOnRect;
107 108
    Okular::Annotation * mouseAnn;
    QPoint mouseAnnPos;
109

Enrico Ros's avatar
Enrico Ros committed
110 111 112 113 114 115
    // viewport move
    bool viewportMoveActive;
    QTime viewportMoveTime;
    QPoint viewportMoveDest;
    QTimer * viewportMoveTimer;
    // auto scroll
116
    int scrollIncrement;
Enrico Ros's avatar
Enrico Ros committed
117
    QTimer * autoScrollTimer;
118
    // annotations
119
    PageViewAnnotator * annotator;
120
    //text annotation dialogs list
121
    QList<AnnotWindow *> m_annowindows;
Enrico Ros's avatar
Enrico Ros committed
122 123
    // other stuff
    QTimer * delayResizeTimer;
124
    bool dirtyLayout;
Enrico Ros's avatar
Enrico Ros committed
125
    bool blockViewport;                 // prevents changes to viewport
126 127
    bool blockPixmapsRequest;           // prevent pixmap requests
    PageViewMessage * messageWindow;    // in pageviewutils.h
128
    bool m_formsVisible;
129
    FormWidgetsController *formsWidgetController;
130

131 132 133 134
    // drag scroll
    QPoint dragScrollVector;
    QTimer dragScrollTimer;

135
    // actions
136 137 138
    KAction * aRotateClockwise;
    KAction * aRotateCounterClockwise;
    KAction * aRotateOriginal;
139
    KSelectAction * aPageSizes;
Laurent Montel's avatar
Laurent Montel committed
140 141 142
    QAction * aMouseNormal;
    QAction * aMouseSelect;
    QAction * aMouseTextSelect;
143
    KToggleAction * aToggleAnnotator;
144
    KSelectAction * aZoom;
145 146
    QAction * aZoomIn;
    QAction * aZoomOut;
147 148 149
    KToggleAction * aZoomFitWidth;
    KToggleAction * aZoomFitPage;
    KToggleAction * aZoomFitText;
150
    KSelectAction * aViewMode;
151
    KToggleAction * aViewContinuous;
Laurent Montel's avatar
Laurent Montel committed
152
    QAction * aPrevAction;
153
    KAction * aToggleForms;
154
    KActionCollection * actionCollection;
155

156
    int setting_viewMode;
157
    int setting_viewCols;
158 159
};

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
PageViewPrivate::PageViewPrivate( PageView *qq )
    : q( qq )
{
}

FormWidgetsController* PageViewPrivate::formWidgetsController()
{
    if ( !formsWidgetController )
    {
        formsWidgetController = new FormWidgetsController();
        QObject::connect( formsWidgetController, SIGNAL( changed( FormWidgetIface* ) ),
                          q, SLOT( slotFormWidgetChanged( FormWidgetIface * ) ) );
    }

    return formsWidgetController;
}


178 179 180 181 182 183 184 185
class PageViewWidget : public QWidget
{
public:
    PageViewWidget(PageView *pv) : QWidget(pv), m_pageView(pv) {}

protected:
    bool event( QEvent *e )
    {
Albert Astals Cid's avatar
Albert Astals Cid committed
186
        if ( e->type() == QEvent::ToolTip && m_pageView->d->mouseMode == PageView::MouseNormal )
187 188 189 190
        {
            QHelpEvent * he = (QHelpEvent*)e;
            PageViewItem * pageItem = m_pageView->pickItemOnPoint( he->x(), he->y() );
            const Okular::ObjectRect * rect = 0;
Pino Toscano's avatar
Pino Toscano committed
191
            const Okular::Action * link = 0;
192
            const Okular::Annotation * ann = 0;
193 194 195 196
            if ( pageItem )
            {
                double nX = (double)( he->x() - pageItem->geometry().left() ) / (double)pageItem->width();
                double nY = (double)( he->y() - pageItem->geometry().top() ) / (double)pageItem->height();
197
                rect = pageItem->page()->objectRect( Okular::ObjectRect::OAnnotation, nX, nY, pageItem->width(), pageItem->height() );
198
                if ( rect )
199
                    ann = static_cast< const Okular::AnnotationObjectRect * >( rect )->annotation();
200 201
                else
                {
Pino Toscano's avatar
Pino Toscano committed
202
                    rect = pageItem->page()->objectRect( Okular::ObjectRect::Action, nX, nY, pageItem->width(), pageItem->height() );
203
                    if ( rect )
Pino Toscano's avatar
Pino Toscano committed
204
                        link = static_cast< const Okular::Action * >( rect->object() );
205
                }
206 207
            }

208
            if ( ann )
209 210 211
            {
                QRect r = rect->boundingRect( pageItem->width(), pageItem->height() );
                r.translate( pageItem->geometry().left(), pageItem->geometry().top() );
Pino Toscano's avatar
Pino Toscano committed
212
                QString tip = GuiUtils::prettyToolTip( ann );
213
                QToolTip::showText( he->globalPos(), tip, this, r );
214
            }
215
            else if ( link )
216 217 218
            {
                QRect r = rect->boundingRect( pageItem->width(), pageItem->height() );
                r.translate( pageItem->geometry().left(), pageItem->geometry().top() );
Pino Toscano's avatar
Pino Toscano committed
219
                QString tip = link->actionTip();
220 221
                if ( !tip.isEmpty() )
                    QToolTip::showText( he->globalPos(), tip, this, r );
222
            }
223 224 225 226 227 228 229 230 231 232 233 234 235
            e->accept();
            return true;
        }
        else
            // do not stop the event
            return QWidget::event( e );
    }

    // viewport events
    void paintEvent( QPaintEvent *e )
    {
        m_pageView->contentsPaintEvent(e);
    }
236

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
    void mouseMoveEvent( QMouseEvent *e )
    {
        m_pageView->contentsMouseMoveEvent(e);
    }

    void mousePressEvent( QMouseEvent *e )
    {
        m_pageView->contentsMousePressEvent(e);
    }

    void mouseReleaseEvent( QMouseEvent *e )
    {
        m_pageView->contentsMouseReleaseEvent(e);
    }


private:
   PageView *m_pageView;
};
256

257 258 259 260
/* PageView. What's in this file? -> quick overview.
 * Code weight (in rows) and meaning:
 *  160 - constructor and creating actions plus their connected slots (empty stuff)
 *  70  - DocumentObserver inherited methodes (important)
261
 *  550 - events: mouse, keyboard, drag/drop
262
 *  170 - slotRelayoutPages: set contents of the scrollview on continuous/single modes
263
 *  100 - zoom: zooming pages in different ways, keeping update the toolbar actions, etc..
264
 *  other misc functions: only slotRequestVisiblePixmaps and pickItemOnPoint noticeable,
265
 * and many insignificant stuff like this comment :-)
266
 */
267
PageView::PageView( QWidget *parent, Okular::Document *document )
268
    : QScrollArea( parent )
269 270
{
    // create and initialize private storage structure
271
    d = new PageViewPrivate( this );
272
    d->document = document;
273 274 275
    d->aRotateClockwise = 0;
    d->aRotateCounterClockwise = 0;
    d->aRotateOriginal = 0;
276
    d->aViewMode = 0;
277 278
    d->zoomMode = (PageView::ZoomMode) Okular::Settings::zoomMode();
    d->zoomFactor = Okular::Settings::zoomFactor();
279
    d->mouseMode = MouseNormal;
280
    d->mouseMidZooming = false;
281
    d->mouseSelecting = false;
282
    d->mouseTextSelecting = false;
283
    d->mouseOnRect = false;
284
    d->mouseAnn = 0;
Enrico Ros's avatar
Enrico Ros committed
285 286
    d->viewportMoveActive = false;
    d->viewportMoveTimer = 0;
287
    d->scrollIncrement = 0;
Enrico Ros's avatar
Enrico Ros committed
288
    d->autoScrollTimer = 0;
289
    d->annotator = 0;
Enrico Ros's avatar
Enrico Ros committed
290
    d->delayResizeTimer = 0;
291
    d->dirtyLayout = false;
292
    d->blockViewport = false;
293
    d->blockPixmapsRequest = false;
294
    d->messageWindow = new PageViewMessage(this);
295
    d->m_formsVisible = false;
296
    d->formsWidgetController = 0;
297 298 299 300 301 302 303 304 305 306 307 308 309
    d->aRotateClockwise = 0;
    d->aRotateCounterClockwise = 0;
    d->aRotateOriginal = 0;
    d->aPageSizes = 0;
    d->aMouseNormal = 0;
    d->aMouseSelect = 0;
    d->aMouseTextSelect = 0;
    d->aToggleAnnotator = 0;
    d->aZoomFitWidth = 0;
    d->aZoomFitPage = 0;
    d->aZoomFitText = 0;
    d->aViewMode = 0;
    d->aViewContinuous = 0;
310
    d->aPrevAction = 0;
311
    d->aToggleForms = 0;
312
    d->actionCollection = 0;
313
    d->aPageSizes=0;
314
    d->setting_viewMode = Okular::Settings::viewMode();
315
    d->setting_viewCols = Okular::Settings::viewColumns();
316

317 318
    setFrameStyle(QFrame::NoFrame);

Pino Toscano's avatar
Pino Toscano committed
319 320
    setAttribute( Qt::WA_StaticContents );

Albert Astals Cid's avatar
Albert Astals Cid committed
321
    setObjectName( QLatin1String( "okular::pageView" ) );
Pino Toscano's avatar
Pino Toscano committed
322

323
    // widget setup: setup focus, accept drops and track mouse
324
    setWidget(new PageViewWidget(this));
325
    viewport()->setFocusProxy( this );
326
    viewport()->setFocusPolicy( Qt::StrongFocus );
327 328
    widget()->setAttribute( Qt::WA_OpaquePaintEvent );
    widget()->setAttribute( Qt::WA_NoSystemBackground );
329
    setAcceptDrops( true );
330 331
    widget()->setMouseTracking( true );
    setWidgetResizable(true);
332 333

    // conntect the padding of the viewport to pixmaps requests
334 335
    connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotRequestVisiblePixmaps()));
    connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotRequestVisiblePixmaps()));
336
    connect( &d->dragScrollTimer, SIGNAL(timeout()), this, SLOT(slotDragScroll()) );
337 338

    // set a corner button to resize the view to the page size
339 340 341 342
//    QPushButton * resizeButton = new QPushButton( viewport() );
//    resizeButton->setPixmap( SmallIcon("crop") );
//    setCornerWidget( resizeButton );
//    resizeButton->setEnabled( false );
343
    // connect(...);
Tobias Koenig's avatar
Tobias Koenig committed
344
    setAttribute( Qt::WA_InputMethodEnabled, true );
345 346

    // schedule the welcome message
347
    QMetaObject::invokeMethod(this, "slotShowWelcome", Qt::QueuedConnection);
348 349 350 351
}

PageView::~PageView()
{
352
    // delete the local storage structure
353
    qDeleteAll(d->m_annowindows);
354
    // delete all widgets
355
    QVector< PageViewItem * >::const_iterator dIt = d->items.begin(), dEnd = d->items.end();
356 357
    for ( ; dIt != dEnd; ++dIt )
        delete *dIt;
358
    delete d->formsWidgetController;
Albert Astals Cid's avatar
Albert Astals Cid committed
359
    d->document->removeObserver( this );
360 361 362
    delete d;
}

363 364 365 366 367 368 369 370 371 372 373 374
void PageView::setupBaseActions( KActionCollection * ac )
{
    d->actionCollection = ac;

    // Zoom actions ( higher scales takes lots of memory! )
    d->aZoom  = new KSelectAction(KIcon( "zoom-original" ), i18n("Zoom"), this);
    ac->addAction("zoom_to", d->aZoom );
    d->aZoom->setEditable( true );
    d->aZoom->setMaxComboViewCount( 13 );
    connect( d->aZoom, SIGNAL( triggered(QAction *) ), this, SLOT( slotZoom() ) );
    updateZoomText();

Pino Toscano's avatar
Pino Toscano committed
375
    d->aZoomIn = KStandardAction::zoomIn( this, SLOT( slotZoomIn() ), ac );
376

Pino Toscano's avatar
Pino Toscano committed
377
    d->aZoomOut = KStandardAction::zoomOut( this, SLOT( slotZoomOut() ), ac );
378 379
}

380
void PageView::setupActions( KActionCollection * ac )
381
{
382 383
    d->actionCollection = ac;

384
    // orientation menu actions
385
    d->aRotateClockwise = new KAction( KIcon( "object-rotate-right" ), i18n( "Rotate Right" ), this );
386
    d->aRotateClockwise->setIconText( i18nc( "Rotate right", "Right" ) );
387
    ac->addAction( "view_orientation_rotate_cw", d->aRotateClockwise );
388
    d->aRotateClockwise->setEnabled( false );
389
    connect( d->aRotateClockwise, SIGNAL( triggered() ), this, SLOT( slotRotateClockwise() ) );
390
    d->aRotateCounterClockwise = new KAction( KIcon( "object-rotate-left" ), i18n( "Rotate Left" ), this );
391
    d->aRotateCounterClockwise->setIconText( i18nc( "Rotate left", "Left" ) );
392
    ac->addAction( "view_orientation_rotate_ccw", d->aRotateCounterClockwise );
393
    d->aRotateCounterClockwise->setEnabled( false );
394 395 396
    connect( d->aRotateCounterClockwise, SIGNAL( triggered() ), this, SLOT( slotRotateCounterClockwise() ) );
    d->aRotateOriginal = new KAction( i18n( "Original Orientation" ), this );
    ac->addAction( "view_orientation_original", d->aRotateOriginal );
397
    d->aRotateOriginal->setEnabled( false );
398 399
    connect( d->aRotateOriginal, SIGNAL( triggered() ), this, SLOT( slotRotateOriginal() ) );

Laurent Montel's avatar
Laurent Montel committed
400 401
    d->aPageSizes = new KSelectAction(i18n("&Page Size"), this);
    ac->addAction("view_pagesizes", d->aPageSizes);
402
    d->aPageSizes->setEnabled( false );
403

404
    connect( d->aPageSizes , SIGNAL( triggered( int ) ),
405
         this, SLOT( slotPageSizes( int ) ) );
406

Laurent Montel's avatar
Laurent Montel committed
407
    d->aZoomFitWidth  = new KToggleAction(KIcon( "view_fit_width" ), i18n("Fit &Width"), this);
Pino Toscano's avatar
Pino Toscano committed
408
    ac->addAction("view_fit_to_width", d->aZoomFitWidth );
409 410
    connect( d->aZoomFitWidth, SIGNAL( toggled( bool ) ), SLOT( slotFitToWidthToggled( bool ) ) );

Laurent Montel's avatar
Laurent Montel committed
411
    d->aZoomFitPage  = new KToggleAction(KIcon( "view_fit_window" ), i18n("Fit &Page"), this);
Pino Toscano's avatar
Pino Toscano committed
412
    ac->addAction("view_fit_to_page", d->aZoomFitPage );
413 414
    connect( d->aZoomFitPage, SIGNAL( toggled( bool ) ), SLOT( slotFitToPageToggled( bool ) ) );

415
/*
416
    d->aZoomFitText  = new KToggleAction(KIcon( "zoom-best-fit" ), i18n("Fit &Text"), this);
Laurent Montel's avatar
Laurent Montel committed
417
    ac->addAction("zoom_fit_text", d->aZoomFitText );
418
    connect( d->aZoomFitText, SIGNAL( toggled( bool ) ), SLOT( slotFitToTextToggled( bool ) ) );
419
*/
420

421
    // View-Layout actions
422
    QStringList viewModes;
Pino Toscano's avatar
Pino Toscano committed
423 424
    viewModes.append( i18n( "Single Page" ) );
    viewModes.append( i18n( "Facing Pages" ) );
425
    viewModes.append( i18n( "Overview" ) );
426

427 428 429 430 431
    d->aViewMode  = new KSelectAction(KIcon( "view-left-right" ), i18n("&View Mode"), this);
    ac->addAction("view_render_mode", d->aViewMode );
    connect( d->aViewMode, SIGNAL( triggered( int ) ), SLOT( slotViewMode( int ) ) );
    d->aViewMode->setItems( viewModes );
    d->aViewMode->setCurrentItem( Okular::Settings::viewMode() );
432

433
    d->aViewContinuous  = new KToggleAction(KIcon( "fileview-text" ), i18n("&Continuous"), this);
Laurent Montel's avatar
Laurent Montel committed
434
    ac->addAction("view_continuous", d->aViewContinuous );
435
    connect( d->aViewContinuous, SIGNAL( toggled( bool ) ), SLOT( slotContinuousToggled( bool ) ) );
436
    d->aViewContinuous->setChecked( Okular::Settings::viewContinuous() );
437 438

    // Mouse-Mode actions
Pino Toscano's avatar
porting  
Pino Toscano committed
439 440
    QActionGroup * actGroup = new QActionGroup( this );
    actGroup->setExclusive( true );
441
    d->aMouseNormal  = new KAction( KIcon( "input-mouse" ), i18n( "&Browse Tool" ), this );
Laurent Montel's avatar
Laurent Montel committed
442
    ac->addAction("mouse_drag", d->aMouseNormal );
443
    connect( d->aMouseNormal, SIGNAL( triggered() ), this, SLOT( slotSetMouseNormal() ) );
Pino Toscano's avatar
Pino Toscano committed
444
    d->aMouseNormal->setIconText( i18nc( "Browse Tool", "Browse" ) );
Pino Toscano's avatar
Pino Toscano committed
445
    d->aMouseNormal->setCheckable( true );
446
    d->aMouseNormal->setShortcut( Qt::CTRL + Qt::Key_1 );
Pino Toscano's avatar
porting  
Pino Toscano committed
447
    d->aMouseNormal->setActionGroup( actGroup );
448
    d->aMouseNormal->setChecked( true );
449

450
    KAction * mz  = new KAction(KIcon( "zoom-original" ), i18n("&Zoom Tool"), this);
Laurent Montel's avatar
Laurent Montel committed
451
    ac->addAction("mouse_zoom", mz );
452
    connect( mz, SIGNAL( triggered() ), this, SLOT( slotSetMouseZoom() ) );
Pino Toscano's avatar
Pino Toscano committed
453
    mz->setIconText( i18nc( "Zoom Tool", "Zoom" ) );
Pino Toscano's avatar
Pino Toscano committed
454
    mz->setCheckable( true );
455
    mz->setShortcut( Qt::CTRL + Qt::Key_2 );
Pino Toscano's avatar
porting  
Pino Toscano committed
456
    mz->setActionGroup( actGroup );
457

Pino Toscano's avatar
Pino Toscano committed
458
    d->aMouseSelect  = new KAction(KIcon( "frame-edit" ), i18n("&Selection Tool"), this);
Laurent Montel's avatar
Laurent Montel committed
459
    ac->addAction("mouse_select", d->aMouseSelect );
460
    connect( d->aMouseSelect, SIGNAL( triggered() ), this, SLOT( slotSetMouseSelect() ) );
Pino Toscano's avatar
Pino Toscano committed
461
    d->aMouseSelect->setIconText( i18nc( "Select Tool", "Selection" ) );
Pino Toscano's avatar
Pino Toscano committed
462
    d->aMouseSelect->setCheckable( true );
463
    d->aMouseSelect->setShortcut( Qt::CTRL + Qt::Key_3 );
Pino Toscano's avatar
porting  
Pino Toscano committed
464
    d->aMouseSelect->setActionGroup( actGroup );
465

Laurent Montel's avatar
Laurent Montel committed
466 467
    d->aMouseTextSelect  = new KAction(KIcon( "text" ), i18n("&Text Selection Tool"), this);
    ac->addAction("mouse_textselect", d->aMouseTextSelect );
468
    connect( d->aMouseTextSelect, SIGNAL( triggered() ), this, SLOT( slotSetMouseTextSelect() ) );
Pino Toscano's avatar
Pino Toscano committed
469
    d->aMouseTextSelect->setIconText( i18nc( "Text Selection Tool", "Text Selection" ) );
470
    d->aMouseTextSelect->setCheckable( true );
471
    d->aMouseTextSelect->setShortcut( Qt::CTRL + Qt::Key_4 );
472 473
    d->aMouseTextSelect->setActionGroup( actGroup );

Pino Toscano's avatar
Pino Toscano committed
474
    d->aToggleAnnotator  = new KToggleAction(KIcon( "draw-freehand" ), i18n("&Review"), this);
Laurent Montel's avatar
Laurent Montel committed
475
    ac->addAction("mouse_toggle_annotate", d->aToggleAnnotator );
Pino Toscano's avatar
Pino Toscano committed
476
    d->aToggleAnnotator->setCheckable( true );
477
    connect( d->aToggleAnnotator, SIGNAL( toggled( bool ) ), SLOT( slotToggleAnnotator( bool ) ) );
Albert Astals Cid's avatar
Albert Astals Cid committed
478
    d->aToggleAnnotator->setShortcut( Qt::Key_F6 );
479

480 481 482 483 484
    ToolAction *ta = new ToolAction( this );
    ac->addAction( "mouse_selecttools", ta );
    ta->addAction( d->aMouseSelect );
    ta->addAction( d->aMouseTextSelect );

485
    // Other actions
Laurent Montel's avatar
Laurent Montel committed
486 487
    KAction * su  = new KAction(i18n("Scroll Up"), this);
    ac->addAction("view_scroll_up", su );
488 489
    connect( su, SIGNAL( triggered() ), this, SLOT( slotScrollUp() ) );
    su->setShortcut( QKeySequence(Qt::SHIFT + Qt::Key_Up) );
Albert Astals Cid's avatar
Albert Astals Cid committed
490
    addAction(su);
491

Laurent Montel's avatar
Laurent Montel committed
492 493
    KAction * sd  = new KAction(i18n("Scroll Down"), this);
    ac->addAction("view_scroll_down", sd );
494 495
    connect( sd, SIGNAL( triggered() ), this, SLOT( slotScrollDown() ) );
    sd->setShortcut( QKeySequence(Qt::SHIFT + Qt::Key_Down) );
Albert Astals Cid's avatar
Albert Astals Cid committed
496
    addAction(sd);
497 498 499 500

    d->aToggleForms = new KAction( this );
    ac->addAction( "view_toggle_forms", d->aToggleForms );
    connect( d->aToggleForms, SIGNAL( triggered() ), this, SLOT( slotToggleForms() ) );
501
    d->aToggleForms->setEnabled( false );
502
    toggleFormWidgets( false );
503 504
}

Pino Toscano's avatar
Pino Toscano committed
505
bool PageView::canFitPageWidth() const
506
{
507
    return Okular::Settings::viewMode() != 0 || d->zoomMode != ZoomFitWidth;
508 509
}

510
void PageView::fitPageWidth( int page )
511
{
512
    // zoom: Fit Width, columns: 1. setActions + relayout + setPage + update
513
    d->zoomMode = ZoomFitWidth;
514
    Okular::Settings::setViewMode( 0 );
515 516
    d->aZoomFitWidth->setChecked( true );
    d->aZoomFitPage->setChecked( false );
517
//    d->aZoomFitText->setChecked( false );
518
    d->aViewMode->setCurrentItem( 0 );
519 520 521
    viewport()->setUpdatesEnabled( false );
    slotRelayoutPages();
    viewport()->setUpdatesEnabled( true );
522
    d->document->setViewportPage( page );
523
    updateZoomText();
Enrico Ros's avatar
Enrico Ros committed
524
    setFocus();
525 526
}

527
void PageView::setAnnotationWindow( Okular::Annotation * annotation )
528
{
529
    if ( !annotation )
530
        return;
531 532 533 534

    // find the annot window
    AnnotWindow* existWindow = 0;
    foreach ( AnnotWindow* tempwnd, d->m_annowindows )
535
    {
536
        if ( tempwnd )
537
        {
538
            if ( tempwnd->m_annot == annotation )
539
            {
540
                existWindow = tempwnd;
541 542 543 544
                break;
            }
        }
    }
545 546

    if ( existWindow == 0 )
547
    {
548 549 550
        existWindow = new AnnotWindow( this, annotation );

        d->m_annowindows << existWindow;
551
    }
552 553 554 555 556 557 558 559 560 561 562

    existWindow->show();
}

void PageView::removeAnnotationWindow( Okular::Annotation *annotation )
{
    QList<AnnotWindow *>::Iterator it = d->m_annowindows.begin();
    QList<AnnotWindow *>::Iterator itEnd = d->m_annowindows.end();
    for ( ; it != itEnd; ++it )
    {
        if ( annotation == (*it)->m_annot )
563
        {
564 565 566 567
            delete *it;
            d->m_annowindows.erase( it );

            return;
568
        }
569
    }
570 571
}

572
void PageView::displayMessage( const QString & message,PageViewMessage::Icon icon,int duration )
573
{
574
    if ( !Okular::Settings::showOSD() )
575 576 577 578 579 580
    {
        if (icon == PageViewMessage::Error)
            KMessageBox::error( this, message );
        else
            return;
    }
581 582 583 584 585 586

    // hide messageWindow if string is empty
    if ( message.isEmpty() )
        return d->messageWindow->hide();

    // display message (duration is length dependant)
587 588 589
    if (duration==-1)
        duration = 500 + 100 * message.length();
    d->messageWindow->display( message, icon, duration );
590 591
}

592 593 594 595 596 597 598 599 600 601 602
void PageView::reparseConfig()
{
    // set the scroll bars policies
    Qt::ScrollBarPolicy scrollBarMode = Okular::Settings::showScrollBars() ?
        Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff;
    if ( horizontalScrollBarPolicy() != scrollBarMode )
    {
        setHorizontalScrollBarPolicy( scrollBarMode );
        setVerticalScrollBarPolicy( scrollBarMode );
    }

603
    if ( Okular::Settings::viewMode() == 2 &&
604
         ( (int)Okular::Settings::viewColumns() != d->setting_viewCols ) )
605
    {
606
        d->setting_viewMode = Okular::Settings::viewMode();
607
        d->setting_viewCols = Okular::Settings::viewColumns();
608 609 610 611 612

        slotRelayoutPages();
    }
}

613 614 615 616 617
KAction *PageView::toggleFormsAction() const
{
    return d->aToggleForms;
}

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
void PageView::copyTextSelection() const
{
    if ( d->pagesWithTextSelection.isEmpty() )
        return;

    QString text;
    QList< int > selpages = d->pagesWithTextSelection.toList();
    qSort( selpages );
    const Okular::Page * pg = 0;
    if ( selpages.count() == 1 )
    {
        pg = d->document->page( selpages.first() );
        text.append( pg->text( pg->textSelection() ) );
    }
    else
    {
        pg = d->document->page( selpages.first() );
        text.append( pg->text( pg->textSelection() ) );
        int end = selpages.count() - 1;
        for( int i = 1; i < end; ++i )
        {
            pg = d->document->page( selpages.at( i ) );
            text.append( pg->text() );
        }
        pg = d->document->page( selpages.last() );
        text.append( pg->text( pg->textSelection() ) );
    }
    if ( !text.isEmpty() )
    {
        QClipboard *cb = QApplication::clipboard();
        cb->setText( text, QClipboard::Clipboard );
        if ( cb->supportsSelection() )
            cb->setText( text, QClipboard::Selection );
    }
}

654 655 656 657 658 659 660 661 662 663 664 665 666 667
void PageView::selectAll()
{
    if ( d->mouseMode != MouseTextSelect )
        return;

    QVector< PageViewItem * >::const_iterator it = d->items.begin(), itEnd = d->items.end();
    for ( ; it < itEnd; ++it )
    {
        Okular::RegularAreaRect * area = textSelectionForItem( *it );
        d->pagesWithTextSelection.insert( (*it)->pageNumber() );
        d->document->setPageTextSelection( (*it)->pageNumber(), area, palette().color( QPalette::Active, QPalette::Highlight ) );
    }
}

668
//BEGIN DocumentObserver inherited methods
669
void PageView::notifySetup( const QVector< Okular::Page * > & pageSet, int setupFlags )
Enrico Ros's avatar
Enrico Ros committed
670
{
671
    bool documentChanged = setupFlags & Okular::DocumentObserver::DocumentChanged;
Enrico Ros's avatar
Enrico Ros committed
672
    // reuse current pages if nothing new
673
    if ( ( pageSet.count() == d->items.count() ) && !documentChanged && !( setupFlags & Okular::DocumentObserver::NewLayoutForPages ) )
Enrico Ros's avatar
Enrico Ros committed
674 675 676
    {
        int count = pageSet.count();
        for ( int i = 0; (i < count) && !documentChanged; i++ )
677
            if ( (int)pageSet[i]->number() != d->items[i]->pageNumber() )
Enrico Ros's avatar
Enrico Ros committed
678 679 680 681
                documentChanged = true;
        if ( !documentChanged )
            return;
    }
682
 
Enrico Ros's avatar
Enrico Ros committed
683
    // delete all widgets (one for each page in pageSet)
684
    QVector< PageViewItem * >::const_iterator dIt = d->items.begin(), dEnd = d->items.end();
685 686
    for ( ; dIt != dEnd; ++dIt )
        delete *dIt;
687
    d->items.clear();
688
    d->visibleItems.clear();
689
    d->pagesWithTextSelection.clear();
690
    toggleFormWidgets( false );
691

692
    bool haspages = !pageSet.isEmpty();
693
    bool hasformwidgets = false;
694
    // create children widgets
695
    QVector< Okular::Page * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end();
696
    for ( ; setIt != setEnd; ++setIt )
697
    {
698 699
        PageViewItem * item = new PageViewItem( *setIt );
        d->items.push_back( item );
700
#ifdef PAGEVIEW_DEBUG
701
        kDebug().nospace() << "geom for " << d->items.last()->pageNumber() << " is " << d->items.last()->geometry();
702
#endif
703 704 705 706 707 708 709 710
        const QLinkedList< Okular::FormField * > pageFields = (*setIt)->formFields();
        QLinkedList< Okular::FormField * >::const_iterator ffIt = pageFields.begin(), ffEnd = pageFields.end();
        for ( ; ffIt != ffEnd; ++ffIt )
        {
            Okular::FormField * ff = *ffIt;
            FormWidgetIface * w = FormWidgetFactory::createWidget( ff, widget() );
            if ( w )
            {
711 712
                w->setPageItem( item );
                w->setFormWidgetsController( d->formWidgetsController() );
713
                w->setVisibility( false );
714
                w->setCanBeFilled( d->document->isAllowed( Okular::AllowFillForms ) );
715 716 717 718
                item->formWidgets().insert( ff->name(), w );
                hasformwidgets = true;
            }
        }
719
    }
720

721
    // invalidate layout so relayout/repaint will happen on next viewport change
722
    if ( haspages )
723 724 725
        // TODO for Enrico: Check if doing always the slotRelayoutPages() is not
        // suboptimal in some cases, i'd say it is not but a recheck will not hurt
        // Need slotRelayoutPages() here instead of d->dirtyLayout = true
Pino Toscano's avatar
Pino Toscano committed
726
        // because opening a document from another document will not trigger a viewportchange
727
        // so pages are never relayouted
728
        QMetaObject::invokeMethod(this, "slotRelayoutPages", Qt::QueuedConnection);
729
    else
Piotr Szymanski's avatar