pageview.cpp 119 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
    bool setting_centerFirst;
159 160
};

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
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;
}


179 180 181 182 183 184 185 186
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
187
        if ( e->type() == QEvent::ToolTip && m_pageView->d->mouseMode == PageView::MouseNormal )
188 189 190 191
        {
            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
192
            const Okular::Action * link = 0;
193
            const Okular::Annotation * ann = 0;
194 195 196 197
            if ( pageItem )
            {
                double nX = (double)( he->x() - pageItem->geometry().left() ) / (double)pageItem->width();
                double nY = (double)( he->y() - pageItem->geometry().top() ) / (double)pageItem->height();
198
                rect = pageItem->page()->objectRect( Okular::ObjectRect::OAnnotation, nX, nY, pageItem->width(), pageItem->height() );
199
                if ( rect )
200
                    ann = static_cast< const Okular::AnnotationObjectRect * >( rect )->annotation();
201 202
                else
                {
Pino Toscano's avatar
Pino Toscano committed
203
                    rect = pageItem->page()->objectRect( Okular::ObjectRect::Action, nX, nY, pageItem->width(), pageItem->height() );
204
                    if ( rect )
Pino Toscano's avatar
Pino Toscano committed
205
                        link = static_cast< const Okular::Action * >( rect->object() );
206
                }
207 208
            }

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

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

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    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;
};
257

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

319 320
    setFrameStyle(QFrame::NoFrame);

Pino Toscano's avatar
Pino Toscano committed
321 322
    setAttribute( Qt::WA_StaticContents );

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

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

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

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

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

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

365 366 367 368 369 370 371 372 373 374 375 376
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
377
    d->aZoomIn = KStandardAction::zoomIn( this, SLOT( slotZoomIn() ), ac );
378

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

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

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

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

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

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

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

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

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

429 430 431 432 433
    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() );
434

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    if ( existWindow == 0 )
549
    {
550 551 552
        existWindow = new AnnotWindow( this, annotation );

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

    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 )
565
        {
566 567 568 569
            delete *it;
            d->m_annowindows.erase( it );

            return;
570
        }
571
    }
572 573
}

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

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

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

594 595 596 597 598 599 600 601 602 603 604
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 );
    }

605 606 607 608
    const int viewMode = Okular::Settings::viewMode();
    if ( ( viewMode == 2 && ( (int)Okular::Settings::viewColumns() != d->setting_viewCols ) )
         || ( viewMode > 0 && ( Okular::Settings::centerFirstPageInRow() != d->setting_centerFirst ) )
       )
609
    {
610
        d->setting_viewMode = Okular::Settings::viewMode();
611
        d->setting_viewCols = Okular::Settings::viewColumns();
612
        d->setting_centerFirst = Okular::Settings::centerFirstPageInRow();
613 614 615 616 617

        slotRelayoutPages();
    }
}

618 619 620 621 622
KAction *PageView::toggleFormsAction() const
{
    return d->aToggleForms;
}

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 654 655 656 657 658
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 );
    }
}

659 660 661 662 663 664 665 666 667 668 669 670 671 672
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 ) );
    }
}

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

697
    bool haspages = !pageSet.isEmpty();
698
    bool hasformwidgets = false;
699
    // create children widgets
700
    QVector< Okular::Page * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end();
701
    for ( ; setIt != setEnd; ++setIt )
702
    {
703 704
        PageViewItem * item = new PageViewItem( *setIt );
        d->items.push_back( item );
705
#ifdef PAGEVIEW_DEBUG
706
        kDebug().nospace() << "geom for " << d->items.last()->pageNumber() << " is " << d->items.last()->geometry();
707
#endif
708 709 710 711 712 713 714 715
        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 )
            {
716 717
                w->setPageItem( item );
                w->setFormWidgetsController( d->formWidgetsController() );
718
                w->setVisibility( false );
719
                w->setCanBeFilled( d->document->isAllowed( Okular::AllowFillForms ) );
720 721 722 723
                item->formWidgets().insert( ff->name(), w );
                hasformwidgets = true;
            }
        }
724
    }
725

726
    // invalidate layout so relayout/repaint will happen on next viewport change
727
    if ( haspages )
728 729 730
        // 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
731
        // because opening a document from another document will not trigger a viewportchange