part.cpp 60 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>                 *
Albert Astals Cid's avatar
Albert Astals Cid committed
15
 *   Copyright (C) 2004-2007 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 29 30
#include <qsplitter.h>
#include <qlayout.h>
#include <qlabel.h>
Pino Toscano's avatar
porting  
Pino Toscano committed
31
#include <kvbox.h>
32
#include <qtoolbox.h>
33
#include <kaboutapplicationdialog.h>
34
#include <kaction.h>
35
#include <kactioncollection.h>
Albert Astals Cid's avatar
Albert Astals Cid committed
36
#include <kdirwatch.h>
37
#include <kprinter.h>
Laurent Montel's avatar
Laurent Montel committed
38
#include <kstandardaction.h>
39
#include <kparts/genericfactory.h>
40
#include <kfiledialog.h>
Albert Astals Cid's avatar
Albert Astals Cid committed
41
#include <kmessagebox.h>
42
#include <knuminput.h>
43
#include <kio/netaccess.h>
44
#include <kmenu.h>
45 46
#include <kxmlguiclient.h>
#include <kxmlguifactory.h>
47
#include <kservicetypetrader.h>
48
#include <kstandarddirs.h>
49
#include <kstandardshortcut.h>
50
#include <ktemporaryfile.h>
Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
51
#include <ktoggleaction.h>
52
#include <ktogglefullscreenaction.h>
Piotr Szymanski's avatar
Piotr Szymanski committed
53
#include <kio/job.h>
Laurent Montel's avatar
Laurent Montel committed
54
#include <kicon.h>
55
#include <kfilterdev.h>
56
#include <knewstuff2/engine.h>
57

58
// local includes
59
#include "aboutdata.h"
60 61
#include "ui/pageview.h"
#include "ui/toc.h"
62 63 64
#include "ui/searchwidget.h"
#include "ui/thumbnaillist.h"
#include "ui/side_reviews.h"
65
#include "ui/minibar.h"
66
#include "ui/embeddedfilesdialog.h"
67 68
#include "ui/propertiesdialog.h"
#include "ui/presentationwidget.h"
Albert Astals Cid's avatar
Albert Astals Cid committed
69
#include "ui/pagesizelabel.h"
70
#include "ui/bookmarklist.h"
71
#include "ui/findbar.h"
72
#include "conf/preferencesdialog.h"
73
#include "settings.h"
74
#include "core/bookmarkmanager.h"
75
#include "core/document.h"
76
#include "core/generator.h"
77
#include "core/page.h"
78
#include "interfaces/configinterface.h"
Christophe Devriese's avatar
Christophe Devriese committed
79

80
typedef KParts::GenericFactory<Part> okularPartFactory;
Albert Astals Cid's avatar
Albert Astals Cid committed
81
K_EXPORT_COMPONENT_FACTORY(libokularpart, okularPartFactory)
82

83 84 85 86 87 88 89 90 91 92
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;
}

Albert Astals Cid's avatar
compile  
Albert Astals Cid committed
93
Part::Part(QWidget *parentWidget,
94
QObject *parent,
Albert Astals Cid's avatar
Albert Astals Cid committed
95
const QStringList &args )
96 97 98
: KParts::ReadOnlyPart(parent),
m_showMenuBarAction(0), m_showFullScreenAction(0), m_actionsSearched(false),
m_searchStarted(false), m_cliPresentation(false)
99
{
100 101 102 103
    QDBusConnection::sessionBus().registerObject("/okular", this, QDBusConnection::ExportScriptableSlots);

    // connect the started signal to tell the job the mimetypes we like
    connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(setMimeTypes(KIO::Job *)));
104 105 106 107 108

    // connect the completed signal so we can put the window caption when loading remote files
    connect(this, SIGNAL(completed()), this, SLOT(setWindowTitleFromDocument()));
    connect(this, SIGNAL(canceled(const QString &)), this, SLOT(loadCancelled(const QString &)));

109 110 111 112 113 114 115 116 117
    // load catalog for translation
    KGlobal::locale()->insertCatalog("okular");

    m_tempfile= 0L;

    // create browser extension (for printing when embedded into browser)
    m_bExtension = new BrowserExtension(this);

    // we need an instance
Albert Astals Cid's avatar
Albert Astals Cid committed
118
    setComponentData(okularPartFactory::componentData());
119 120

    // build the document
121
    m_document = new Okular::Document(widget());
122 123 124 125 126
    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(const KUrl &) ), this, SLOT( openUrlFromDocument(const KUrl &) ) );
127
    connect( m_document->bookmarkManager(), SIGNAL( openUrl(const KUrl &) ), this, SLOT( openUrlFromBookmarks(const KUrl &) ) );
128 129
    connect( m_document, SIGNAL( close() ), this, SLOT( close() ) );

Pino Toscano's avatar
Pino Toscano committed
130
    if ( parent && parent->metaObject()->indexOfSlot( QMetaObject::normalizedSignature( "slotQuit()" ) ) != -1 )
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 157 158 159 160 161 162 163
        connect( m_document, SIGNAL( quit() ), parent, SLOT( slotQuit() ) );
    else
        connect( m_document, SIGNAL( quit() ), this, SLOT( cannotQuit() ) );
    // 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 );

    // widgets: [] splitter []
    m_splitter = new QSplitter( parentWidget );
    m_splitter->setOpaqueResize( true );
    m_splitter->setChildrenCollapsible( false );
    setWidget( m_splitter );

    // widgets: [left panel] | []
    m_leftPanel = new QWidget( m_splitter );
    m_leftPanel->setMinimumWidth( 90 );
    m_leftPanel->setMaximumWidth( 300 );
    QVBoxLayout * leftPanelLayout = new QVBoxLayout( m_leftPanel );
    leftPanelLayout->setMargin( 0 );
    m_splitter->setCollapsible( 0, true );

    // widgets: [left toolbox/..] | []
    m_toolBox = new QToolBox( m_leftPanel );
    leftPanelLayout->addWidget( m_toolBox );

    int tbIndex;
    // [left toolbox: Table of Contents] | []
    m_toc = new TOC( m_toolBox, m_document );
    connect( m_toc, SIGNAL( hasTOC( bool ) ), this, SLOT( enableTOC( bool ) ) );
164
    tbIndex = m_toolBox->addItem( m_toc, KIcon(QApplication::isLeftToRight() ? "leftjust" : "format-justify-right"), i18n("Contents") );
165 166 167 168 169 170 171 172 173 174 175
    m_toolBox->setItemToolTip( tbIndex, i18n("Contents") );
    enableTOC( false );

    // [left toolbox: Thumbnails and Bookmarks] | []
    KVBox * thumbsBox = new ThumbnailsBox( m_toolBox );
    thumbsBox->setSpacing( 4 );
    m_searchWidget = new SearchWidget( thumbsBox, m_document );
    m_thumbnailList = new ThumbnailList( thumbsBox, m_document );
    //	ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList );
    connect( m_thumbnailList, SIGNAL( urlDropped( const KUrl& ) ), SLOT( openUrlFromDocument( const KUrl & )) );
    connect( m_thumbnailList, SIGNAL( rightClick(const Okular::Page *, const QPoint &) ), this, SLOT( slotShowMenu(const Okular::Page *, const QPoint &) ) );
176
    tbIndex = m_toolBox->addItem( thumbsBox, KIcon("thumbnail-show"), i18n("Thumbnails") );
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
    m_toolBox->setItemToolTip( tbIndex, i18n("Thumbnails") );
    m_toolBox->setCurrentIndex( m_toolBox->indexOf( thumbsBox ) );

    // [left toolbox: Reviews] | []
    Reviews * reviewsWidget = new Reviews( m_toolBox, m_document );
    m_toolBox->addItem( reviewsWidget, KIcon("pencil"), i18n("Reviews") );

    // [left toolbox: Bookmarks] | []
    BookmarkList * bookmarkList = new BookmarkList( m_document, m_toolBox );
    m_toolBox->addItem( bookmarkList, KIcon("bookmark"), i18n("Bookmarks") );

    // widgets: [../miniBarContainer] | []
    QWidget * miniBarContainer = new QWidget( m_leftPanel );
    leftPanelLayout->addWidget( miniBarContainer );
    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 ) );

    // widgets: [] | [right 'pageView']
    QWidget * rightContainer = new QWidget( m_splitter );
    QVBoxLayout * rightLayout = new QVBoxLayout( rightContainer );
    rightLayout->setMargin( 0 );
    rightLayout->setSpacing( 0 );
    //	KToolBar * rtb = new KToolBar( rightContainer, "mainToolBarSS" );
    //	rightLayout->addWidget( rtb );
    m_topMessage = new PageViewTopMessage( rightContainer );
213
    m_topMessage->setup( i18n( "This document has embedded files. <a href=\"okular:/embeddedfiles\">Click here to see them</a> or go to File -> Embedded Files." ), KIcon( "attach" ) );
214 215
    connect( m_topMessage, SIGNAL( action() ), this, SLOT( slotShowEmbeddedFiles() ) );
    rightLayout->addWidget( m_topMessage );
216 217 218
    m_formsMessage = new PageViewTopMessage( rightContainer );
    m_formsMessage->setup( i18n( "This document has forms. Click on the button to interact with them, or use View -> Show Forms." ) );
    rightLayout->addWidget( m_formsMessage );
219 220
    m_pageView = new PageView( rightContainer, m_document );
    m_pageView->setFocus();      //usability setting
Albert Astals Cid's avatar
Albert Astals Cid committed
221
    m_splitter->setFocusProxy(m_pageView);
222 223 224 225 226 227
    connect( m_pageView, SIGNAL( urlDropped( const KUrl& ) ), SLOT( openUrlFromDocument( const KUrl & )));
    connect( m_pageView, SIGNAL( rightClick(const Okular::Page *, const QPoint &) ), this, SLOT( slotShowMenu(const Okular::Page *, const QPoint &) ) );
    connect( m_document, SIGNAL( error( const QString&, int ) ), m_pageView, SLOT( errorMessage( const QString&, int ) ) );
    connect( m_document, SIGNAL( warning( const QString&, int ) ), m_pageView, SLOT( warningMessage( const QString&, int ) ) );
    connect( m_document, SIGNAL( notice( const QString&, int ) ), m_pageView, SLOT( noticeMessage( const QString&, int ) ) );
    rightLayout->addWidget( m_pageView );
228 229
    m_findBar = new FindBar( m_document, rightContainer );
    rightLayout->addWidget( m_findBar );
230 231 232 233 234 235 236 237 238 239 240 241
    QWidget * bottomBar = new QWidget( rightContainer );
    QHBoxLayout * bottomBarLayout = new QHBoxLayout( bottomBar );
    m_pageSizeLabel = new PageSizeLabel( bottomBar, m_document );
    bottomBarLayout->setMargin( 0 );
    bottomBarLayout->setSpacing( 0 );
    bottomBarLayout->addWidget( m_pageSizeLabel->antiWidget() );
    bottomBarLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Expanding, QSizePolicy::Minimum ) );
    m_miniBar = new MiniBar( bottomBar, m_document );
    bottomBarLayout->addWidget( m_miniBar );
    bottomBarLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Expanding, QSizePolicy::Minimum ) );
    bottomBarLayout->addWidget( m_pageSizeLabel );
    rightLayout->addWidget( bottomBar );
242

243
    connect( reviewsWidget, SIGNAL( setAnnotationWindow( Okular::Annotation* ) ),
244
        m_pageView, SLOT( setAnnotationWindow( Okular::Annotation* ) ) );
245
    connect( reviewsWidget, SIGNAL( removeAnnotationWindow( Okular::Annotation* ) ),
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
        m_pageView, SLOT( removeAnnotationWindow( Okular::Annotation* ) ) );

    // add document observers
    m_document->addObserver( this );
    m_document->addObserver( m_thumbnailList );
    m_document->addObserver( m_pageView );
    m_document->addObserver( m_toc );
    m_document->addObserver( m_miniBar );
    m_document->addObserver( m_progressWidget );
    m_document->addObserver( reviewsWidget );
    m_document->addObserver( m_pageSizeLabel );
    m_document->addObserver( bookmarkList );

    // ACTIONS
    KActionCollection * ac = actionCollection();

    // Page Traversal actions
    m_gotoPage = KStandardAction::gotoPage( this, SLOT( slotGoToPage() ), ac );
    ac->addAction("goto_page", m_gotoPage);
    m_gotoPage->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_G) );
    // dirty way to activate gotopage when pressing miniBar's button
    connect( m_miniBar, SIGNAL( gotoPage() ), m_gotoPage, SLOT( trigger() ) );

    m_prevPage = KStandardAction::prior(this, SLOT(slotPreviousPage()), ac);
    ac->addAction("previous_page", m_prevPage);
    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
    connect( m_miniBar, SIGNAL( prevPage() ), m_prevPage, SLOT( trigger() ) );
    connect( m_progressWidget, SIGNAL( prevPage() ), m_prevPage, SLOT( trigger() ) );

    m_nextPage = KStandardAction::next(this, SLOT(slotNextPage()), ac );
    ac->addAction("next_page", m_nextPage);
    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
    connect( m_miniBar, SIGNAL( nextPage() ), m_nextPage, SLOT( trigger() ) );
    connect( m_progressWidget, SIGNAL( nextPage() ), m_nextPage, SLOT( trigger() ) );

    m_firstPage = KStandardAction::firstPage( this, SLOT( slotGotoFirst() ), ac );
    ac->addAction("first_page", m_firstPage);
    m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) );

    m_lastPage = KStandardAction::lastPage( this, SLOT( slotGotoLast() ), ac );
    ac->addAction("last_page",m_lastPage);
    m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) );

Albert Astals Cid's avatar
Albert Astals Cid committed
293 294 295
    // we do not want back and next in history in the dummy mode
    m_historyBack = 0;
    m_historyNext = 0;
296

297 298
    m_addBookmark = KStandardAction::addBookmark( this, SLOT( slotAddBookmark() ), ac );
    m_addBookmarkText = m_addBookmark->text();
299
    m_addBookmarkIcon = m_addBookmark->icon();
300

301 302
    m_prevBookmark = ac->addAction("previous_bookmark");
    m_prevBookmark->setText(i18n( "Previous Bookmark" ));
303
    m_prevBookmark->setIcon(KIcon( "find-previous" ));
304 305 306 307 308
    m_prevBookmark->setWhatsThis( i18n( "Go to the previous bookmarked page" ) );
    connect( m_prevBookmark, SIGNAL( triggered() ), this, SLOT( slotPreviousBookmark() ) );

    m_nextBookmark = ac->addAction("next_bookmark");
    m_nextBookmark->setText(i18n( "Next Bookmark" ));
309
    m_nextBookmark->setIcon(KIcon( "find-next" ));
310 311 312 313 314 315 316
    m_nextBookmark->setWhatsThis( i18n( "Go to the next bookmarked page" ) );
    connect( m_nextBookmark, SIGNAL( triggered() ), this, SLOT( slotNextBookmark() ) );

    m_copy = KStandardAction::create( KStandardAction::Copy, m_pageView, SLOT( copyTextSelection() ), ac );
    ac->addAction("edit_copy",m_copy);

    // Find and other actions
317
    m_find = KStandardAction::find( this, SLOT( slotShowFindBar() ), ac );
318
    ac->addAction("find", m_find);
319 320 321
    QList<QKeySequence> s = m_find->shortcuts();
    s.append( QKeySequence( Qt::Key_Slash ) );
    m_find->setShortcuts( s );
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
    m_find->setEnabled( false );

    m_findNext = KStandardAction::findNext( this, SLOT( slotFindNext() ), ac);
    ac->addAction("find_next",m_findNext);
    m_findNext->setEnabled( false );

    m_saveAs = KStandardAction::saveAs( this, SLOT( slotSaveFileAs() ), ac );
    ac->addAction("save",m_saveAs);
    m_saveAs->setEnabled( false );
    QAction * prefs = KStandardAction::preferences( this, SLOT( slotPreferences() ), ac);
    ac->addAction("preferences", prefs);
    if ( parent && ( parent->objectName() == QLatin1String( "okular::Shell" ) ) )
    {
        prefs->setText( i18n( "Configure okular..." ) );
    }
    else
    {
Pino Toscano's avatar
Pino Toscano committed
339
        // TODO: improve this message
340 341 342 343 344 345
        prefs->setText( i18n( "Configure Viewer..." ) );
    }

    QAction * genPrefs = KStandardAction::preferences( this, SLOT( slotGeneratorPreferences() ), ac );
    ac->addAction("generator_prefs", genPrefs);
    genPrefs->setText( i18n( "Configure Backends..." ) );
346
    genPrefs->setEnabled( m_document->configurableGenerators() > 0 );
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365

    m_printPreview = KStandardAction::printPreview( this, SLOT( slotPrintPreview() ), ac );
    m_printPreview->setEnabled( false );

    m_showLeftPanel = ac->add<KToggleAction>("show_leftpanel");
    m_showLeftPanel->setText(i18n( "Show &Navigation Panel"));
    m_showLeftPanel->setIcon(KIcon( "show_side_panel" ));
    connect( m_showLeftPanel, SIGNAL( toggled( bool ) ), this, SLOT( slotShowLeftPanel() ) );
    m_showLeftPanel->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_L) );
    m_showLeftPanel->setCheckedState( KGuiItem(i18n( "Hide &Navigation Panel" ) ));
    m_showLeftPanel->setChecked( Okular::Settings::showLeftPanel() );
    slotShowLeftPanel();

    QAction * importPS = ac->addAction("import_ps");
    importPS->setText(i18n("&Import Postscript as PDF..."));
    importPS->setIcon(KIcon("psimport"));
    connect(importPS, SIGNAL(triggered()), this, SLOT(slotImportPSFile()));
    QAction * ghns = ac->addAction("get_new_stuff");
    ghns->setText(i18n("&Get Books From Internet..."));
366
    ghns->setIcon(KIcon("get-hot-new-stuff"));
367
    connect(ghns, SIGNAL(triggered()), this, SLOT(slotGetNewStuff()));
Pino Toscano's avatar
Pino Toscano committed
368
    // TEMP, REMOVE ME!
369 370 371 372
    ghns->setShortcut( Qt::Key_G );

    m_showProperties = ac->addAction("properties");
    m_showProperties->setText(i18n("&Properties"));
373
    m_showProperties->setIcon(KIcon("document-properties"));
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
    connect(m_showProperties, SIGNAL(triggered()), this, SLOT(slotShowProperties()));
    m_showProperties->setEnabled( false );

    m_showEmbeddedFiles = ac->addAction("embedded_files");
    m_showEmbeddedFiles->setText(i18n("&Embedded Files"));
    connect(m_showEmbeddedFiles, SIGNAL(triggered()), this, SLOT(slotShowEmbeddedFiles()));
    m_showEmbeddedFiles->setEnabled( false );

    m_showPresentation = ac->addAction("presentation");
    m_showPresentation->setText(i18n("P&resentation"));
    m_showPresentation->setIcon(KIcon( "kpresenter_kpr" ));
    connect(m_showPresentation, SIGNAL(triggered()), this, SLOT(slotShowPresentation()));
    m_showPresentation->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_P ) );
    m_showPresentation->setEnabled( false );

    m_exportAs = ac->addAction("file_export_as");
    m_exportAs->setText(i18n("E&xport As"));
    QMenu *menu = new QMenu(widget());
    connect(menu, SIGNAL(triggered(QAction *)), this, SLOT(slotExportAs(QAction *)));
    m_exportAs->setMenu( menu );
394
    m_exportAsText = actionForExportFormat( Okular::ExportFormat::standardFormat( Okular::ExportFormat::PlainText ), menu );
395
    menu->addAction( m_exportAsText );
396 397
    m_exportAsText->setEnabled( false );

398 399 400 401
    m_aboutBackend = ac->addAction("help_about_backend");
    m_aboutBackend->setText(i18n("About backend..."));
    connect(m_aboutBackend, SIGNAL(triggered()), this, SLOT(slotAboutBackend()));

402 403 404 405 406 407 408 409
    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()) );
    reload->setShortcut( KStandardShortcut::reload() );
    m_reload = reload;

410 411 412 413 414 415
    KAction *closeFindBar = new KAction( i18n( "Close &Find Bar" ), ac );
    ac->addAction("close_find_bar", closeFindBar);
    connect(closeFindBar, SIGNAL(triggered()), this, SLOT(slotHideFindBar()));
    closeFindBar->setShortcut( QKeySequence( Qt::Key_Escape ) );
    widget()->addAction(closeFindBar);

416 417 418 419 420 421 422 423 424 425 426 427
    // document watcher and reloader
    m_watcher = new KDirWatch( this );
    connect( m_watcher, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileDirty( const QString& ) ) );
    m_dirtyHandler = new QTimer( this );
    m_dirtyHandler->setSingleShot( true );
    connect( m_dirtyHandler, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) );

    slotNewConfig();

    // [SPEECH] check for KTTSD presence and usability
    KService::List offers = KServiceTypeTrader::self()->query("DBUS/Text-to-Speech", "Name == 'KTTSD'");
    Okular::Settings::setUseKTTSD( !offers.isEmpty() );
428
    Okular::Settings::self()->writeConfig();
429

430 431
    rebuildBookmarkMenu( false );

432 433
    // set our XML-UI resource file
    setXMLFile("part.rc");
434 435 436 437

    m_pageView->setupBaseActions( actionCollection() );

    // ensure history actions are in the correct state
438
    updateViewActions();
439 440 441

    m_dummyMode = true;
    m_leftPanel->hide();
Albert Astals Cid's avatar
Albert Astals Cid committed
442
    if (!args.contains("Print/Preview")) unsetDummyMode();
443 444
}

445

446
Part::~Part()
Laurent Montel's avatar
Laurent Montel committed
447
{
Albert Astals Cid's avatar
Albert Astals Cid committed
448 449 450 451
    delete m_toc;
    delete m_pageView;
    delete m_thumbnailList;
    delete m_miniBar;
452
    delete m_progressWidget;
Albert Astals Cid's avatar
Albert Astals Cid committed
453
    delete m_pageSizeLabel;
Albert Astals Cid's avatar
Albert Astals Cid committed
454

455
    delete m_document;
Leandro Emanuel López's avatar
Leandro Emanuel López committed
456 457

    delete m_tempfile;
458 459

    qDeleteAll( m_bookmarkActions );
Laurent Montel's avatar
Laurent Montel committed
460 461
}

462

463 464 465 466 467 468 469 470
bool Part::openDocument(const KUrl& url, uint page)
{
    Okular::DocumentViewport vp( page - 1 );
    if ( vp.isValid() )
        m_document->setNextDocumentViewport( vp );
    return openUrl( url );
}

471

472 473 474 475 476
void Part::startPresentation()
{
    m_cliPresentation = true;
}

477

478 479 480 481 482 483
QStringList Part::supportedMimeTypes() const
{
    return m_document->supportedMimeTypes();
}


484
void Part::openUrlFromDocument(const KUrl &url)
Piotr Szymanski's avatar
Piotr Szymanski committed
485
{
486 487
    if (m_dummyMode) return;

Albert Astals Cid's avatar
Albert Astals Cid committed
488 489 490
    m_bExtension->openUrlNotify();
    m_bExtension->setLocationBarUrl(url.prettyUrl());
    openUrl(url);
Piotr Szymanski's avatar
Piotr Szymanski committed
491 492
}

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
void Part::openUrlFromBookmarks(const KUrl &_url)
{
    KUrl url = _url;
    Okular::DocumentViewport vp( _url.htmlRef() );
    if ( vp.isValid() )
        m_document->setNextDocumentViewport( vp );
    url.setHTMLRef( QString() );
    if ( m_document->currentDocument() == url )
    {
        if ( vp.isValid() )
            m_document->setViewport( vp );
    }
    else
        openUrl( url );
}

Piotr Szymanski's avatar
Piotr Szymanski committed
509 510 511 512
void Part::setMimeTypes(KIO::Job *job)
{
    if (job)
    {
513 514
        QStringList supportedMimeTypes = m_document->supportedMimeTypes();
        job->addMetaData("accept", supportedMimeTypes.join(", ") + ", */*;q=0.5");
Albert Astals Cid's avatar
Albert Astals Cid committed
515
        connect(job, SIGNAL(mimetype(KIO::Job*,const QString&)), this, SLOT(readMimeType(KIO::Job*,const QString&)));
Piotr Szymanski's avatar
Piotr Szymanski committed
516 517 518
    }
}

Albert Astals Cid's avatar
Albert Astals Cid committed
519 520 521 522
void Part::readMimeType(KIO::Job *, const QString &mime)
{
    m_jobMime = mime;
}
523

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
void Part::loadCancelled(const QString &reason)
{
    emit setWindowCaption( QString() );
    if (!reason.isEmpty())
    {
        KMessageBox::error( widget(), i18n("Could not open %1. Reason: %2", url().prettyUrl(), reason ) );
    }
    else
    {
        KMessageBox::error( widget(), i18n("Could not open %1", url().prettyUrl() ) );
    }
}

void Part::setWindowTitleFromDocument()
{
    // if the document have a 'DocumentTitle' flag set (and it is not empty), set it as title
    QString title = m_document->metaData( "DocumentTitle" ).toString();
    if ( !title.isEmpty() && !title.trimmed().isEmpty() )
    {
        emit setWindowCaption( title );
    }
    else
    {
        emit setWindowCaption( url().fileName() );
    }
}

551 552 553 554 555 556 557 558
void Part::slotGeneratorPreferences( )
{
    // an instance the dialog could be already created and could be cached,
    // in which case you want to display the cached dialog
    if ( KConfigDialog::showDialog( "generator_prefs" ) )
        return;

    // we didn't find an instance of this dialog, so lets create it
559
    KConfigDialog * dialog = new KConfigDialog( m_pageView, "generator_prefs", Okular::Settings::self() );
Pino Toscano's avatar
Pino Toscano committed
560
    dialog->setCaption( i18n( "Configure Backends" ) );
561

562
    m_document->fillConfigDialog( dialog );
563

564 565
    // keep us informed when the user changes settings
    connect( dialog, SIGNAL( settingsChanged( const QString& ) ), this, SLOT( slotNewGeneratorConfig() ) );
566 567 568
    dialog->show();
}

569

570 571 572 573 574 575
void Part::notifySetup( const QVector< Okular::Page * > & /*pages*/, bool documentChanged )
{
    if ( !documentChanged )
        return;

    rebuildBookmarkMenu();
576
    updateAboutBackendAction();
577
    m_searchWidget->setEnabled( m_document->supportsSearching() );
578 579
}

Enrico Ros's avatar
Enrico Ros committed
580
void Part::notifyViewportChanged( bool /*smoothMove*/ )
581
{
582 583 584 585 586
    // update actions if the page is changed
    static int lastPage = -1;
    int viewportPage = m_document->viewport().pageNumber;
    if ( viewportPage != lastPage )
    {
587
        updateViewActions();
588 589
        lastPage = viewportPage;
    }
590 591
}

592
void Part::notifyPageChanged( int page, int flags )
593 594 595 596 597
{
    if ( !(flags & Okular::DocumentObserver::Bookmark ) )
        return;

    rebuildBookmarkMenu();
598 599
    if ( page == m_document->viewport().pageNumber )
        updateBookmarksActions();
600 601
}

602

603 604
void Part::goToPage(uint i)
{
605
    if ( i <= m_document->pages() )
606
        m_document->setViewportPage( i - 1 );
607 608
}

609

Pino Toscano's avatar
porting  
Pino Toscano committed
610
void Part::openDocument(KUrl doc)
611
{
612
    openUrl(doc);
613 614
}

615

616 617
uint Part::pages()
{
Enrico Ros's avatar
Enrico Ros committed
618 619 620
    return m_document->pages();
}

621

Enrico Ros's avatar
Enrico Ros committed
622 623 624 625 626
uint Part::currentPage()
{
    return m_document->pages() ? m_document->currentPage() + 1 : 0;
}

627

Pino Toscano's avatar
porting  
Pino Toscano committed
628
KUrl Part::currentDocument()
Enrico Ros's avatar
Enrico Ros committed
629 630
{
    return m_document->currentDocument();
631 632
}

633

634
//this don't go anywhere but is required by genericfactory.h
635
KAboutData* Part::createAboutData()
Laurent Montel's avatar
Laurent Montel committed
636
{
637 638 639
    // the non-i18n name here must be the same as the directory in
    // which the part's rc file is installed ('partrcdir' in the
    // Makefile)
640
    KAboutData* aboutData = okularAboutData( "okularpart", I18N_NOOP( "okularpart" ) );
641
    aboutData->addAuthor(ki18n("Wilco Greven"), KLocalizedString(), "greven@kde.org");
642
    return aboutData;
Laurent Montel's avatar
Laurent Montel committed
643 644
}

645

646 647
bool Part::slotImportPSFile()
{
648 649 650 651 652 653 654
    QString app = KStandardDirs::findExe( "ps2pdf" );
    if ( app.isEmpty() )
    {
        // TODO point the user to their distro packages?
        KMessageBox::error( widget(), i18n( "The program \"ps2pdf\" was not found, so okular can not import PS files using it." ), i18n("ps2pdf not found") );
        return false;
    }
655

Pino Toscano's avatar
Pino Toscano committed
656
    KUrl url = KFileDialog::getOpenUrl( KUrl(), "application/postscript", this->widget() );
657
    if ( url.isLocalFile() )
658
    {
659 660 661 662 663 664
        KTemporaryFile tf;
        tf.setSuffix( ".pdf" );
        tf.setAutoRemove( false );
        if ( !tf.open() )
            return false;
        m_temporaryLocalFile = tf.fileName();
665
        tf.close();
666

667
        setLocalFilePath( url.path() );
668 669 670
        QStringList args;
        QProcess *p = new QProcess();
        args << url.toLocalFile() << m_temporaryLocalFile;
671
        m_pageView->displayMessage(i18n("Importing PS file as PDF (this may take a while)..."));
672 673
        connect(p, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(psTransformEnded(int, QProcess::ExitStatus)));
        p->start(app, args);
674 675
        return true;
    }
676

Albert Astals Cid's avatar
Albert Astals Cid committed
677
    m_temporaryLocalFile.clear();
678
    return false;
679
}
Piotr Szymanski's avatar
Piotr Szymanski committed
680

681

682
bool Part::openFile()
Laurent Montel's avatar
Laurent Montel committed
683
{
Piotr Szymanski's avatar
Piotr Szymanski committed
684 685 686
    KMimeType::Ptr mime;
    if ( m_bExtension->urlArgs().serviceType.isEmpty() )
    {
Albert Astals Cid's avatar
Albert Astals Cid committed
687 688 689 690 691
        if (!m_jobMime.isEmpty())
        {
            mime = KMimeType::mimeType(m_jobMime);
            if ( !mime )
            {
692
                mime = KMimeType::findByPath( localFilePath() );
Albert Astals Cid's avatar
Albert Astals Cid committed
693 694 695 696
            }
        }
        else
        {
697
            mime = KMimeType::findByPath( localFilePath() );
Albert Astals Cid's avatar
Albert Astals Cid committed
698
        }
Piotr Szymanski's avatar
Piotr Szymanski committed
699 700 701 702 703
    }
    else
    {
        mime = KMimeType::mimeType( m_bExtension->urlArgs().serviceType );
    }
704
    bool ok = m_document->openDocument( localFilePath(), url(), mime );
705
    bool canSearch = m_document->supportsSearching();
706 707

    // update one-time actions
708 709
    m_find->setEnabled( ok && canSearch );
    m_findNext->setEnabled( ok && canSearch );
710 711
    m_saveAs->setEnabled( ok );
    m_printPreview->setEnabled( ok );
712
    m_showProperties->setEnabled( ok );
713 714
    bool hasEmbeddedFiles = ok && m_document->embeddedFiles() && m_document->embeddedFiles()->count() > 0;
    m_showEmbeddedFiles->setEnabled( hasEmbeddedFiles );
715
    m_topMessage->setVisible( hasEmbeddedFiles );
716 717
    // m_pageView->toggleFormsAction() may be null on dummy mode
    m_formsMessage->setVisible( ok && m_pageView->toggleFormsAction() && m_pageView->toggleFormsAction()->isEnabled() );
718
    m_showPresentation->setEnabled( ok );
719 720
    if ( ok )
    {
Tobias Koenig's avatar
Tobias Koenig committed
721 722 723
        m_exportFormats = m_document->exportFormats();
        QList<Okular::ExportFormat>::ConstIterator it = m_exportFormats.constBegin();
        QList<Okular::ExportFormat>::ConstIterator itEnd = m_exportFormats.constEnd();
724 725 726
        QMenu *menu = m_exportAs->menu();
        for ( ; it != itEnd; ++it )
        {
727
            menu->addAction( actionForExportFormat( *it ) );
728 729 730
        }
    }
    m_exportAsText->setEnabled( ok && m_document->canExportToText() );
731 732

    // update viewing actions
733
    updateViewActions();
734

735 736 737
    if ( !ok )
    {
        // if can't open document, update windows so they display blank contents
738
        m_pageView->widget()->update();
739
        m_thumbnailList->update();
740 741 742 743
        return false;
    }

    // set the file to the fileWatcher
744 745
    if ( !m_watcher->contains(localFilePath()) )
        m_watcher->addFile(localFilePath());
746

Pino Toscano's avatar
Pino Toscano committed
747
    // if the 'OpenTOC' flag is set, open the TOC
748
    if ( m_document->metaData( "OpenTOC" ).toBool() && m_toolBox->isItemEnabled( 0 ) )
749 750 751
    {
        m_toolBox->setCurrentIndex( 0 );
    }
752 753 754
    // if the 'StartFullScreen' flag is set, or the command line flag was
    // specified, start presentation
    if ( m_document->metaData( "StartFullScreen" ).toBool() || m_cliPresentation )
Enrico Ros's avatar
Enrico Ros committed
755
    {
756
        if ( !m_cliPresentation )
Albert Astals Cid's avatar
Albert Astals Cid committed
757
            KMessageBox::information( m_presentationWidget, i18n("The document is going to be launched on presentation mode because the file requested it."), QString(), "autoPresentationWarning" );
758 759
        m_cliPresentation = false;
        QMetaObject::invokeMethod(this, "slotShowPresentation", Qt::QueuedConnection);
Enrico Ros's avatar
Enrico Ros committed
760
    }
761 762
    /*    if (m_document->getXMLFile() != QString::null)
            setXMLFile(m_document->getXMLFile(),true);*/
763
    m_document->setupGui( actionCollection(), m_toolBox );
764
    return true;
Laurent Montel's avatar
Laurent Montel committed
765 766
}

767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
static QString compressedMimeFor( const QString& mime_to_check )
{
    static QHash< QString, QString > compressedMimeMap;
    if ( compressedMimeMap.isEmpty() )
    {
        compressedMimeMap[ QString::fromLatin1( "application/x-gzip" ) ] =
            QString::fromLatin1( "application/x-gzip" );
        compressedMimeMap[ QString::fromLatin1( "application/x-bzip" ) ] =
            QString::fromLatin1( "application/x-bzip" );
        compressedMimeMap[ QString::fromLatin1( "application/x-bzpdf" ) ] =
            QString::fromLatin1( "application/x-bzip" );
        compressedMimeMap[ QString::fromLatin1( "application/x-bzpostscript" ) ] =
            QString::fromLatin1( "application/x-bzip" );
        compressedMimeMap[ QString::fromLatin1( "application/x-bzdvi" ) ] =
            QString::fromLatin1( "application/x-bzip" );
    }
    QHash< QString, QString >::const_iterator it = compressedMimeMap.find( mime_to_check );
    if ( it != compressedMimeMap.end() )
        return it.value();

    return QString();
}
789

790
bool Part::openUrl(const KUrl &url)
791
{
Enrico Ros's avatar
Enrico Ros committed
792 793 794 795
    // note: this can be the right place to check the file for gz or bz2 extension
    // if it matches then: download it (if not local) extract to a temp file using
    // KTar and proceed with the URL of the temporary file

Albert Astals Cid's avatar
Albert Astals Cid committed
796
    m_jobMime.clear();
797 798 799 800
    const QString path = url.path();
    const KMimeType::Ptr mimetype = KMimeType::findByPath( path );
    bool isCompressedFile = false;
    KUrl tempUrl;
801 802 803 804
    QString compressedMime = compressedMimeFor( mimetype->name() );
    if ( compressedMime.isEmpty() )
        compressedMime = compressedMimeFor( mimetype->parentMimeType() );
    if ( !compressedMime.isEmpty() )
805 806 807
    {
        isCompressedFile=handleCompressed(tempUrl,path,mimetype);
    }
808

809
    // this calls in sequence the 'closeUrl' and 'openFile' methods
810 811
    bool openOk;
    if ( !isCompressedFile )
812
        openOk = KParts::ReadOnlyPart::openUrl(url);
813
    else openOk = KParts::ReadOnlyPart::openUrl(tempUrl);
814

815
    if ( openOk )
816
    {
Albert Astals Cid's avatar
Albert Astals Cid committed
817
        m_viewportDirty.pageNumber = -1;
818

819
        setWindowTitleFromDocument();
820
    }
821

Albert Astals Cid's avatar
Albert Astals Cid committed
822
    emit enablePrintAction(openOk);
823
    return openOk;
824 825
}

826

827
bool Part::closeUrl()
828
{
829
    if (!m_temporaryLocalFile.isNull() && m_temporaryLocalFile != localFilePath())
830 831
    {
        QFile::remove( m_temporaryLocalFile );
Albert Astals Cid's avatar
Albert Astals Cid committed
832
        m_temporaryLocalFile.clear();
833 834
    }

Piotr Szymanski's avatar
Piotr Szymanski committed
835
    slotHidePresentation();
836 837 838 839 840
    m_find->setEnabled( false );
    m_findNext->setEnabled( false );
    m_saveAs->setEnabled( false );
    m_printPreview->setEnabled( false );
    m_showProperties->setEnabled( false );
841
    m_showEmbeddedFiles->setEnabled( false );
842
    m_exportAsText->setEnabled( false );
Tobias Koenig's avatar
Tobias Koenig committed
843
    m_exportFormats.clear();
844 845 846 847 848 849 850 851
    QMenu *menu = m_exportAs->menu();
    QList<QAction*> acts = menu->actions();
    int num = acts.count();
    for ( int i = 1; i < num; ++i )
    {
        menu->removeAction( acts.at(i) );
        delete acts.at(i);
    }
852
    m_showPresentation->setEnabled( false );
Piotr Szymanski's avatar
Piotr Szymanski committed
853 854
    emit setWindowCaption("");
    emit enablePrintAction(false);
855
    m_searchStarted = false;
856
    if (!localFilePath().isEmpty()) m_watcher->removeFile(localFilePath());
857
    m_document->closeDocument();
Piotr Szymanski's avatar
Piotr Szymanski committed
858
    updateViewActions();
859
    m_searchWidget->clearText();
Albert Astals Cid's avatar
Albert Astals Cid committed
860
    return KParts::ReadOnlyPart::closeUrl();
861 862
}

863

Piotr Szymanski's avatar
Piotr Szymanski committed
864 865
void Part::close()
{
Pino Toscano's avatar
Pino Toscano committed
866 867
    // NOTE: don't know why, but the correct object name should be "okular::Shell"
    if (parent() && (parent()->objectName() == QLatin1String("okular/okular__Shell")))
868 869 870
    {
        closeUrl();
    }
Albert Astals Cid's avatar
Albert Astals Cid committed
871
    else KMessageBox::information( widget(), i18n( "This link points to a close document action that does not work when using the embedded viewer." ), QString(), "warnNoCloseIfNotInOkular" );
Piotr Szymanski's avatar
Piotr Szymanski committed
872 873
}

874

Piotr Szymanski's avatar
Piotr Szymanski committed
875 876
void Part::cannotQuit()
{
Albert Astals Cid's avatar
Albert Astals Cid committed
877
    KMessageBox::information( widget(), i18n( "This link points to a quit application action that does not work when using the embedded viewer." ), QString(), "warnNoQuitIfNotInOkular" );
Piotr Szymanski's avatar
Piotr Szymanski committed
878 879
}

880

881
void Part::splitterMoved( int /*pos*/, int index )
882 883
{
    // if pageView has been resized, save splitter sizes
884
    if ( index == 1 )
Piotr Szymanski's avatar
Piotr Szymanski committed
885
        saveSplitterSize();
886 887
}

888

889
void Part::slotShowLeftPanel()
Albert Astals Cid's avatar
Albert Astals Cid committed
890
{
891
    bool showLeft = m_showLeftPanel->isChecked();
892
    Okular::Settings::setShowLeftPanel( showLeft );
893
    Okular::Settings::self()->writeConfig();
Enrico Ros's avatar
Enrico Ros committed
894
    // show/hide left panel
Pino Toscano's avatar
Pino Toscano committed
895
    m_leftPanel->setVisible( showLeft );
896
    // this needs to be hidden explicitly to disable thumbnails gen
Pino Toscano's avatar
Pino Toscano committed
897
    m_thumbnailList->setVisible( showLeft );
Albert Astals Cid's avatar
Albert Astals Cid committed
898 899
}

900

Piotr Szymanski's avatar
Piotr Szymanski committed
901 902
void Part::saveSplitterSize()
{
903
    Okular::Settings::setSplitterSizes( m_splitter->sizes() );
904
    Okular::Settings::self()->writeConfig();
Piotr Szymanski's avatar
Piotr Szymanski committed
905 906
}

907