part.cpp 97.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/***************************************************************************
 *   Copyright (C) 2002 by Wilco Greven <greven@kde.org>                   *
 *   Copyright (C) 2002 by Chris Cheney <ccheney@cheney.cx>                *
 *   Copyright (C) 2002 by Malcolm Hunter <malcolm.hunter@gmx.co.uk>       *
 *   Copyright (C) 2003-2004 by Christophe Devriese                        *
 *                         <Christophe.Devriese@student.kuleuven.ac.be>    *
 *   Copyright (C) 2003 by Daniel Molkentin <molkentin@kde.org>            *
 *   Copyright (C) 2003 by Andy Goossens <andygoossens@telenet.be>         *
 *   Copyright (C) 2003 by Dirk Mueller <mueller@kde.org>                  *
 *   Copyright (C) 2003 by Laurent Montel <montel@kde.org>                 *
 *   Copyright (C) 2004 by Dominique Devriese <devriese@kde.org>           *
 *   Copyright (C) 2004 by Christoph Cullmann <crossfire@babylon2k.de>     *
 *   Copyright (C) 2004 by Henrique Pinto <stampede@coltec.ufmg.br>        *
 *   Copyright (C) 2004 by Waldo Bastian <bastian@kde.org>                 *
15
 *   Copyright (C) 2004-2008 by Albert Astals Cid <aacid@kde.org>          *
16
 *   Copyright (C) 2004 by Antti Markus <antti.markus@starman.ee>          *
17 18 19 20 21 22 23
 *                                                                         *
 *   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
24 25
#include "part.h"

26
// qt/kde includes
27
#include <qapplication.h>
28
#include <qfile.h>
29 30
#include <qlayout.h>
#include <qlabel.h>
Christian Ehrlicher's avatar
Christian Ehrlicher committed
31
#include <qtimer.h>
32 33
#include <QtGui/QPrinter>
#include <QtGui/QPrintDialog>
34
#include <QScrollBar>
35

Pino Toscano's avatar
porting  
Pino Toscano committed
36
#include <kvbox.h>
37
#include <kaboutapplicationdialog.h>
38
#include <kaction.h>
39
#include <kactioncollection.h>
Albert Astals Cid's avatar
Albert Astals Cid committed
40
#include <kdirwatch.h>
Laurent Montel's avatar
Laurent Montel committed
41
#include <kstandardaction.h>
42
#include <kpluginfactory.h>
43
#include <kfiledialog.h>
44
#include <kinputdialog.h>
Albert Astals Cid's avatar
Albert Astals Cid committed
45
#include <kmessagebox.h>
46
#include <knuminput.h>
47
#include <kio/netaccess.h>
48
#include <kmenu.h>
49 50
#include <kxmlguiclient.h>
#include <kxmlguifactory.h>
51
#include <kservicetypetrader.h>
52
#include <kstandarddirs.h>
53
#include <kstandardshortcut.h>
54
#include <ktemporaryfile.h>
Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
55
#include <ktoggleaction.h>
56
#include <ktogglefullscreenaction.h>
Piotr Szymanski's avatar
Piotr Szymanski committed
57
#include <kio/job.h>
Laurent Montel's avatar
Laurent Montel committed
58
#include <kicon.h>
59
#include <kfilterdev.h>
60
#include <kfilterbase.h>
61
#if 0
62
#include <knewstuff2/engine.h>
63
#endif
64
#include <kdeprintdialog.h>
65
#include <kprintpreview.h>
66
#include <kbookmarkmenu.h>
67 68
#include <kpassworddialog.h>
#include <kwallet.h>
69

70
// local includes
71
#include "aboutdata.h"
72
#include "extensions.h"
73 74
#include "ui/pageview.h"
#include "ui/toc.h"
75 76 77
#include "ui/searchwidget.h"
#include "ui/thumbnaillist.h"
#include "ui/side_reviews.h"
78
#include "ui/minibar.h"
79
#include "ui/embeddedfilesdialog.h"
80 81
#include "ui/propertiesdialog.h"
#include "ui/presentationwidget.h"
Albert Astals Cid's avatar
Albert Astals Cid committed
82
#include "ui/pagesizelabel.h"
83
#include "ui/bookmarklist.h"
84
#include "ui/findbar.h"
Pino Toscano's avatar
Pino Toscano committed
85
#include "ui/sidebar.h"
86
#include "ui/fileprinterpreview.h"
87
#include "ui/guiutils.h"
88
#include "conf/preferencesdialog.h"
89
#include "settings.h"
90
#include "core/action.h"
91
#include "core/annotations.h"
92
#include "core/bookmarkmanager.h"
93
#include "core/document.h"
94
#include "core/generator.h"
95
#include "core/page.h"
John Layt's avatar
John Layt committed
96
#include "core/fileprinter.h"
Christophe Devriese's avatar
Christophe Devriese committed
97

98
#include <cstdio>
99
#include <memory>
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

class FileKeeper
{
    public:
        FileKeeper()
            : m_handle( NULL )
        {
        }

        ~FileKeeper()
        {
        }

        void open( const QString & path )
        {
            if ( !m_handle )
                m_handle = std::fopen( QFile::encodeName( path ), "r" );
        }

        void close()
        {
            if ( m_handle )
            {
                int ret = std::fclose( m_handle );
                Q_UNUSED( ret )
                m_handle = NULL;
            }
        }

        KTemporaryFile* copyToTemporary() const
        {
            if ( !m_handle )
                return 0;

            KTemporaryFile * retFile = new KTemporaryFile;
            retFile->open();

            std::rewind( m_handle );
            int c = -1;
            do
            {
                c = std::fgetc( m_handle );
                if ( c == EOF )
                    break;
                if ( !retFile->putChar( (char)c ) )
                    break;
            } while ( !feof( m_handle ) );

            retFile->flush();

            return retFile;
        }

    private:
        std::FILE * m_handle;
};

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
Okular::PartFactory::PartFactory()
: KPluginFactory(okularAboutData( "okular", I18N_NOOP( "Okular" ) ))
{
}

Okular::PartFactory::~PartFactory()
{
}

QObject *Okular::PartFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString &keyword)
{
    Q_UNUSED ( keyword );

    Okular::Part *object = new Okular::Part( parentWidget, parent, args, componentData() );
    object->setReadWrite( QLatin1String(iface) == QLatin1String("KParts::ReadWritePart") );
    return object;
}

K_EXPORT_PLUGIN( Okular::PartFactory() )
176

177 178 179 180 181 182 183 184 185 186
static QAction* actionForExportFormat( const Okular::ExportFormat& format, QObject *parent = 0 )
{
    QAction *act = new QAction( format.description(), parent );
    if ( !format.icon().isNull() )
    {
        act->setIcon( format.icon() );
    }
    return act;
}

187 188
static QString compressedMimeFor( const QString& mime_to_check )
{
189 190 191
    // The compressedMimeMap is here in case you have a very old shared mime database
    // that doesn't have inheritance info for things like gzeps, etc
    // Otherwise the "is()" calls below are just good enough
192
    static QHash< QString, QString > compressedMimeMap;
193 194 195 196 197
    static bool supportBzip = false;
    static bool supportXz = false;
    const QString app_gzip( QString::fromLatin1( "application/x-gzip" ) );
    const QString app_bzip( QString::fromLatin1( "application/x-bzip" ) );
    const QString app_xz( QString::fromLatin1( "application/x-xz" ) );
198 199
    if ( compressedMimeMap.isEmpty() )
    {
200
        std::auto_ptr< KFilterBase > f;
201
        compressedMimeMap[ QString::fromLatin1( "image/x-gzeps" ) ] = app_gzip;
202
        // check we can read bzip2-compressed files
203
        f.reset( KFilterBase::findFilterByMimeType( app_bzip ) );
204 205
        if ( f.get() )
        {
206
            supportBzip = true;
207 208 209 210 211
            compressedMimeMap[ QString::fromLatin1( "application/x-bzpdf" ) ] = app_bzip;
            compressedMimeMap[ QString::fromLatin1( "application/x-bzpostscript" ) ] = app_bzip;
            compressedMimeMap[ QString::fromLatin1( "application/x-bzdvi" ) ] = app_bzip;
            compressedMimeMap[ QString::fromLatin1( "image/x-bzeps" ) ] = app_bzip;
        }
212
        // check we can read XZ-compressed files
213
        f.reset( KFilterBase::findFilterByMimeType( app_xz ) );
214 215
        if ( f.get() )
        {
216
            supportXz = true;
217
        }
218
    }
Laurent Montel's avatar
Laurent Montel committed
219 220
    QHash< QString, QString >::const_iterator it = compressedMimeMap.constFind( mime_to_check );
    if ( it != compressedMimeMap.constEnd() )
221 222
        return it.value();

223
    KMimeType::Ptr mime = KMimeType::mimeType( mime_to_check );
224 225 226 227 228 229 230 231 232
    if ( mime )
    {
        if ( mime->is( app_gzip ) )
            return app_gzip;
        else if ( supportBzip && mime->is( app_bzip ) )
            return app_bzip;
        else if ( supportXz && mime->is( app_xz ) )
            return app_xz;
    }
233

234 235 236
    return QString();
}

237
static Okular::EmbedMode detectEmbedMode( QWidget *parentWidget, QObject *parent, const QVariantList &args )
238 239 240 241 242 243
{
    Q_UNUSED( parentWidget );

    if ( parent
         && ( parent->objectName() == QLatin1String( "okular::Shell" )
              || parent->objectName() == QLatin1String( "okular/okular__Shell" ) ) )
244
        return Okular::NativeShellMode;
245

246 247
    if ( parent
         && ( QByteArray( "KHTMLPart" ) == parent->metaObject()->className() ) )
248
        return Okular::KHTMLPartMode;
249

250 251 252 253
    Q_FOREACH ( const QVariant &arg, args )
    {
        if ( arg.type() == QVariant::String )
        {
Michel Ludwig's avatar
Michel Ludwig committed
254 255
            if ( arg.toString() == QLatin1String( "Print/Preview" ) )
            {
256
                return Okular::PrintPreviewMode;
257
            }
Michel Ludwig's avatar
Michel Ludwig committed
258 259
            else if ( arg.toString() == QLatin1String( "ViewerWidget" ) )
            {
260
                return Okular::ViewerWidgetMode;
261
            }
262 263 264
        }
    }

265
    return Okular::UnknownEmbedMode;
266 267
}

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
static QString detectConfigFileName( const QVariantList &args )
{
    Q_FOREACH ( const QVariant &arg, args )
    {
        if ( arg.type() == QVariant::String )
        {
            QString argString = arg.toString();
            int separatorIndex = argString.indexOf( "=" );
            if ( separatorIndex >= 0 && argString.left( separatorIndex ) == QLatin1String( "ConfigFileName" ) )
            {
                return argString.mid( separatorIndex + 1 );
            }
        }
    }

Michel Ludwig's avatar
Michel Ludwig committed
283
    return QString();
284 285
}

286 287 288 289 290 291 292 293 294 295
#undef OKULAR_KEEP_FILE_OPEN

#ifdef OKULAR_KEEP_FILE_OPEN
static bool keepFileOpen()
{
    static bool keep_file_open = !qgetenv("OKULAR_NO_KEEP_FILE_OPEN").toInt();
    return keep_file_open;
}
#endif

296 297
int Okular::Part::numberOfParts = 0;

298 299 300
namespace Okular
{

Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
301
Part::Part(QWidget *parentWidget,
302
QObject *parent,
303 304 305
const QVariantList &args,
KComponentData componentData )
: KParts::ReadWritePart(parent),
306
m_tempfile( 0 ), m_fileWasRemoved( false ), m_showMenuBarAction( 0 ), m_showFullScreenAction( 0 ), m_actionsSearched( false ),
307
m_cliPresentation(false), m_cliPrint(false), m_embedMode(detectEmbedMode(parentWidget, parent, args)), m_generatorGuiClient(0), m_keeper( 0 )
308
{
309 310
    // first, we check if a config file name has been specified
    QString configFileName = detectConfigFileName( args );
Michel Ludwig's avatar
Michel Ludwig committed
311
    if ( configFileName.isEmpty() )
312
    {
313 314 315 316 317 318 319 320
        configFileName = KStandardDirs::locateLocal( "config", "okularpartrc" );
        // first necessary step: copy the configuration from kpdf, if available
        if ( !QFile::exists( configFileName ) )
        {
            QString oldkpdfconffile = KStandardDirs::locateLocal( "config", "kpdfpartrc" );
            if ( QFile::exists( oldkpdfconffile ) )
                QFile::copy( oldkpdfconffile, configFileName );
        }
321
    }
322
    Okular::Settings::instance( configFileName );
323 324 325 326 327 328 329
    
    numberOfParts++;
    if (numberOfParts == 1) {
        QDBusConnection::sessionBus().registerObject("/okular", this, QDBusConnection::ExportScriptableSlots);
    } else {
        QDBusConnection::sessionBus().registerObject(QString("/okular%1").arg(numberOfParts), this, QDBusConnection::ExportScriptableSlots);
    }
330

331 332
    // connect the started signal to tell the job the mimetypes we like,
    // and get some more information from it
Laurent Montel's avatar
Laurent Montel committed
333
    connect(this, SIGNAL(started(KIO::Job*)), this, SLOT(slotJobStarted(KIO::Job*)));
334 335 336

    // connect the completed signal so we can put the window caption when loading remote files
    connect(this, SIGNAL(completed()), this, SLOT(setWindowTitleFromDocument()));
Laurent Montel's avatar
Laurent Montel committed
337
    connect(this, SIGNAL(canceled(QString)), this, SLOT(loadCancelled(QString)));
338

339 340
    // create browser extension (for printing when embedded into browser)
    m_bExtension = new BrowserExtension(this);
341 342
    // create live connect extension (for integrating with browser scripting)
    new OkularLiveConnectExtension( this );
343 344

    // we need an instance
345
    setComponentData( componentData );
346

347
    GuiUtils::addIconLoader( iconLoader() );
348

349 350
    m_sidebar = new Sidebar( parentWidget );
    setWidget( m_sidebar );
351
    connect( m_sidebar, SIGNAL(urlsDropped(KUrl::List)), SLOT(handleDroppedUrls(KUrl::List)) );
Pino Toscano's avatar
Pino Toscano committed
352

353
    // build the document
354
    m_document = new Okular::Document(widget());
Laurent Montel's avatar
Laurent Montel committed
355 356 357 358 359 360 361
    connect( m_document, SIGNAL(linkFind()), this, SLOT(slotFind()) );
    connect( m_document, SIGNAL(linkGoToPage()), this, SLOT(slotGoToPage()) );
    connect( m_document, SIGNAL(linkPresentation()), this, SLOT(slotShowPresentation()) );
    connect( m_document, SIGNAL(linkEndPresentation()), this, SLOT(slotHidePresentation()) );
    connect( m_document, SIGNAL(openUrl(KUrl)), this, SLOT(openUrlFromDocument(KUrl)) );
    connect( m_document->bookmarkManager(), SIGNAL(openUrl(KUrl)), this, SLOT(openUrlFromBookmarks(KUrl)) );
    connect( m_document, SIGNAL(close()), this, SLOT(close()) );
362

Pino Toscano's avatar
Pino Toscano committed
363
    if ( parent && parent->metaObject()->indexOfSlot( QMetaObject::normalizedSignature( "slotQuit()" ) ) != -1 )
Laurent Montel's avatar
Laurent Montel committed
364
        connect( m_document, SIGNAL(quit()), parent, SLOT(slotQuit()) );
365
    else
Laurent Montel's avatar
Laurent Montel committed
366
        connect( m_document, SIGNAL(quit()), this, SLOT(cannotQuit()) );
367 368 369 370 371 372 373 374 375 376
    // widgets: ^searchbar (toolbar containing label and SearchWidget)
    //      m_searchToolBar = new KToolBar( parentWidget, "searchBar" );
    //      m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() );
    //      QLabel * sLabel = new QLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" );
    //      m_searchWidget = new SearchWidget( m_searchToolBar, m_document );
    //      sLabel->setBuddy( m_searchWidget );
    //      m_searchToolBar->setStretchableWidget( m_searchWidget );

    int tbIndex;
    // [left toolbox: Table of Contents] | []
Pino Toscano's avatar
Pino Toscano committed
377
    m_toc = new TOC( 0, m_document );
Laurent Montel's avatar
Laurent Montel committed
378
    connect( m_toc, SIGNAL(hasTOC(bool)), this, SLOT(enableTOC(bool)) );
379
    tbIndex = m_sidebar->addItem( m_toc, KIcon(QApplication::isLeftToRight() ? "format-justify-left" : "format-justify-right"), i18n("Contents") );
380 381 382
    enableTOC( false );

    // [left toolbox: Thumbnails and Bookmarks] | []
Pino Toscano's avatar
Pino Toscano committed
383
    KVBox * thumbsBox = new ThumbnailsBox( 0 );
384
    thumbsBox->setSpacing( 6 );
385 386 387
    m_searchWidget = new SearchWidget( thumbsBox, m_document );
    m_thumbnailList = new ThumbnailList( thumbsBox, m_document );
    //	ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList );
Laurent Montel's avatar
Laurent Montel committed
388
    connect( m_thumbnailList, SIGNAL(rightClick(const Okular::Page*,QPoint)), this, SLOT(slotShowMenu(const Okular::Page*,QPoint)) );
Pino Toscano's avatar
Pino Toscano committed
389
    tbIndex = m_sidebar->addItem( thumbsBox, KIcon( "view-preview" ), i18n("Thumbnails") );
Pino Toscano's avatar
Pino Toscano committed
390
    m_sidebar->setCurrentIndex( tbIndex );
391 392

    // [left toolbox: Reviews] | []
393 394
    m_reviewsWidget = new Reviews( 0, m_document );
    m_sidebar->addItem( m_reviewsWidget, KIcon("draw-freehand"), i18n("Reviews") );
395
    m_sidebar->setItemEnabled( 2, false );
396 397

    // [left toolbox: Bookmarks] | []
398 399
    m_bookmarkList = new BookmarkList( m_document, 0 );
    m_sidebar->addItem( m_bookmarkList, KIcon("bookmarks"), i18n("Bookmarks") );
400
    m_sidebar->setItemEnabled( 3, false );
401 402

    // widgets: [../miniBarContainer] | []
403
#ifdef OKULAR_ENABLE_MINIBAR
Pino Toscano's avatar
Pino Toscano committed
404 405
    QWidget * miniBarContainer = new QWidget( 0 );
    m_sidebar->setBottomWidget( miniBarContainer );
406 407 408 409 410 411 412 413 414 415 416 417 418
    QVBoxLayout * miniBarLayout = new QVBoxLayout( miniBarContainer );
    miniBarLayout->setMargin( 0 );
    // widgets: [../[spacer/..]] | []
    miniBarLayout->addItem( new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
    // widgets: [../[../MiniBar]] | []
    QFrame * bevelContainer = new QFrame( miniBarContainer );
    bevelContainer->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
    QVBoxLayout * bevelContainerLayout = new QVBoxLayout( bevelContainer );
    bevelContainerLayout->setMargin( 4 );
    m_progressWidget = new ProgressWidget( bevelContainer, m_document );
    bevelContainerLayout->addWidget( m_progressWidget );
    miniBarLayout->addWidget( bevelContainer );
    miniBarLayout->addItem( new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
419
#endif
420 421

    // widgets: [] | [right 'pageView']
Pino Toscano's avatar
Pino Toscano committed
422 423
    QWidget * rightContainer = new QWidget( 0 );
    m_sidebar->setMainWidget( rightContainer );
424 425 426 427 428
    QVBoxLayout * rightLayout = new QVBoxLayout( rightContainer );
    rightLayout->setMargin( 0 );
    rightLayout->setSpacing( 0 );
    //	KToolBar * rtb = new KToolBar( rightContainer, "mainToolBarSS" );
    //	rightLayout->addWidget( rtb );
429 430 431 432 433 434 435
    m_topMessage = new KMessageWidget( rightContainer );
    m_topMessage->setVisible( false );
    m_topMessage->setWordWrap( true );
    m_topMessage->setMessageType( KMessageWidget::Information );
    m_topMessage->setText( i18n( "This document has embedded files. <a href=\"okular:/embeddedfiles\">Click here to see them</a> or go to File -> Embedded Files." ) );
    m_topMessage->setIcon( KIcon( "mail-attachment" ) );
    connect( m_topMessage, SIGNAL(linkActivated(QString)), this, SLOT(slotShowEmbeddedFiles()) );
436
    rightLayout->addWidget( m_topMessage );
437 438 439 440
    m_formsMessage = new KMessageWidget( rightContainer );
    m_formsMessage->setVisible( false );
    m_formsMessage->setWordWrap( true );
    m_formsMessage->setMessageType( KMessageWidget::Information );
441
    rightLayout->addWidget( m_formsMessage );
442 443 444 445 446 447 448 449
    m_infoMessage = new KMessageWidget( rightContainer );
    m_infoMessage->setVisible( false );
    m_infoMessage->setWordWrap( true );
    m_infoMessage->setMessageType( KMessageWidget::Information );
    rightLayout->addWidget( m_infoMessage );
    m_infoTimer = new QTimer();
    m_infoTimer->setSingleShot( true );
    connect( m_infoTimer, SIGNAL(timeout()), m_infoMessage, SLOT(animatedHide()) );
450
    m_pageView = new PageView( rightContainer, m_document );
451
    QMetaObject::invokeMethod( m_pageView, "setFocus", Qt::QueuedConnection );      //usability setting
Pino Toscano's avatar
Pino Toscano committed
452
//    m_splitter->setFocusProxy(m_pageView);
Laurent Montel's avatar
Laurent Montel committed
453
    connect( m_pageView, SIGNAL(rightClick(const Okular::Page*,QPoint)), this, SLOT(slotShowMenu(const Okular::Page*,QPoint)) );
454 455 456
    connect( m_document, SIGNAL(error(QString,int)), this, SLOT(errorMessage(QString,int)) );
    connect( m_document, SIGNAL(warning(QString,int)), this, SLOT(warningMessage(QString,int)) );
    connect( m_document, SIGNAL(notice(QString,int)), this, SLOT(noticeMessage(QString,int)) );
Michel Ludwig's avatar
Michel Ludwig committed
457
    connect( m_document, SIGNAL(sourceReferenceActivated(const QString&,int,int,bool*)), this, SLOT(slotHandleActivatedSourceReference(const QString&,int,int,bool*)) );
458
    rightLayout->addWidget( m_pageView );
459 460
    m_findBar = new FindBar( m_document, rightContainer );
    rightLayout->addWidget( m_findBar );
461 462 463
    m_bottomBar = new QWidget( rightContainer );
    QHBoxLayout * bottomBarLayout = new QHBoxLayout( m_bottomBar );
    m_pageSizeLabel = new PageSizeLabel( m_bottomBar, m_document );
464 465 466
    bottomBarLayout->setMargin( 0 );
    bottomBarLayout->setSpacing( 0 );
    bottomBarLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Expanding, QSizePolicy::Minimum ) );
Albert Astals Cid's avatar
Albert Astals Cid committed
467 468
    m_miniBarLogic = new MiniBarLogic( this, m_document );
    m_miniBar = new MiniBar( m_bottomBar, m_miniBarLogic );
469 470
    bottomBarLayout->addWidget( m_miniBar );
    bottomBarLayout->addWidget( m_pageSizeLabel );
471
    rightLayout->addWidget( m_bottomBar );
472

Albert Astals Cid's avatar
Albert Astals Cid committed
473
    m_pageNumberTool = new MiniBar( 0, m_miniBarLogic );
474

Laurent Montel's avatar
Laurent Montel committed
475
    connect( m_findBar, SIGNAL(forwardKeyPressEvent(QKeyEvent*)), m_pageView, SLOT(externalKeyPressEvent(QKeyEvent*)));
476
    connect( m_findBar, SIGNAL(onCloseButtonPressed()), m_pageView, SLOT(setFocus()));
Laurent Montel's avatar
Laurent Montel committed
477
    connect( m_miniBar, SIGNAL(forwardKeyPressEvent(QKeyEvent*)), m_pageView, SLOT(externalKeyPressEvent(QKeyEvent*)));
478
    connect( m_pageView, SIGNAL(escPressed()), m_findBar, SLOT(resetSearch()) );
479
    connect( m_pageNumberTool, SIGNAL(forwardKeyPressEvent(QKeyEvent*)), m_pageView, SLOT(externalKeyPressEvent(QKeyEvent*)));
480

481 482
    connect( m_reviewsWidget, SIGNAL(openAnnotationWindow(Okular::Annotation*,int)),
        m_pageView, SLOT(openAnnotationWindow(Okular::Annotation*,int)) );
483 484 485 486 487

    // add document observers
    m_document->addObserver( this );
    m_document->addObserver( m_thumbnailList );
    m_document->addObserver( m_pageView );
488
    m_document->registerView( m_pageView );
489
    m_document->addObserver( m_toc );
Albert Astals Cid's avatar
Albert Astals Cid committed
490
    m_document->addObserver( m_miniBarLogic );
491
#ifdef OKULAR_ENABLE_MINIBAR
492
    m_document->addObserver( m_progressWidget );
493
#endif
494
    m_document->addObserver( m_reviewsWidget );
495
    m_document->addObserver( m_pageSizeLabel );
496
    m_document->addObserver( m_bookmarkList );
497

Laurent Montel's avatar
Laurent Montel committed
498 499
    connect( m_document->bookmarkManager(), SIGNAL(saved()),
        this, SLOT(slotRebuildBookmarkMenu()) );
500

501 502 503 504 505 506
    setupViewerActions();

    if ( m_embedMode != ViewerWidgetMode )
    {
        setupActions();
    }
507 508 509 510
    else
    {
        setViewerShortcuts();
    }
511 512 513 514 515 516 517 518 519 520

    // document watcher and reloader
    m_watcher = new KDirWatch( this );
    connect( m_watcher, SIGNAL(dirty(QString)), this, SLOT(slotFileDirty(QString)) );
    m_dirtyHandler = new QTimer( this );
    m_dirtyHandler->setSingleShot( true );
    connect( m_dirtyHandler, SIGNAL(timeout()),this, SLOT(slotDoFileDirty()) );

    slotNewConfig();

521 522 523
    // keep us informed when the user changes settings
    connect( Okular::Settings::self(), SIGNAL(configChanged()), this, SLOT(slotNewConfig()) );

524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
    // [SPEECH] check for KTTSD presence and usability
    const KService::Ptr kttsd = KService::serviceByDesktopName("kttsd");
    Okular::Settings::setUseKTTSD( kttsd );
    Okular::Settings::self()->writeConfig();

    rebuildBookmarkMenu( false );

    if ( m_embedMode == ViewerWidgetMode ) {
        // set the XML-UI resource file for the viewer mode
        setXMLFile("part-viewermode.rc");
    }
    else
    {
        // set our main XML-UI resource file
        setXMLFile("part.rc");
    }

    m_pageView->setupBaseActions( actionCollection() );

    m_sidebar->setSidebarVisibility( false );
    if ( m_embedMode != PrintPreviewMode )
    {
        // now set up actions that are required for all remaining modes
        m_pageView->setupViewerActions( actionCollection() );
        // and if we are not in viewer mode, we want the full GUI
        if ( m_embedMode != ViewerWidgetMode )
        {
            unsetDummyMode();
        }
    }

    // ensure history actions are in the correct state
    updateViewActions();

558 559
    // also update the state of the actions in the page view
    m_pageView->updateActionState( false, false, false );
560 561 562 563 564 565 566 567 568 569 570

    if ( m_embedMode == NativeShellMode )
        m_sidebar->setAutoFillBackground( false );

#ifdef OKULAR_KEEP_FILE_OPEN
    m_keeper = new FileKeeper();
#endif
}

void Part::setupViewerActions()
{
571 572 573 574
    // ACTIONS
    KActionCollection * ac = actionCollection();

    // Page Traversal actions
Laurent Montel's avatar
Laurent Montel committed
575
    m_gotoPage = KStandardAction::gotoPage( this, SLOT(slotGoToPage()), ac );
576
    m_gotoPage->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_G) );
577
    // dirty way to activate gotopage when pressing miniBar's button
Laurent Montel's avatar
Laurent Montel committed
578
    connect( m_miniBar, SIGNAL(gotoPage()), m_gotoPage, SLOT(trigger()) );
579
    connect( m_pageNumberTool, SIGNAL(gotoPage()), m_gotoPage, SLOT(trigger()) );
580 581

    m_prevPage = KStandardAction::prior(this, SLOT(slotPreviousPage()), ac);
Pino Toscano's avatar
Pino Toscano committed
582 583
    m_prevPage->setIconText( i18nc( "Previous page", "Previous" ) );
    m_prevPage->setToolTip( i18n( "Go back to the Previous Page" ) );
584 585 586
    m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );
    m_prevPage->setShortcut( 0 );
    // dirty way to activate prev page when pressing miniBar's button
Laurent Montel's avatar
Laurent Montel committed
587
    connect( m_miniBar, SIGNAL(prevPage()), m_prevPage, SLOT(trigger()) );
588
    connect( m_pageNumberTool, SIGNAL(prevPage()), m_prevPage, SLOT(trigger()) );
589
#ifdef OKULAR_ENABLE_MINIBAR
Laurent Montel's avatar
Laurent Montel committed
590
    connect( m_progressWidget, SIGNAL(prevPage()), m_prevPage, SLOT(trigger()) );
591
#endif
592 593

    m_nextPage = KStandardAction::next(this, SLOT(slotNextPage()), ac );
Pino Toscano's avatar
Pino Toscano committed
594 595
    m_nextPage->setIconText( i18nc( "Next page", "Next" ) );
    m_nextPage->setToolTip( i18n( "Advance to the Next Page" ) );
596 597 598
    m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );
    m_nextPage->setShortcut( 0 );
    // dirty way to activate next page when pressing miniBar's button
Laurent Montel's avatar
Laurent Montel committed
599
    connect( m_miniBar, SIGNAL(nextPage()), m_nextPage, SLOT(trigger()) );
600
    connect( m_pageNumberTool, SIGNAL(nextPage()), m_nextPage, SLOT(trigger()) );
601
#ifdef OKULAR_ENABLE_MINIBAR
Laurent Montel's avatar
Laurent Montel committed
602
    connect( m_progressWidget, SIGNAL(nextPage()), m_nextPage, SLOT(trigger()) );
603
#endif
604

Laurent Montel's avatar
Laurent Montel committed
605
    m_beginningOfDocument = KStandardAction::firstPage( this, SLOT(slotGotoFirst()), ac );
606 607 608
    ac->addAction("first_page", m_beginningOfDocument);
    m_beginningOfDocument->setText(i18n( "Beginning of the document"));
    m_beginningOfDocument->setWhatsThis( i18n( "Moves to the beginning of the document" ) );
609

Laurent Montel's avatar
Laurent Montel committed
610
    m_endOfDocument = KStandardAction::lastPage( this, SLOT(slotGotoLast()), ac );
611 612 613
    ac->addAction("last_page",m_endOfDocument);
    m_endOfDocument->setText(i18n( "End of the document"));
    m_endOfDocument->setWhatsThis( i18n( "Moves to the end of the document" ) );
614

Albert Astals Cid's avatar
Albert Astals Cid committed
615 616 617
    // we do not want back and next in history in the dummy mode
    m_historyBack = 0;
    m_historyNext = 0;
618

Laurent Montel's avatar
Laurent Montel committed
619
    m_addBookmark = KStandardAction::addBookmark( this, SLOT(slotAddBookmark()), ac );
620
    m_addBookmarkText = m_addBookmark->text();
621
    m_addBookmarkIcon = m_addBookmark->icon();
622

623 624 625
    m_renameBookmark = ac->addAction("rename_bookmark");
    m_renameBookmark->setText(i18n( "Rename Bookmark" ));
    m_renameBookmark->setIcon(KIcon( "edit-rename" ));
626 627
    m_renameBookmark->setWhatsThis( i18n( "Rename the current bookmark" ) );
    connect( m_renameBookmark, SIGNAL(triggered()), this, SLOT(slotRenameCurrentViewportBookmark()) );
628

629 630
    m_prevBookmark = ac->addAction("previous_bookmark");
    m_prevBookmark->setText(i18n( "Previous Bookmark" ));
631
    m_prevBookmark->setIcon(KIcon( "go-up-search" ));
632
    m_prevBookmark->setWhatsThis( i18n( "Go to the previous bookmark" ) );
Laurent Montel's avatar
Laurent Montel committed
633
    connect( m_prevBookmark, SIGNAL(triggered()), this, SLOT(slotPreviousBookmark()) );
634 635 636

    m_nextBookmark = ac->addAction("next_bookmark");
    m_nextBookmark->setText(i18n( "Next Bookmark" ));
637
    m_nextBookmark->setIcon(KIcon( "go-down-search" ));
638
    m_nextBookmark->setWhatsThis( i18n( "Go to the next bookmark" ) );
Laurent Montel's avatar
Laurent Montel committed
639
    connect( m_nextBookmark, SIGNAL(triggered()), this, SLOT(slotNextBookmark()) );
640

Michel Ludwig's avatar
Michel Ludwig committed
641
    m_copy = 0;
642

Michel Ludwig's avatar
Michel Ludwig committed
643
    m_selectAll = 0;
644

645
    // Find and other actions
Laurent Montel's avatar
Laurent Montel committed
646
    m_find = KStandardAction::find( this, SLOT(slotShowFindBar()), ac );
647 648 649
    QList<QKeySequence> s = m_find->shortcuts();
    s.append( QKeySequence( Qt::Key_Slash ) );
    m_find->setShortcuts( s );
650 651
    m_find->setEnabled( false );

Laurent Montel's avatar
Laurent Montel committed
652
    m_findNext = KStandardAction::findNext( this, SLOT(slotFindNext()), ac);
653 654
    m_findNext->setEnabled( false );

Laurent Montel's avatar
Laurent Montel committed
655
    m_findPrev = KStandardAction::findPrev( this, SLOT(slotFindPrev()), ac );
Pino Toscano's avatar
Pino Toscano committed
656 657
    m_findPrev->setEnabled( false );

Michel Ludwig's avatar
Michel Ludwig committed
658 659
    m_saveCopyAs = 0;
    m_saveAs = 0;
Pino Toscano's avatar
Pino Toscano committed
660

Laurent Montel's avatar
Laurent Montel committed
661
    QAction * prefs = KStandardAction::preferences( this, SLOT(slotPreferences()), ac);
662
    if ( m_embedMode == NativeShellMode )
663
    {
Pino Toscano's avatar
Pino Toscano committed
664
        prefs->setText( i18n( "Configure Okular..." ) );
665 666 667
    }
    else
    {
Pino Toscano's avatar
Pino Toscano committed
668
        // TODO: improve this message
669 670 671
        prefs->setText( i18n( "Configure Viewer..." ) );
    }

Pino Toscano's avatar
Pino Toscano committed
672 673
    KAction * genPrefs = new KAction( ac );
    ac->addAction("options_configure_generators", genPrefs);
674 675 676 677
    if ( m_embedMode == ViewerWidgetMode )
    {
        genPrefs->setText( i18n( "Configure Viewer Backends..." ) );
    }
Michel Ludwig's avatar
Michel Ludwig committed
678 679
    else
    {
680 681
        genPrefs->setText( i18n( "Configure Backends..." ) );
    }
Pino Toscano's avatar
Pino Toscano committed
682
    genPrefs->setIcon( KIcon( "configure" ) );
683
    genPrefs->setEnabled( m_document->configurableGenerators() > 0 );
Laurent Montel's avatar
Laurent Montel committed
684
    connect( genPrefs, SIGNAL(triggered(bool)), this, SLOT(slotGeneratorPreferences()) );
685

Laurent Montel's avatar
Laurent Montel committed
686
    m_printPreview = KStandardAction::printPreview( this, SLOT(slotPrintPreview()), ac );
687 688
    m_printPreview->setEnabled( false );

Michel Ludwig's avatar
Michel Ludwig committed
689 690
    m_showLeftPanel = 0;
    m_showBottomBar = 0;
691 692 693 694 695 696 697

    m_showProperties = ac->addAction("properties");
    m_showProperties->setText(i18n("&Properties"));
    m_showProperties->setIcon(KIcon("document-properties"));
    connect(m_showProperties, SIGNAL(triggered()), this, SLOT(slotShowProperties()));
    m_showProperties->setEnabled( false );

Michel Ludwig's avatar
Michel Ludwig committed
698 699
    m_showEmbeddedFiles = 0;
    m_showPresentation = 0;
700

Michel Ludwig's avatar
Michel Ludwig committed
701 702 703 704
    m_exportAs = 0;
    m_exportAsMenu = 0;
    m_exportAsText = 0;
    m_exportAsDocArchive = 0;
705 706 707 708 709 710 711 712 713 714 715

    m_aboutBackend = ac->addAction("help_about_backend");
    m_aboutBackend->setText(i18n("About Backend"));
    m_aboutBackend->setEnabled( false );
    connect(m_aboutBackend, SIGNAL(triggered()), this, SLOT(slotAboutBackend()));

    KAction *reload = ac->add<KAction>( "file_reload" );
    reload->setText( i18n( "Reloa&d" ) );
    reload->setIcon( KIcon( "view-refresh" ) );
    reload->setWhatsThis( i18n( "Reload the current document from disk." ) );
    connect( reload, SIGNAL(triggered()), this, SLOT(slotReload()) );
716
    reload->setShortcut( KStandardShortcut::reload() );
717 718
    m_reload = reload;

Jonathan Doman's avatar
Jonathan Doman committed
719 720 721 722
    m_closeFindBar = ac->addAction( "close_find_bar", this, SLOT(slotHideFindBar()) );
    m_closeFindBar->setText( i18n("Close &Find Bar") );
    m_closeFindBar->setShortcut( QKeySequence(Qt::Key_Escape) );
    m_closeFindBar->setEnabled( false );
723 724 725 726

    KAction *pageno = new KAction( i18n( "Page Number" ), ac );
    pageno->setDefaultWidget( m_pageNumberTool );
    ac->addAction( "page_number", pageno );
727 728
}

729
void Part::setViewerShortcuts()
730 731 732
{
    KActionCollection * ac = actionCollection();

733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
    m_gotoPage->setShortcut( QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_G) );
    m_find->setShortcuts( QList<QKeySequence>() );

    m_findNext->setShortcut( QKeySequence() );
    m_findPrev->setShortcut( QKeySequence() );

    m_addBookmark->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_B ) );

    m_beginningOfDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_Home ) );
    m_endOfDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_End ) );

    KAction *action = static_cast<KAction*>( ac->action( "file_reload" ) );
    if( action )  action->setShortcuts( QList<QKeySequence>() << QKeySequence( Qt::ALT + Qt::Key_F5 ) );
}

void Part::setupActions()
{
    KActionCollection * ac = actionCollection();
751 752 753 754 755 756 757

    m_copy = KStandardAction::create( KStandardAction::Copy, m_pageView, SLOT(copyTextSelection()), ac );

    m_selectAll = KStandardAction::selectAll( m_pageView, SLOT(selectAll()), ac );

    m_saveCopyAs = KStandardAction::saveAs( this, SLOT(slotSaveCopyAs()), ac );
    m_saveCopyAs->setText( i18n( "Save &Copy As..." ) );
758
    m_saveCopyAs->setShortcut( KShortcut() );
759 760 761 762 763 764
    ac->addAction( "file_save_copy", m_saveCopyAs );
    m_saveCopyAs->setEnabled( false );

    m_saveAs = KStandardAction::saveAs( this, SLOT(slotSaveFileAs()), ac );
    m_saveAs->setEnabled( false );

765 766
    m_showLeftPanel = ac->add<KToggleAction>("show_leftpanel");
    m_showLeftPanel->setText(i18n( "Show &Navigation Panel"));
767
    m_showLeftPanel->setIcon(KIcon( "view-sidetree" ));
Laurent Montel's avatar
Laurent Montel committed
768
    connect( m_showLeftPanel, SIGNAL(toggled(bool)), this, SLOT(slotShowLeftPanel()) );
769
    m_showLeftPanel->setShortcut( Qt::Key_F7 );
770 771 772
    m_showLeftPanel->setChecked( Okular::Settings::showLeftPanel() );
    slotShowLeftPanel();

773 774
    m_showBottomBar = ac->add<KToggleAction>("show_bottombar");
    m_showBottomBar->setText(i18n( "Show &Page Bar"));
Laurent Montel's avatar
Laurent Montel committed
775
    connect( m_showBottomBar, SIGNAL(toggled(bool)), this, SLOT(slotShowBottomBar()) );
776 777 778
    m_showBottomBar->setChecked( Okular::Settings::showBottomBar() );
    slotShowBottomBar();

779 780
    m_showEmbeddedFiles = ac->addAction("embedded_files");
    m_showEmbeddedFiles->setText(i18n("&Embedded Files"));
Pino Toscano's avatar
Pino Toscano committed
781
    m_showEmbeddedFiles->setIcon( KIcon( "mail-attachment" ) );
782 783 784 785 786
    connect(m_showEmbeddedFiles, SIGNAL(triggered()), this, SLOT(slotShowEmbeddedFiles()));
    m_showEmbeddedFiles->setEnabled( false );

    m_exportAs = ac->addAction("file_export_as");
    m_exportAs->setText(i18n("E&xport As"));
Pino Toscano's avatar
Pino Toscano committed
787
    m_exportAs->setIcon( KIcon( "document-export" ) );
788
    m_exportAsMenu = new QMenu();
Laurent Montel's avatar
Laurent Montel committed
789
    connect(m_exportAsMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotExportAs(QAction*)));
790 791 792
    m_exportAs->setMenu( m_exportAsMenu );
    m_exportAsText = actionForExportFormat( Okular::ExportFormat::standardFormat( Okular::ExportFormat::PlainText ), m_exportAsMenu );
    m_exportAsMenu->addAction( m_exportAsText );
793
    m_exportAs->setEnabled( false );
794
    m_exportAsText->setEnabled( false );
795 796 797 798 799
    m_exportAsDocArchive = actionForExportFormat( Okular::ExportFormat(
            i18nc( "A document format, Okular-specific", "Document Archive" ),
            KMimeType::mimeType( "application/vnd.kde.okular-archive" ) ), m_exportAsMenu );
    m_exportAsMenu->addAction( m_exportAsDocArchive );
    m_exportAsDocArchive->setEnabled( false );
800

801 802 803 804 805 806
    m_showPresentation = ac->addAction("presentation");
    m_showPresentation->setText(i18n("P&resentation"));
    m_showPresentation->setIcon( KIcon( "view-presentation" ) );
    connect(m_showPresentation, SIGNAL(triggered()), this, SLOT(slotShowPresentation()));
    m_showPresentation->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_P ) );
    m_showPresentation->setEnabled( false );
807

808 809 810 811 812 813 814 815 816 817 818 819
    QAction * importPS = ac->addAction("import_ps");
    importPS->setText(i18n("&Import PostScript as PDF..."));
    importPS->setIcon(KIcon("document-import"));
    connect(importPS, SIGNAL(triggered()), this, SLOT(slotImportPSFile()));
#if 0
    QAction * ghns = ac->addAction("get_new_stuff");
    ghns->setText(i18n("&Get Books From Internet..."));
    ghns->setIcon(KIcon("get-hot-new-stuff"));
    connect(ghns, SIGNAL(triggered()), this, SLOT(slotGetNewStuff()));
    // TEMP, REMOVE ME!
    ghns->setShortcut( Qt::Key_G );
#endif
820

821 822 823 824
    KToggleAction *blackscreenAction = new KToggleAction( i18n( "Switch Blackscreen Mode" ), ac );
    ac->addAction( "switch_blackscreen_mode", blackscreenAction );
    blackscreenAction->setShortcut( QKeySequence( Qt::Key_B ) );
    blackscreenAction->setIcon( KIcon( "view-presentation" ) );
825
    blackscreenAction->setEnabled( false );
826

827 828 829
    KToggleAction *drawingAction = new KToggleAction( i18n( "Toggle Drawing Mode" ), ac );
    ac->addAction( "presentation_drawing_mode", drawingAction );
    drawingAction->setIcon( KIcon( "draw-freehand" ) );
830
    drawingAction->setEnabled( false );
831 832 833 834

    KAction *eraseDrawingAction = new KAction( i18n( "Erase Drawings" ), ac );
    ac->addAction( "presentation_erase_drawings", eraseDrawingAction );
    eraseDrawingAction->setIcon( KIcon( "draw-eraser" ) );
835
    eraseDrawingAction->setEnabled( false );
836 837 838 839 840

    KAction *configureAnnotations = new KAction( i18n( "Configure Annotations..." ), ac );
    ac->addAction( "options_configure_annotations", configureAnnotations );
    configureAnnotations->setIcon( KIcon( "configure" ) );
    connect(configureAnnotations, SIGNAL(triggered()), this, SLOT(slotAnnotationPreferences()));
841 842

    KAction *playPauseAction = new KAction( i18n( "Play/Pause Presentation" ), ac );
843 844
    ac->addAction( "presentation_play_pause", playPauseAction );
    playPauseAction->setEnabled( false );
845 846
}

847
Part::~Part()
Laurent Montel's avatar
Laurent Montel committed
848
{
849
    GuiUtils::removeIconLoader( iconLoader() );
850 851
    m_document->removeObserver( this );

852
    if ( m_document->isOpened() )
853
        Part::closeUrl( false );
854

Albert Astals Cid's avatar
Albert Astals Cid committed
855 856 857 858
    delete m_toc;
    delete m_pageView;
    delete m_thumbnailList;
    delete m_miniBar;