OSDN Git Service

f76d2868b4d09f3b783f3bb0e504b4d6590c027e
[kde/kde-extraapps.git] / okular / part.cpp
1 /***************************************************************************
2  *   Copyright (C) 2002 by Wilco Greven <greven@kde.org>                   *
3  *   Copyright (C) 2002 by Chris Cheney <ccheney@cheney.cx>                *
4  *   Copyright (C) 2002 by Malcolm Hunter <malcolm.hunter@gmx.co.uk>       *
5  *   Copyright (C) 2003-2004 by Christophe Devriese                        *
6  *                         <Christophe.Devriese@student.kuleuven.ac.be>    *
7  *   Copyright (C) 2003 by Daniel Molkentin <molkentin@kde.org>            *
8  *   Copyright (C) 2003 by Andy Goossens <andygoossens@telenet.be>         *
9  *   Copyright (C) 2003 by Dirk Mueller <mueller@kde.org>                  *
10  *   Copyright (C) 2003 by Laurent Montel <montel@kde.org>                 *
11  *   Copyright (C) 2004 by Dominique Devriese <devriese@kde.org>           *
12  *   Copyright (C) 2004 by Christoph Cullmann <crossfire@babylon2k.de>     *
13  *   Copyright (C) 2004 by Henrique Pinto <stampede@coltec.ufmg.br>        *
14  *   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  *   This program is free software; you can redistribute it and/or modify  *
19  *   it under the terms of the GNU General Public License as published by  *
20  *   the Free Software Foundation; either version 2 of the License, or     *
21  *   (at your option) any later version.                                   *
22  ***************************************************************************/
23
24 #include "part.h"
25
26 // qt/kde includes
27 #include <qapplication.h>
28 #include <qfile.h>
29 #include <qlayout.h>
30 #include <qlabel.h>
31 #include <qtimer.h>
32 #include <QtGui/QPrinter>
33 #include <QtGui/QPrintDialog>
34 #include <QtGui/QPrintPreviewDialog>
35 #include <QScrollBar>
36
37 #include <kvbox.h>
38 #include <kaboutapplicationdialog.h>
39 #include <kaction.h>
40 #include <kactioncollection.h>
41 #include <kdirwatch.h>
42 #include <kstandardaction.h>
43 #include <kpluginfactory.h>
44 #include <kfiledialog.h>
45 #include <kinputdialog.h>
46 #include <kmessagebox.h>
47 #include <knuminput.h>
48 #include <kio/netaccess.h>
49 #include <kmenu.h>
50 #include <kxmlguiclient.h>
51 #include <kxmlguifactory.h>
52 #include <kservicetypetrader.h>
53 #include <kstandarddirs.h>
54 #include <kstandardshortcut.h>
55 #include <ktemporaryfile.h>
56 #include <ktoggleaction.h>
57 #include <ktogglefullscreenaction.h>
58 #include <kio/job.h>
59 #include <kicon.h>
60 #include <kdecompressor.h>
61 #include <kdeprintdialog.h>
62 #include <kbookmarkmenu.h>
63 #include <kpassworddialog.h>
64 #include <kpasswdstore.h>
65
66 // local includes
67 #include "aboutdata.h"
68 #include "extensions.h"
69 #include "ui/pageview.h"
70 #include "ui/toc.h"
71 #include "ui/searchwidget.h"
72 #include "ui/thumbnaillist.h"
73 #include "ui/side_reviews.h"
74 #include "ui/minibar.h"
75 #include "ui/embeddedfilesdialog.h"
76 #include "ui/propertiesdialog.h"
77 #include "ui/presentationwidget.h"
78 #include "ui/pagesizelabel.h"
79 #include "ui/bookmarklist.h"
80 #include "ui/findbar.h"
81 #include "ui/sidebar.h"
82 #include "ui/guiutils.h"
83 #include "conf/preferencesdialog.h"
84 #include "settings.h"
85 #include "core/action.h"
86 #include "core/annotations.h"
87 #include "core/bookmarkmanager.h"
88 #include "core/document.h"
89 #include "core/generator.h"
90 #include "core/page.h"
91
92 #include <cstdio>
93 #include <memory>
94
95 class FileKeeper
96 {
97     public:
98         FileKeeper()
99             : m_handle( NULL )
100         {
101         }
102
103         ~FileKeeper()
104         {
105         }
106
107         void open( const QString & path )
108         {
109             if ( !m_handle )
110                 m_handle = std::fopen( QFile::encodeName( path ), "r" );
111         }
112
113         void close()
114         {
115             if ( m_handle )
116             {
117                 int ret = std::fclose( m_handle );
118                 Q_UNUSED( ret )
119                 m_handle = NULL;
120             }
121         }
122
123         KTemporaryFile* copyToTemporary() const
124         {
125             if ( !m_handle )
126                 return 0;
127
128             KTemporaryFile * retFile = new KTemporaryFile;
129             retFile->open();
130
131             std::rewind( m_handle );
132             int c = -1;
133             do
134             {
135                 c = std::fgetc( m_handle );
136                 if ( c == EOF )
137                     break;
138                 if ( !retFile->putChar( (char)c ) )
139                     break;
140             } while ( !feof( m_handle ) );
141
142             retFile->flush();
143
144             return retFile;
145         }
146
147     private:
148         std::FILE * m_handle;
149 };
150
151 Okular::PartFactory::PartFactory()
152 : KPluginFactory(okularAboutData( "okular", I18N_NOOP( "Okular" ) ))
153 {
154 }
155
156 Okular::PartFactory::~PartFactory()
157 {
158 }
159
160 QObject *Okular::PartFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString &keyword)
161 {
162     Q_UNUSED ( keyword );
163
164     Okular::Part *object = new Okular::Part( parentWidget, parent, args, componentData() );
165     object->setReadWrite( QLatin1String(iface) == QLatin1String("KParts::ReadWritePart") );
166     return object;
167 }
168
169 K_EXPORT_PLUGIN( Okular::PartFactory() )
170
171 static QAction* actionForExportFormat( const Okular::ExportFormat& format, QObject *parent = 0 )
172 {
173     QAction *act = new QAction( format.description(), parent );
174     if ( !format.icon().isNull() )
175     {
176         act->setIcon( format.icon() );
177     }
178     return act;
179 }
180
181 static QString compressedMimeFor( const QString& mime_to_check )
182 {
183     static bool supportChecked = false;
184     static bool supportBzip = false;
185     static bool supportXz = false;
186     const QString app_gzip( QString::fromLatin1( "application/x-gzip" ) );
187     const QString app_bzip( QString::fromLatin1( "application/x-bzip" ) );
188     const QString app_xz( QString::fromLatin1( "application/x-xz" ) );
189     if ( !supportChecked )
190     {
191         KDecompressor f;
192         // check we can read bzip2-compressed files
193         if ( f.setType( KDecompressor::TypeBZip2 ) )
194         {
195             supportBzip = true;
196         }
197         // check we can read XZ-compressed files
198         if ( f.setType( KDecompressor::TypeXZ ) )
199         {
200             supportXz = true;
201         }
202         supportChecked = true;
203     }
204
205     // The "is()" calls below check inheritance too
206     KMimeType::Ptr mime = KMimeType::mimeType( mime_to_check );
207     if ( mime )
208     {
209         if ( mime->is( app_gzip ) )
210             return app_gzip;
211         else if ( supportBzip && mime->is( app_bzip ) )
212             return app_bzip;
213         else if ( supportXz && mime->is( app_xz ) )
214             return app_xz;
215     }
216
217     return QString();
218 }
219
220 static Okular::EmbedMode detectEmbedMode( QWidget *parentWidget, QObject *parent, const QVariantList &args )
221 {
222     Q_UNUSED( parentWidget );
223
224     if ( parent
225          && ( parent->objectName() == QLatin1String( "okular::Shell" )
226               || parent->objectName() == QLatin1String( "okular/okular__Shell" ) ) )
227         return Okular::NativeShellMode;
228
229     Q_FOREACH ( const QVariant &arg, args )
230     {
231         if ( arg.type() == QVariant::String )
232         {
233             if ( arg.toString() == QLatin1String( "Print/Preview" ) )
234             {
235                 return Okular::PrintPreviewMode;
236             }
237             else if ( arg.toString() == QLatin1String( "ViewerWidget" ) )
238             {
239                 return Okular::ViewerWidgetMode;
240             }
241         }
242     }
243
244     return Okular::UnknownEmbedMode;
245 }
246
247 static QString detectConfigFileName( const QVariantList &args )
248 {
249     Q_FOREACH ( const QVariant &arg, args )
250     {
251         if ( arg.type() == QVariant::String )
252         {
253             QString argString = arg.toString();
254             int separatorIndex = argString.indexOf( "=" );
255             if ( separatorIndex >= 0 && argString.left( separatorIndex ) == QLatin1String( "ConfigFileName" ) )
256             {
257                 return argString.mid( separatorIndex + 1 );
258             }
259         }
260     }
261
262     return QString();
263 }
264
265 #undef OKULAR_KEEP_FILE_OPEN
266
267 #ifdef OKULAR_KEEP_FILE_OPEN
268 static bool keepFileOpen()
269 {
270     static bool keep_file_open = !qgetenv("OKULAR_NO_KEEP_FILE_OPEN").toInt();
271     return keep_file_open;
272 }
273 #endif
274
275 int Okular::Part::numberOfParts = 0;
276
277 namespace Okular
278 {
279
280 Part::Part(QWidget *parentWidget,
281 QObject *parent,
282 const QVariantList &args,
283 KComponentData componentData )
284 : KParts::ReadWritePart(parent),
285 m_tempfile( 0 ), m_fileWasRemoved( false ), m_showMenuBarAction( 0 ), m_showFullScreenAction( 0 ), m_actionsSearched( false ),
286 m_cliPresentation(false), m_cliPrint(false), m_embedMode(detectEmbedMode(parentWidget, parent, args)), m_generatorGuiClient(0), m_keeper( 0 )
287 {
288     setObjectName(QString::fromLatin1("OkularPart"));
289
290     // first, we check if a config file name has been specified
291     QString configFileName = detectConfigFileName( args );
292     if ( configFileName.isEmpty() )
293     {
294         configFileName = KStandardDirs::locateLocal( "config", "okularpartrc" );
295     }
296     Okular::Settings::instance( configFileName );
297     
298     numberOfParts++;
299     if (numberOfParts == 1) {
300         QDBusConnection::sessionBus().registerObject("/okular", this, QDBusConnection::ExportScriptableSlots);
301     } else {
302         QDBusConnection::sessionBus().registerObject(QString("/okular%1").arg(numberOfParts), this, QDBusConnection::ExportScriptableSlots);
303     }
304
305     // connect the started signal to tell the job the mimetypes we like,
306     // and get some more information from it
307     connect(this, SIGNAL(started(KIO::Job*)), this, SLOT(slotJobStarted(KIO::Job*)));
308
309     // connect the completed signal so we can put the window caption when loading remote files
310     connect(this, SIGNAL(completed()), this, SLOT(setWindowTitleFromDocument()));
311     connect(this, SIGNAL(canceled(QString)), this, SLOT(loadCancelled(QString)));
312
313     // create browser extension (for printing when embedded into browser)
314     m_bExtension = new BrowserExtension(this);
315
316     // we need an instance
317     setComponentData( componentData );
318
319     m_sidebar = new Sidebar( parentWidget );
320     setWidget( m_sidebar );
321     connect( m_sidebar, SIGNAL(urlsDropped(KUrl::List)), SLOT(handleDroppedUrls(KUrl::List)) );
322
323     // build the document
324     m_document = new Okular::Document(widget());
325     connect( m_document, SIGNAL(linkFind()), this, SLOT(slotFind()) );
326     connect( m_document, SIGNAL(linkGoToPage()), this, SLOT(slotGoToPage()) );
327     connect( m_document, SIGNAL(linkPresentation()), this, SLOT(slotShowPresentation()) );
328     connect( m_document, SIGNAL(linkEndPresentation()), this, SLOT(slotHidePresentation()) );
329     connect( m_document, SIGNAL(openUrl(KUrl)), this, SLOT(openUrlFromDocument(KUrl)) );
330     connect( m_document->bookmarkManager(), SIGNAL(openUrl(KUrl)), this, SLOT(openUrlFromBookmarks(KUrl)) );
331     connect( m_document, SIGNAL(close()), this, SLOT(close()) );
332
333     if ( parent && parent->metaObject()->indexOfSlot( QMetaObject::normalizedSignature( "slotQuit()" ) ) != -1 )
334         connect( m_document, SIGNAL(quit()), parent, SLOT(slotQuit()) );
335     else
336         connect( m_document, SIGNAL(quit()), this, SLOT(cannotQuit()) );
337     // widgets: ^searchbar (toolbar containing label and SearchWidget)
338     //      m_searchToolBar = new KToolBar( parentWidget, "searchBar" );
339     //      m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() );
340     //      QLabel * sLabel = new QLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" );
341     //      m_searchWidget = new SearchWidget( m_searchToolBar, m_document );
342     //      sLabel->setBuddy( m_searchWidget );
343     //      m_searchToolBar->setStretchableWidget( m_searchWidget );
344
345     int tbIndex;
346     // [left toolbox: Table of Contents] | []
347     m_toc = new TOC( 0, m_document );
348     connect( m_toc, SIGNAL(hasTOC(bool)), this, SLOT(enableTOC(bool)) );
349     tbIndex = m_sidebar->addItem( m_toc, KIcon(QApplication::isLeftToRight() ? "format-justify-left" : "format-justify-right"), i18n("Contents") );
350     enableTOC( false );
351
352     // [left toolbox: Thumbnails and Bookmarks] | []
353     KVBox * thumbsBox = new ThumbnailsBox( 0 );
354     thumbsBox->setSpacing( 6 );
355     m_searchWidget = new SearchWidget( thumbsBox, m_document );
356     m_thumbnailList = new ThumbnailList( thumbsBox, m_document );
357     //  ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList );
358     connect( m_thumbnailList, SIGNAL(rightClick(const Okular::Page*,QPoint)), this, SLOT(slotShowMenu(const Okular::Page*,QPoint)) );
359     tbIndex = m_sidebar->addItem( thumbsBox, KIcon( "view-preview" ), i18n("Thumbnails") );
360     m_sidebar->setCurrentIndex( tbIndex );
361
362     // [left toolbox: Reviews] | []
363     m_reviewsWidget = new Reviews( 0, m_document );
364     m_sidebar->addItem( m_reviewsWidget, KIcon("draw-freehand"), i18n("Reviews") );
365     m_sidebar->setItemEnabled( 2, false );
366
367     // [left toolbox: Bookmarks] | []
368     m_bookmarkList = new BookmarkList( m_document, 0 );
369     m_sidebar->addItem( m_bookmarkList, KIcon("bookmarks"), i18n("Bookmarks") );
370     m_sidebar->setItemEnabled( 3, false );
371
372     // widgets: [../miniBarContainer] | []
373 #ifdef OKULAR_ENABLE_MINIBAR
374     QWidget * miniBarContainer = new QWidget( 0 );
375     m_sidebar->setBottomWidget( miniBarContainer );
376     QVBoxLayout * miniBarLayout = new QVBoxLayout( miniBarContainer );
377     miniBarLayout->setMargin( 0 );
378     // widgets: [../[spacer/..]] | []
379     miniBarLayout->addItem( new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
380     // widgets: [../[../MiniBar]] | []
381     QFrame * bevelContainer = new QFrame( miniBarContainer );
382     bevelContainer->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
383     QVBoxLayout * bevelContainerLayout = new QVBoxLayout( bevelContainer );
384     bevelContainerLayout->setMargin( 4 );
385     m_progressWidget = new ProgressWidget( bevelContainer, m_document );
386     bevelContainerLayout->addWidget( m_progressWidget );
387     miniBarLayout->addWidget( bevelContainer );
388     miniBarLayout->addItem( new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
389 #endif
390
391     // widgets: [] | [right 'pageView']
392     QWidget * rightContainer = new QWidget( 0 );
393     m_sidebar->setMainWidget( rightContainer );
394     QVBoxLayout * rightLayout = new QVBoxLayout( rightContainer );
395     rightLayout->setMargin( 0 );
396     rightLayout->setSpacing( 0 );
397     //  KToolBar * rtb = new KToolBar( rightContainer, "mainToolBarSS" );
398     //  rightLayout->addWidget( rtb );
399     m_topMessage = new KMessageWidget( rightContainer );
400     m_topMessage->setVisible( false );
401     m_topMessage->setWordWrap( true );
402     m_topMessage->setMessageType( KMessageWidget::Information );
403     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." ) );
404     m_topMessage->setIcon( KIcon( "mail-attachment" ) );
405     connect( m_topMessage, SIGNAL(linkActivated(QString)), this, SLOT(slotShowEmbeddedFiles()) );
406     rightLayout->addWidget( m_topMessage );
407     m_formsMessage = new KMessageWidget( rightContainer );
408     m_formsMessage->setVisible( false );
409     m_formsMessage->setWordWrap( true );
410     m_formsMessage->setMessageType( KMessageWidget::Information );
411     rightLayout->addWidget( m_formsMessage );
412     m_infoMessage = new KMessageWidget( rightContainer );
413     m_infoMessage->setVisible( false );
414     m_infoMessage->setWordWrap( true );
415     m_infoMessage->setMessageType( KMessageWidget::Information );
416     rightLayout->addWidget( m_infoMessage );
417     m_infoTimer = new QTimer();
418     m_infoTimer->setSingleShot( true );
419     connect( m_infoTimer, SIGNAL(timeout()), m_infoMessage, SLOT(animatedHide()) );
420     m_pageView = new PageView( rightContainer, m_document );
421     QMetaObject::invokeMethod( m_pageView, "setFocus", Qt::QueuedConnection );      //usability setting
422 //    m_splitter->setFocusProxy(m_pageView);
423     connect( m_pageView, SIGNAL(rightClick(const Okular::Page*,QPoint)), this, SLOT(slotShowMenu(const Okular::Page*,QPoint)) );
424     connect( m_document, SIGNAL(error(QString,int)), this, SLOT(errorMessage(QString,int)) );
425     connect( m_document, SIGNAL(warning(QString,int)), this, SLOT(warningMessage(QString,int)) );
426     connect( m_document, SIGNAL(notice(QString,int)), this, SLOT(noticeMessage(QString,int)) );
427     connect( m_document, SIGNAL(sourceReferenceActivated(const QString&,int,int,bool*)), this, SLOT(slotHandleActivatedSourceReference(const QString&,int,int,bool*)) );
428     rightLayout->addWidget( m_pageView );
429     m_findBar = new FindBar( m_document, rightContainer );
430     rightLayout->addWidget( m_findBar );
431     m_bottomBar = new QWidget( rightContainer );
432     QHBoxLayout * bottomBarLayout = new QHBoxLayout( m_bottomBar );
433     m_pageSizeLabel = new PageSizeLabel( m_bottomBar, m_document );
434     bottomBarLayout->setMargin( 0 );
435     bottomBarLayout->setSpacing( 0 );
436     bottomBarLayout->addItem( new QSpacerItem( 5, 5, QSizePolicy::Expanding, QSizePolicy::Minimum ) );
437     m_miniBarLogic = new MiniBarLogic( this, m_document );
438     m_miniBar = new MiniBar( m_bottomBar, m_miniBarLogic );
439     bottomBarLayout->addWidget( m_miniBar );
440     bottomBarLayout->addWidget( m_pageSizeLabel );
441     rightLayout->addWidget( m_bottomBar );
442
443     m_pageNumberTool = new MiniBar( 0, m_miniBarLogic );
444
445     connect( m_findBar, SIGNAL(forwardKeyPressEvent(QKeyEvent*)), m_pageView, SLOT(externalKeyPressEvent(QKeyEvent*)));
446     connect( m_findBar, SIGNAL(onCloseButtonPressed()), m_pageView, SLOT(setFocus()));
447     connect( m_miniBar, SIGNAL(forwardKeyPressEvent(QKeyEvent*)), m_pageView, SLOT(externalKeyPressEvent(QKeyEvent*)));
448     connect( m_pageView, SIGNAL(escPressed()), m_findBar, SLOT(resetSearch()) );
449     connect( m_pageNumberTool, SIGNAL(forwardKeyPressEvent(QKeyEvent*)), m_pageView, SLOT(externalKeyPressEvent(QKeyEvent*)));
450
451     connect( m_reviewsWidget, SIGNAL(openAnnotationWindow(Okular::Annotation*,int)),
452         m_pageView, SLOT(openAnnotationWindow(Okular::Annotation*,int)) );
453
454     // add document observers
455     m_document->addObserver( this );
456     m_document->addObserver( m_thumbnailList );
457     m_document->addObserver( m_pageView );
458     m_document->registerView( m_pageView );
459     m_document->addObserver( m_toc );
460     m_document->addObserver( m_miniBarLogic );
461 #ifdef OKULAR_ENABLE_MINIBAR
462     m_document->addObserver( m_progressWidget );
463 #endif
464     m_document->addObserver( m_reviewsWidget );
465     m_document->addObserver( m_pageSizeLabel );
466     m_document->addObserver( m_bookmarkList );
467
468     connect( m_document->bookmarkManager(), SIGNAL(saved()),
469         this, SLOT(slotRebuildBookmarkMenu()) );
470
471     setupViewerActions();
472
473     if ( m_embedMode != ViewerWidgetMode )
474     {
475         setupActions();
476     }
477     else
478     {
479         setViewerShortcuts();
480     }
481
482     // document watcher and reloader
483     m_watcher = new KDirWatch( this );
484     connect( m_watcher, SIGNAL(dirty(QString)), this, SLOT(slotFileDirty(QString)) );
485     m_dirtyHandler = new QTimer( this );
486     m_dirtyHandler->setSingleShot( true );
487     connect( m_dirtyHandler, SIGNAL(timeout()),this, SLOT(slotDoFileDirty()) );
488
489     slotNewConfig();
490
491     // keep us informed when the user changes settings
492     connect( Okular::Settings::self(), SIGNAL(configChanged()), this, SLOT(slotNewConfig()) );
493
494     rebuildBookmarkMenu( false );
495
496     if ( m_embedMode == ViewerWidgetMode ) {
497         // set the XML-UI resource file for the viewer mode
498         setXMLFile("part-viewermode.rc");
499     }
500     else
501     {
502         // set our main XML-UI resource file
503         setXMLFile("part.rc");
504     }
505
506     m_pageView->setupBaseActions( actionCollection() );
507
508     m_sidebar->setSidebarVisibility( false );
509     if ( m_embedMode != PrintPreviewMode )
510     {
511         // now set up actions that are required for all remaining modes
512         m_pageView->setupViewerActions( actionCollection() );
513         // and if we are not in viewer mode, we want the full GUI
514         if ( m_embedMode != ViewerWidgetMode )
515         {
516             unsetDummyMode();
517         }
518     }
519
520     // ensure history actions are in the correct state
521     updateViewActions();
522
523     // also update the state of the actions in the page view
524     m_pageView->updateActionState( false, false, false );
525
526     if ( m_embedMode == NativeShellMode )
527         m_sidebar->setAutoFillBackground( false );
528
529 #ifdef OKULAR_KEEP_FILE_OPEN
530     m_keeper = new FileKeeper();
531 #endif
532 }
533
534 void Part::setupViewerActions()
535 {
536     // ACTIONS
537     KActionCollection * ac = actionCollection();
538
539     // Page Traversal actions
540     m_gotoPage = KStandardAction::gotoPage( this, SLOT(slotGoToPage()), ac );
541     m_gotoPage->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_G) );
542     // dirty way to activate gotopage when pressing miniBar's button
543     connect( m_miniBar, SIGNAL(gotoPage()), m_gotoPage, SLOT(trigger()) );
544     connect( m_pageNumberTool, SIGNAL(gotoPage()), m_gotoPage, SLOT(trigger()) );
545
546     m_prevPage = KStandardAction::prior(this, SLOT(slotPreviousPage()), ac);
547     m_prevPage->setIconText( i18nc( "Previous page", "Previous" ) );
548     m_prevPage->setToolTip( i18n( "Go back to the Previous Page" ) );
549     m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );
550     m_prevPage->setShortcut( 0 );
551     // dirty way to activate prev page when pressing miniBar's button
552     connect( m_miniBar, SIGNAL(prevPage()), m_prevPage, SLOT(trigger()) );
553     connect( m_pageNumberTool, SIGNAL(prevPage()), m_prevPage, SLOT(trigger()) );
554 #ifdef OKULAR_ENABLE_MINIBAR
555     connect( m_progressWidget, SIGNAL(prevPage()), m_prevPage, SLOT(trigger()) );
556 #endif
557
558     m_nextPage = KStandardAction::next(this, SLOT(slotNextPage()), ac );
559     m_nextPage->setIconText( i18nc( "Next page", "Next" ) );
560     m_nextPage->setToolTip( i18n( "Advance to the Next Page" ) );
561     m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );
562     m_nextPage->setShortcut( 0 );
563     // dirty way to activate next page when pressing miniBar's button
564     connect( m_miniBar, SIGNAL(nextPage()), m_nextPage, SLOT(trigger()) );
565     connect( m_pageNumberTool, SIGNAL(nextPage()), m_nextPage, SLOT(trigger()) );
566 #ifdef OKULAR_ENABLE_MINIBAR
567     connect( m_progressWidget, SIGNAL(nextPage()), m_nextPage, SLOT(trigger()) );
568 #endif
569
570     m_beginningOfDocument = KStandardAction::firstPage( this, SLOT(slotGotoFirst()), ac );
571     ac->addAction("first_page", m_beginningOfDocument);
572     m_beginningOfDocument->setText(i18n( "Beginning of the document"));
573     m_beginningOfDocument->setWhatsThis( i18n( "Moves to the beginning of the document" ) );
574
575     m_endOfDocument = KStandardAction::lastPage( this, SLOT(slotGotoLast()), ac );
576     ac->addAction("last_page",m_endOfDocument);
577     m_endOfDocument->setText(i18n( "End of the document"));
578     m_endOfDocument->setWhatsThis( i18n( "Moves to the end of the document" ) );
579
580     // we do not want back and next in history in the dummy mode
581     m_historyBack = 0;
582     m_historyNext = 0;
583
584     m_addBookmark = KStandardAction::addBookmark( this, SLOT(slotAddBookmark()), ac );
585     m_addBookmarkText = m_addBookmark->text();
586     m_addBookmarkIcon = m_addBookmark->icon();
587
588     m_renameBookmark = ac->addAction("rename_bookmark");
589     m_renameBookmark->setText(i18n( "Rename Bookmark" ));
590     m_renameBookmark->setIcon(KIcon( "edit-rename" ));
591     m_renameBookmark->setWhatsThis( i18n( "Rename the current bookmark" ) );
592     connect( m_renameBookmark, SIGNAL(triggered()), this, SLOT(slotRenameCurrentViewportBookmark()) );
593
594     m_prevBookmark = ac->addAction("previous_bookmark");
595     m_prevBookmark->setText(i18n( "Previous Bookmark" ));
596     m_prevBookmark->setIcon(KIcon( "go-up-search" ));
597     m_prevBookmark->setWhatsThis( i18n( "Go to the previous bookmark" ) );
598     connect( m_prevBookmark, SIGNAL(triggered()), this, SLOT(slotPreviousBookmark()) );
599
600     m_nextBookmark = ac->addAction("next_bookmark");
601     m_nextBookmark->setText(i18n( "Next Bookmark" ));
602     m_nextBookmark->setIcon(KIcon( "go-down-search" ));
603     m_nextBookmark->setWhatsThis( i18n( "Go to the next bookmark" ) );
604     connect( m_nextBookmark, SIGNAL(triggered()), this, SLOT(slotNextBookmark()) );
605
606     m_copy = 0;
607
608     m_selectAll = 0;
609
610     // Find and other actions
611     m_find = KStandardAction::find( this, SLOT(slotShowFindBar()), ac );
612     QList<QKeySequence> s = m_find->shortcuts();
613     s.append( QKeySequence( Qt::Key_Slash ) );
614     m_find->setShortcuts( s );
615     m_find->setEnabled( false );
616
617     m_findNext = KStandardAction::findNext( this, SLOT(slotFindNext()), ac);
618     m_findNext->setEnabled( false );
619
620     m_findPrev = KStandardAction::findPrev( this, SLOT(slotFindPrev()), ac );
621     m_findPrev->setEnabled( false );
622
623     m_saveCopyAs = 0;
624     m_saveAs = 0;
625
626     QAction * prefs = KStandardAction::preferences( this, SLOT(slotPreferences()), ac);
627     if ( m_embedMode == NativeShellMode )
628     {
629         prefs->setText( i18n( "Configure Okular..." ) );
630     }
631     else
632     {
633         // TODO: improve this message
634         prefs->setText( i18n( "Configure Viewer..." ) );
635     }
636
637     KAction * genPrefs = new KAction( ac );
638     ac->addAction("options_configure_generators", genPrefs);
639     if ( m_embedMode == ViewerWidgetMode )
640     {
641         genPrefs->setText( i18n( "Configure Viewer Backends..." ) );
642     }
643     else
644     {
645         genPrefs->setText( i18n( "Configure Backends..." ) );
646     }
647     genPrefs->setIcon( KIcon( "configure" ) );
648     genPrefs->setEnabled( m_document->configurableGenerators() > 0 );
649     connect( genPrefs, SIGNAL(triggered(bool)), this, SLOT(slotGeneratorPreferences()) );
650
651     m_printPreview = KStandardAction::printPreview( this, SLOT(slotPrintPreview()), ac );
652     m_printPreview->setEnabled( false );
653
654     m_showLeftPanel = 0;
655     m_showBottomBar = 0;
656
657     m_showProperties = ac->addAction("properties");
658     m_showProperties->setText(i18n("&Properties"));
659     m_showProperties->setIcon(KIcon("document-properties"));
660     connect(m_showProperties, SIGNAL(triggered()), this, SLOT(slotShowProperties()));
661     m_showProperties->setEnabled( false );
662
663     m_showEmbeddedFiles = 0;
664     m_showPresentation = 0;
665
666     m_exportAs = 0;
667     m_exportAsMenu = 0;
668     m_exportAsText = 0;
669     m_exportAsDocArchive = 0;
670
671     m_aboutBackend = ac->addAction("help_about_backend");
672     m_aboutBackend->setText(i18n("About Backend"));
673     m_aboutBackend->setIcon(KIcon("preferences-plugin"));
674     m_aboutBackend->setEnabled( false );
675     connect(m_aboutBackend, SIGNAL(triggered()), this, SLOT(slotAboutBackend()));
676
677     KAction *reload = ac->add<KAction>( "file_reload" );
678     reload->setText( i18n( "Reloa&d" ) );
679     reload->setIcon( KIcon( "view-refresh" ) );
680     reload->setWhatsThis( i18n( "Reload the current document from disk." ) );
681     connect( reload, SIGNAL(triggered()), this, SLOT(slotReload()) );
682     reload->setShortcut( KStandardShortcut::reload() );
683     m_reload = reload;
684
685     m_closeFindBar = ac->addAction( "close_find_bar", this, SLOT(slotHideFindBar()) );
686     m_closeFindBar->setText( i18n("Close &Find Bar") );
687     m_closeFindBar->setShortcut( QKeySequence(Qt::Key_Escape) );
688     m_closeFindBar->setEnabled( false );
689
690     KAction *pageno = new KAction( i18n( "Page Number" ), ac );
691     pageno->setDefaultWidget( m_pageNumberTool );
692     ac->addAction( "page_number", pageno );
693 }
694
695 void Part::setViewerShortcuts()
696 {
697     KActionCollection * ac = actionCollection();
698
699     m_gotoPage->setShortcut( QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_G) );
700     m_find->setShortcuts( QList<QKeySequence>() );
701
702     m_findNext->setShortcut( QKeySequence() );
703     m_findPrev->setShortcut( QKeySequence() );
704
705     m_addBookmark->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_B ) );
706
707     m_beginningOfDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_Home ) );
708     m_endOfDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_End ) );
709
710     KAction *action = static_cast<KAction*>( ac->action( "file_reload" ) );
711     if( action )  action->setShortcuts( QList<QKeySequence>() << QKeySequence( Qt::ALT + Qt::Key_F5 ) );
712 }
713
714 void Part::setupActions()
715 {
716     KActionCollection * ac = actionCollection();
717
718     m_copy = KStandardAction::create( KStandardAction::Copy, m_pageView, SLOT(copyTextSelection()), ac );
719
720     m_selectAll = KStandardAction::selectAll( m_pageView, SLOT(selectAll()), ac );
721
722     m_saveCopyAs = KStandardAction::saveAs( this, SLOT(slotSaveCopyAs()), ac );
723     m_saveCopyAs->setText( i18n( "Save &Copy As..." ) );
724     m_saveCopyAs->setShortcut( KShortcut() );
725     ac->addAction( "file_save_copy", m_saveCopyAs );
726     m_saveCopyAs->setEnabled( false );
727
728     m_saveAs = KStandardAction::saveAs( this, SLOT(slotSaveFileAs()), ac );
729     m_saveAs->setEnabled( false );
730
731     m_showLeftPanel = ac->add<KToggleAction>("show_leftpanel");
732     m_showLeftPanel->setText(i18n( "Show &Navigation Panel"));
733     m_showLeftPanel->setIcon(KIcon( "view-sidetree" ));
734     connect( m_showLeftPanel, SIGNAL(toggled(bool)), this, SLOT(slotShowLeftPanel()) );
735     m_showLeftPanel->setShortcut( Qt::Key_F7 );
736     m_showLeftPanel->setChecked( Okular::Settings::showLeftPanel() );
737     slotShowLeftPanel();
738
739     m_showBottomBar = ac->add<KToggleAction>("show_bottombar");
740     m_showBottomBar->setText(i18n( "Show &Page Bar"));
741     connect( m_showBottomBar, SIGNAL(toggled(bool)), this, SLOT(slotShowBottomBar()) );
742     m_showBottomBar->setChecked( Okular::Settings::showBottomBar() );
743     slotShowBottomBar();
744
745     m_showEmbeddedFiles = ac->addAction("embedded_files");
746     m_showEmbeddedFiles->setText(i18n("&Embedded Files"));
747     m_showEmbeddedFiles->setIcon( KIcon( "mail-attachment" ) );
748     connect(m_showEmbeddedFiles, SIGNAL(triggered()), this, SLOT(slotShowEmbeddedFiles()));
749     m_showEmbeddedFiles->setEnabled( false );
750
751     m_exportAs = ac->addAction("file_export_as");
752     m_exportAs->setText(i18n("E&xport As"));
753     m_exportAs->setIcon( KIcon( "document-export" ) );
754     m_exportAsMenu = new QMenu();
755     connect(m_exportAsMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotExportAs(QAction*)));
756     m_exportAs->setMenu( m_exportAsMenu );
757     m_exportAsText = actionForExportFormat( Okular::ExportFormat::standardFormat( Okular::ExportFormat::PlainText ), m_exportAsMenu );
758     m_exportAsMenu->addAction( m_exportAsText );
759     m_exportAs->setEnabled( false );
760     m_exportAsText->setEnabled( false );
761     m_exportAsDocArchive = actionForExportFormat( Okular::ExportFormat(
762             i18nc( "A document format, Okular-specific", "Document Archive" ),
763             KMimeType::mimeType( "application/vnd.kde.okular-archive" ) ), m_exportAsMenu );
764     m_exportAsMenu->addAction( m_exportAsDocArchive );
765     m_exportAsDocArchive->setEnabled( false );
766
767     m_showPresentation = ac->addAction("presentation");
768     m_showPresentation->setText(i18n("P&resentation"));
769     m_showPresentation->setIcon( KIcon( "view-presentation" ) );
770     connect(m_showPresentation, SIGNAL(triggered()), this, SLOT(slotShowPresentation()));
771     m_showPresentation->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_P ) );
772     m_showPresentation->setEnabled( false );
773
774     KToggleAction *blackscreenAction = new KToggleAction( i18n( "Switch Blackscreen Mode" ), ac );
775     ac->addAction( "switch_blackscreen_mode", blackscreenAction );
776     blackscreenAction->setShortcut( QKeySequence( Qt::Key_B ) );
777     blackscreenAction->setIcon( KIcon( "view-presentation" ) );
778     blackscreenAction->setEnabled( false );
779
780     KToggleAction *drawingAction = new KToggleAction( i18n( "Toggle Drawing Mode" ), ac );
781     ac->addAction( "presentation_drawing_mode", drawingAction );
782     drawingAction->setIcon( KIcon( "draw-freehand" ) );
783     drawingAction->setEnabled( false );
784
785     KAction *eraseDrawingAction = new KAction( i18n( "Erase Drawings" ), ac );
786     ac->addAction( "presentation_erase_drawings", eraseDrawingAction );
787     eraseDrawingAction->setIcon( KIcon( "draw-eraser" ) );
788     eraseDrawingAction->setEnabled( false );
789
790     KAction *configureAnnotations = new KAction( i18n( "Configure Annotations..." ), ac );
791     ac->addAction( "options_configure_annotations", configureAnnotations );
792     configureAnnotations->setIcon( KIcon( "configure" ) );
793     connect(configureAnnotations, SIGNAL(triggered()), this, SLOT(slotAnnotationPreferences()));
794
795     KAction *playPauseAction = new KAction( i18n( "Play/Pause Presentation" ), ac );
796     ac->addAction( "presentation_play_pause", playPauseAction );
797     playPauseAction->setEnabled( false );
798 }
799
800 Part::~Part()
801 {
802     m_document->removeObserver( this );
803     m_document->removeObserver( m_toc );
804
805     if ( m_document->isOpened() )
806         Part::closeUrl( false );
807
808     delete m_toc;
809     delete m_pageView;
810     delete m_thumbnailList;
811     delete m_miniBar;
812     delete m_pageNumberTool;
813     delete m_miniBarLogic;
814     delete m_bottomBar;
815 #ifdef OKULAR_ENABLE_MINIBAR
816     delete m_progressWidget;
817 #endif
818     delete m_pageSizeLabel;
819     delete m_reviewsWidget;
820     delete m_bookmarkList;
821     delete m_infoTimer;
822
823     delete m_document;
824
825     delete m_tempfile;
826
827     qDeleteAll( m_bookmarkActions );
828
829     delete m_exportAsMenu;
830
831 #ifdef OKULAR_KEEP_FILE_OPEN
832     delete m_keeper;
833 #endif
834 }
835
836
837 bool Part::openDocument(const KUrl& url, uint page)
838 {
839     Okular::DocumentViewport vp( page - 1 );
840     vp.rePos.enabled = true;
841     vp.rePos.normalizedX = 0;
842     vp.rePos.normalizedY = 0;
843     vp.rePos.pos = Okular::DocumentViewport::TopLeft;
844     if ( vp.isValid() )
845         m_document->setNextDocumentViewport( vp );
846     return openUrl( url );
847 }
848
849
850 void Part::startPresentation()
851 {
852     m_cliPresentation = true;
853 }
854
855
856 QStringList Part::supportedMimeTypes() const
857 {
858     return m_document->supportedMimeTypes();
859 }
860
861
862 KUrl Part::realUrl() const
863 {
864     if ( !m_realUrl.isEmpty() )
865         return m_realUrl;
866
867     return url();
868 }
869
870 // ViewerInterface
871
872 void Part::showSourceLocation(const QString& fileName, int line, int column, bool showGraphically)
873 {
874     const QString u = QString( "src:%1 %2" ).arg( line + 1 ).arg( fileName );
875     GotoAction action( QString(), u );
876     m_document->processAction( &action );
877     if( showGraphically )
878     {
879         m_pageView->setLastSourceLocationViewport( m_document->viewport() );
880     }
881 }
882
883 void Part::clearLastShownSourceLocation()
884 {
885     m_pageView->clearLastSourceLocationViewport();
886 }
887
888 bool Part::isWatchFileModeEnabled() const
889 {
890     return true;
891 }
892
893 void Part::setWatchFileModeEnabled(bool enabled)
894 {
895     if( !enabled && isWatchFileModeEnabled() )
896     {
897         m_dirtyHandler->stop();
898     }
899 }
900
901 bool Part::areSourceLocationsShownGraphically() const
902 {
903     return m_pageView->areSourceLocationsShownGraphically();
904 }
905
906 void Part::setShowSourceLocationsGraphically(bool show)
907 {
908     m_pageView->setShowSourceLocationsGraphically(show);
909 }
910
911 bool Part::openNewFilesInTabs() const
912 {
913     return Okular::Settings::self()->shellOpenFileInTabs();
914 }
915
916 void Part::slotHandleActivatedSourceReference(const QString& absFileName, int line, int col, bool *handled)
917 {
918     emit openSourceReference( absFileName, line, col );
919     if ( m_embedMode == Okular::ViewerWidgetMode )
920     {
921         *handled = true;
922     }
923 }
924
925 void Part::openUrlFromDocument(const KUrl &url)
926 {
927     if ( m_embedMode == PrintPreviewMode )
928        return;
929
930     if (KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, widget()))
931     {
932         m_bExtension->openUrlNotify();
933         m_bExtension->setLocationBarUrl(url.prettyUrl());
934         openUrl(url);
935     } else {
936         KMessageBox::error( widget(), i18n("Could not open '%1'. File does not exist", url.pathOrUrl() ) );
937     }
938 }
939
940 void Part::openUrlFromBookmarks(const KUrl &_url)
941 {
942     KUrl url = _url;
943     Okular::DocumentViewport vp( _url.fragment() );
944     if ( vp.isValid() )
945         m_document->setNextDocumentViewport( vp );
946     url.setFragment( QString() );
947     if ( m_document->currentDocument() == url )
948     {
949         if ( vp.isValid() )
950             m_document->setViewport( vp );
951     }
952     else
953         openUrl( url );
954 }
955
956 void Part::handleDroppedUrls( const KUrl::List& urls )
957 {
958     if ( urls.isEmpty() )
959         return;
960
961     if ( m_embedMode != NativeShellMode || !openNewFilesInTabs() )
962     {
963         openUrlFromDocument( urls.first() );
964         return;
965     }
966
967     emit urlsDropped( urls );
968 }
969
970 void Part::slotJobStarted(KIO::Job *job)
971 {
972     if (job)
973     {
974         QStringList supportedMimeTypes = m_document->supportedMimeTypes();
975         job->addMetaData("accept", supportedMimeTypes.join(", ") + ", */*;q=0.5");
976
977         connect(job, SIGNAL(result(KJob*)), this, SLOT(slotJobFinished(KJob*)));
978     }
979 }
980
981 void Part::slotJobFinished(KJob *job)
982 {
983     if ( job->error() == KIO::ERR_USER_CANCELED )
984     {
985         m_pageView->displayMessage( i18n( "The loading of %1 has been canceled.", realUrl().pathOrUrl() ) );
986     }
987 }
988
989 void Part::loadCancelled(const QString &reason)
990 {
991     emit setWindowCaption( QString() );
992     resetStartArguments();
993
994     // when m_viewportDirty.pageNumber != -1 we come from slotDoFileDirty
995     // so we don't want to show an ugly messagebox just because the document is
996     // taking more than usual to be recreated
997     if (m_viewportDirty.pageNumber == -1)
998     {
999         if (!reason.isEmpty())
1000         {
1001             KMessageBox::error( widget(), i18n("Could not open %1. Reason: %2", url().prettyUrl(), reason ) );
1002         }
1003     }
1004 }
1005
1006 void Part::setWindowTitleFromDocument()
1007 {
1008     // If 'DocumentTitle' should be used, check if the document has one. If
1009     // either case is false, use the file name.
1010     QString title = Okular::Settings::displayDocumentNameOrPath() == Okular::Settings::EnumDisplayDocumentNameOrPath::Path ? realUrl().pathOrUrl() : realUrl().fileName();
1011
1012     if ( Okular::Settings::displayDocumentTitle() )
1013     {
1014         const QString docTitle = m_document->metaData( "DocumentTitle" ).toString();
1015         if ( !docTitle.isEmpty() && !docTitle.trimmed().isEmpty() )
1016         {
1017              title = docTitle;
1018         }
1019     }
1020
1021     emit setWindowCaption( title );
1022 }
1023
1024 KConfigDialog * Part::slotGeneratorPreferences( )
1025 {
1026     // Create dialog
1027     KConfigDialog * dialog = new KConfigDialog( m_pageView, "generator_prefs", Okular::Settings::self() );
1028     dialog->setAttribute( Qt::WA_DeleteOnClose );
1029
1030     if( m_embedMode == ViewerWidgetMode )
1031     {
1032         dialog->setCaption( i18n( "Configure Viewer Backends" ) );
1033     }
1034     else
1035     {
1036         dialog->setCaption( i18n( "Configure Backends" ) );
1037     }
1038
1039     m_document->fillConfigDialog( dialog );
1040
1041     // Show it
1042     dialog->setWindowModality( Qt::ApplicationModal );
1043     dialog->show();
1044
1045     return dialog;
1046 }
1047
1048
1049 void Part::notifySetup( const QVector< Okular::Page * > & /*pages*/, int setupFlags )
1050 {
1051     if ( !( setupFlags & Okular::DocumentObserver::DocumentChanged ) )
1052         return;
1053
1054     rebuildBookmarkMenu();
1055     updateAboutBackendAction();
1056     m_findBar->resetSearch();
1057     m_searchWidget->setEnabled( m_document->supportsSearching() );
1058 }
1059
1060 void Part::notifyViewportChanged( bool /*smoothMove*/ )
1061 {
1062     updateViewActions();
1063 }
1064
1065 void Part::notifyPageChanged( int page, int flags )
1066 {
1067     if ( flags & Okular::DocumentObserver::NeedSaveAs )
1068         setModified();
1069
1070     if ( !(flags & Okular::DocumentObserver::Bookmark ) )
1071         return;
1072
1073     rebuildBookmarkMenu();
1074     if ( page == m_document->viewport().pageNumber )
1075         updateBookmarksActions();
1076 }
1077
1078
1079 void Part::goToPage(uint i)
1080 {
1081     if ( i <= m_document->pages() )
1082         m_document->setViewportPage( i - 1 );
1083 }
1084
1085
1086 void Part::openDocument( const QString &doc )
1087 {
1088     openUrl( KUrl( doc ) );
1089 }
1090
1091
1092 uint Part::pages()
1093 {
1094     return m_document->pages();
1095 }
1096
1097
1098 uint Part::currentPage()
1099 {
1100     return m_document->pages() ? m_document->currentPage() + 1 : 0;
1101 }
1102
1103
1104 QString Part::currentDocument()
1105 {
1106     return m_document->currentDocument().pathOrUrl();
1107 }
1108
1109
1110 QString Part::documentMetaData( const QString &metaData ) const
1111 {
1112     const Okular::DocumentInfo * info = m_document->documentInfo();
1113     if ( info )
1114     {
1115         QDomElement docElement = info->documentElement();
1116         for ( QDomNode node = docElement.firstChild(); !node.isNull(); node = node.nextSibling() )
1117         {
1118             const QDomElement element = node.toElement();
1119             if ( metaData.compare( element.tagName(), Qt::CaseInsensitive ) == 0 )
1120                 return element.attribute( "value" );
1121         }
1122     }
1123
1124     return QString();
1125 }
1126
1127 static void addFileToWatcher( KDirWatch *watcher, const QString &filePath)
1128 {
1129     if ( !watcher->contains( filePath ) ) watcher->addFile(filePath);
1130     const QFileInfo fi(filePath);
1131     if ( !watcher->contains( fi.absolutePath() ) ) watcher->addDir(fi.absolutePath());
1132     if ( fi.isSymLink() ) watcher->addFile( fi.readLink() );
1133 }
1134
1135 Document::OpenResult Part::doOpenFile( const KMimeType::Ptr &mimeA, const QString &fileNameToOpenA, bool *isCompressedFile )
1136 {
1137     Document::OpenResult openResult = Document::OpenError;
1138     bool uncompressOk = true;
1139     KMimeType::Ptr mime = mimeA;
1140     QString fileNameToOpen = fileNameToOpenA;
1141     QString compressedMime = compressedMimeFor( mime->name() );
1142     if ( compressedMime.isEmpty() ) {
1143         const QStringList parentMimes = mime->parentMimeTypes();
1144         compressedMime = compressedMimeFor( !parentMimes.isEmpty() ? parentMimes.first() : QString() );        
1145     }
1146     if ( !compressedMime.isEmpty() )
1147     {
1148         *isCompressedFile = true;
1149         uncompressOk = handleCompressed( fileNameToOpen, localFilePath(), compressedMime );
1150         mime = KMimeType::findByPath( fileNameToOpen );
1151     }
1152     else
1153     {
1154         *isCompressedFile = false;
1155     }
1156
1157     isDocumentArchive = false;
1158     if ( uncompressOk )
1159     {
1160         if ( mime->is( "application/vnd.kde.okular-archive" ) )
1161         {
1162             openResult = m_document->openDocumentArchive( fileNameToOpen,  url() );
1163             isDocumentArchive = true;
1164         }
1165         else
1166         {
1167             openResult = m_document->openDocument( fileNameToOpen,  url(), mime );
1168         }
1169
1170         // if the file didn't open correctly it might be encrypted, so ask for a pass
1171         QString walletName, walletKey;
1172         m_document->walletDataForFile(fileNameToOpen, &walletName, &walletKey);
1173         bool firstInput = true;
1174         bool triedWallet = false;
1175         bool keep = true;
1176         while ( openResult == Document::OpenNeedsPassword )
1177         {
1178             KPasswdStore store;
1179             bool storeopened = false;
1180             const WId parentwid = widget()->effectiveWinId();
1181             QString password;
1182             QByteArray obscuredWalletKey = KPasswdStore::makeKey(walletKey);
1183
1184             // 1.A. try to retrieve the first password from the kde store system
1185             if ( !triedWallet && !walletKey.isNull() )
1186             {
1187                 store.setStoreID(walletName);
1188                 storeopened = store.openStore( parentwid );
1189                 if ( storeopened )
1190                 {
1191                     // look for the pass in that folder
1192                     QString retrievedPass = store.getPasswd( obscuredWalletKey, parentwid );
1193                     if (!retrievedPass.isEmpty())
1194                         password = retrievedPass;
1195                 }
1196                 triedWallet = true;
1197             }
1198
1199             // 1.B. if not retrieved, ask the password using the kde password dialog
1200             if ( password.isNull() )
1201             {
1202                 QString prompt;
1203                 if ( firstInput )
1204                     prompt = i18n( "Please enter the password to read the document:" );
1205                 else
1206                     prompt = i18n( "Incorrect password. Try again:" );
1207                 firstInput = false;
1208
1209                 // if the user presses cancel, abort opening
1210                 KPasswordDialog dlg( widget(), storeopened ? KPasswordDialog::ShowKeepPassword : KPasswordDialog::KPasswordDialogFlags() );
1211                 dlg.setCaption( i18n( "Document Password" ) );
1212                 dlg.setPrompt( prompt );
1213                 if( !dlg.exec() )
1214                     break;
1215                 password = dlg.password();
1216                 if ( storeopened )
1217                     keep = dlg.keepPassword();
1218             }
1219
1220             // 2. reopen the document using the password
1221             if ( mime->is( "application/vnd.kde.okular-archive" ) )
1222             {
1223                 openResult = m_document->openDocumentArchive( fileNameToOpen,  url(), password );
1224                 isDocumentArchive = true;
1225             }
1226             else
1227             {
1228                 openResult = m_document->openDocument( fileNameToOpen,  url(), mime, password );
1229             }
1230
1231             // 3. if the password is correct and the user chose to remember it, store it to the wallet
1232             if ( openResult == Document::OpenSuccess && storeopened && keep )
1233             {
1234                 store.storePasswd( obscuredWalletKey, password, parentwid );
1235             }
1236         }
1237     }
1238
1239     return openResult;
1240 }
1241
1242 bool Part::openFile()
1243 {
1244     QList<KMimeType::Ptr> mimes;
1245     QString fileNameToOpen = localFilePath();
1246     const bool isstdin = url().isLocalFile() && url().fileName( KUrl::LeaveTrailingSlash ) == QLatin1String( "-" );
1247     const QFileInfo fileInfo( fileNameToOpen );
1248     if ( !isstdin && !fileInfo.exists() )
1249         return false;
1250     KMimeType::Ptr pathMime = KMimeType::findByPath( fileNameToOpen );
1251     if ( !arguments().mimeType().isEmpty() )
1252     {
1253         KMimeType::Ptr argMime = KMimeType::mimeType( arguments().mimeType() );
1254
1255         // Select the "childmost" mimetype, if none of them
1256         // inherits the other trust more what pathMime says
1257         // but still do a second try if that one fails
1258         if ( argMime->is( pathMime->name() ) )
1259         {
1260             mimes << argMime;
1261         }
1262         else if ( pathMime->is( argMime->name() ) )
1263         {
1264             mimes << pathMime;
1265         }
1266         else
1267         {
1268             mimes << pathMime << argMime;
1269         }
1270
1271         if (mimes[0]->name() == "text/plain") {
1272             KMimeType::Ptr contentMime = KMimeType::findByFileContent( fileNameToOpen );
1273             mimes.prepend( contentMime );
1274         }
1275     }
1276     else
1277     {
1278         mimes << pathMime;
1279     }
1280
1281     KMimeType::Ptr mime;
1282     Document::OpenResult openResult = Document::OpenError;
1283     bool isCompressedFile = false;
1284     while ( !mimes.isEmpty() && openResult == Document::OpenError ) {
1285         mime = mimes.takeFirst();
1286         openResult = doOpenFile( mime, fileNameToOpen, &isCompressedFile );
1287     }
1288
1289     bool canSearch = m_document->supportsSearching();
1290     emit mimeTypeChanged( mime );
1291
1292     // update one-time actions
1293     const bool ok = openResult == Document::OpenSuccess;
1294     emit enableCloseAction( ok );
1295     m_find->setEnabled( ok && canSearch );
1296     m_findNext->setEnabled( ok && canSearch );
1297     m_findPrev->setEnabled( ok && canSearch );
1298     if( m_saveAs ) m_saveAs->setEnabled( ok && (m_document->canSaveChanges() || isDocumentArchive) );
1299     if( m_saveCopyAs ) m_saveCopyAs->setEnabled( ok );
1300     emit enablePrintAction( ok && m_document->printingSupport() != Okular::Document::NoPrinting );
1301     m_printPreview->setEnabled( ok && m_document->printingSupport() != Okular::Document::NoPrinting );
1302     m_showProperties->setEnabled( ok );
1303     bool hasEmbeddedFiles = ok && m_document->embeddedFiles() && m_document->embeddedFiles()->count() > 0;
1304     if ( m_showEmbeddedFiles ) m_showEmbeddedFiles->setEnabled( hasEmbeddedFiles );
1305     m_topMessage->setVisible( hasEmbeddedFiles && Okular::Settings::showOSD() );
1306
1307     // m_pageView->toggleFormsAction() may be null on dummy mode
1308     if ( ok && m_pageView->toggleFormsAction() && m_pageView->toggleFormsAction()->isEnabled() )
1309     {
1310         m_formsMessage->setText( i18n( "This document has forms. Click on the button to interact with them, or use View -> Show Forms." ) );
1311         m_formsMessage->setMessageType( KMessageWidget::Information );
1312         m_formsMessage->setVisible( true );
1313     }
1314     else
1315     {
1316         m_formsMessage->setVisible( false );
1317     }
1318
1319     if ( m_showPresentation ) m_showPresentation->setEnabled( ok );
1320     if ( ok )
1321     {
1322         if ( m_exportAs )
1323         {
1324             m_exportFormats = m_document->exportFormats();
1325             QList<Okular::ExportFormat>::ConstIterator it = m_exportFormats.constBegin();
1326             QList<Okular::ExportFormat>::ConstIterator itEnd = m_exportFormats.constEnd();
1327             QMenu *menu = m_exportAs->menu();
1328             for ( ; it != itEnd; ++it )
1329             {
1330                 menu->addAction( actionForExportFormat( *it ) );
1331             }
1332         }
1333         if ( isCompressedFile )
1334         {
1335             m_realUrl = url();
1336         }
1337 #ifdef OKULAR_KEEP_FILE_OPEN
1338         if ( keepFileOpen() )
1339             m_keeper->open( fileNameToOpen );
1340 #endif
1341     }
1342     if ( m_exportAsText ) m_exportAsText->setEnabled( ok && m_document->canExportToText() );
1343     if ( m_exportAsDocArchive ) m_exportAsDocArchive->setEnabled( ok );
1344     if ( m_exportAs ) m_exportAs->setEnabled( ok );
1345
1346     // update viewing actions
1347     updateViewActions();
1348
1349     m_fileWasRemoved = false;
1350
1351     if ( !ok )
1352     {
1353         // if can't open document, update windows so they display blank contents
1354         m_pageView->viewport()->update();
1355         m_thumbnailList->update();
1356         setUrl( KUrl() );
1357         return false;
1358     }
1359
1360     // set the file to the fileWatcher
1361     if ( url().isLocalFile() )
1362     {
1363         addFileToWatcher( m_watcher, localFilePath() );
1364     }
1365
1366     // if the 'OpenTOC' flag is set, open the TOC
1367     if ( m_document->metaData( "OpenTOC" ).toBool() && m_sidebar->isItemEnabled( 0 ) && !m_sidebar->isCollapsed() && m_sidebar->currentIndex() != 0 )
1368     {
1369         m_sidebar->setCurrentIndex( 0, Sidebar::DoNotUncollapseIfCollapsed );
1370     }
1371     // if the 'StartFullScreen' flag is set, or the command line flag was
1372     // specified, start presentation
1373     if ( m_document->metaData( "StartFullScreen" ).toBool() || m_cliPresentation )
1374     {
1375         bool goAheadWithPresentationMode = true;
1376         if ( !m_cliPresentation )
1377         {
1378             const QString text = i18n( "The document requested to be launched in presentation mode.\n"
1379                                        "Do you want to allow it?" );
1380             const QString caption = i18n( "Presentation Mode" );
1381             const KGuiItem yesItem = KGuiItem( i18n( "Allow" ), "dialog-ok", i18n( "Allow the presentation mode" ) );
1382             const KGuiItem noItem = KGuiItem( i18n( "Do Not Allow" ), "process-stop", i18n( "Do not allow the presentation mode" ) );
1383             const int result = KMessageBox::questionYesNo( widget(), text, caption, yesItem, noItem );
1384             if ( result == KMessageBox::No )
1385                 goAheadWithPresentationMode = false;
1386         }
1387         m_cliPresentation = false;
1388         if ( goAheadWithPresentationMode )
1389             QMetaObject::invokeMethod( this, "slotShowPresentation", Qt::QueuedConnection );
1390     }
1391     m_generatorGuiClient = factory() ? m_document->guiClient() : 0;
1392     if ( m_generatorGuiClient )
1393         factory()->addClient( m_generatorGuiClient );
1394     if ( m_cliPrint )
1395     {
1396         m_cliPrint = false;
1397         slotPrint();
1398     }
1399     return true;
1400 }
1401
1402 bool Part::openUrl(const KUrl &_url)
1403 {
1404     // Close current document if any
1405     if ( !closeUrl() )
1406         return false;
1407
1408     KUrl url( _url );
1409     // More or less the same hack as in ShellUtils::urlFromArg()
1410     if ( url.isLocalFile() && !QFile::exists(url.toLocalFile()) ) {
1411         const QString localFile = url.toLocalFile();
1412         const int sharpPos = localFile.lastIndexOf( QLatin1Char('#') );
1413         if (sharpPos != -1) {
1414             url.setPath( localFile.left(sharpPos) );
1415             url.setFragment( localFile.mid(sharpPos + 1) );
1416         }
1417     }
1418     if ( url.hasFragment() )
1419     {
1420         const QString dest = url.fragment();
1421         bool ok = true;
1422         const int page = dest.toInt( &ok );
1423         if ( ok )
1424         {
1425             Okular::DocumentViewport vp( page - 1 );
1426             vp.rePos.enabled = true;
1427             vp.rePos.normalizedX = 0;
1428             vp.rePos.normalizedY = 0;
1429             vp.rePos.pos = Okular::DocumentViewport::TopLeft;
1430             m_document->setNextDocumentViewport( vp );
1431         }
1432         else
1433         {
1434             m_document->setNextDocumentDestination( dest );
1435         }
1436         url.setFragment( QString() );
1437     }
1438
1439     // this calls in sequence the 'closeUrl' and 'openFile' methods
1440     bool openOk = KParts::ReadWritePart::openUrl( url );
1441
1442     if ( openOk )
1443     {
1444         m_viewportDirty.pageNumber = -1;
1445
1446         setWindowTitleFromDocument();
1447     }
1448     else
1449     {
1450         resetStartArguments();
1451         KMessageBox::error( widget(), i18n("Could not open %1", url.pathOrUrl() ) );
1452     }
1453
1454     return openOk;
1455 }
1456
1457 bool Part::queryClose()
1458 {
1459     if ( !isReadWrite() || !isModified() )
1460         return true;
1461
1462     const int res = KMessageBox::warningYesNoCancel( widget(),
1463                         i18n( "Do you want to save your annotation changes or discard them?" ),
1464                         i18n( "Close Document" ),
1465                         KStandardGuiItem::saveAs(),
1466                         KStandardGuiItem::discard() );
1467
1468     switch ( res )
1469     {
1470         case KMessageBox::Yes: // Save as
1471             slotSaveFileAs();
1472             return !isModified(); // Only allow closing if file was really saved
1473         case KMessageBox::No: // Discard
1474             return true;
1475         default: // Cancel
1476             return false;
1477     }
1478 }
1479
1480 bool Part::closeUrl(bool promptToSave)
1481 {
1482     if ( promptToSave && !queryClose() )
1483         return false;
1484
1485     setModified( false );
1486
1487     slotHidePresentation();
1488     emit enableCloseAction( false );
1489     m_find->setEnabled( false );
1490     m_findNext->setEnabled( false );
1491     m_findPrev->setEnabled( false );
1492     if( m_saveAs )  m_saveAs->setEnabled( false );
1493     if( m_saveCopyAs ) m_saveCopyAs->setEnabled( false );
1494     m_printPreview->setEnabled( false );
1495     m_showProperties->setEnabled( false );
1496     if ( m_showEmbeddedFiles ) m_showEmbeddedFiles->setEnabled( false );
1497     if ( m_exportAs ) m_exportAs->setEnabled( false );
1498     if ( m_exportAsText ) m_exportAsText->setEnabled( false );
1499     if ( m_exportAsDocArchive ) m_exportAsDocArchive->setEnabled( false );
1500     m_exportFormats.clear();
1501     if ( m_exportAs )
1502     {
1503         QMenu *menu = m_exportAs->menu();
1504         QList<QAction*> acts = menu->actions();
1505         int num = acts.count();
1506         for ( int i = 2; i < num; ++i )
1507         {
1508             menu->removeAction( acts.at(i) );
1509             delete acts.at(i);
1510         }
1511     }
1512     if ( m_showPresentation ) m_showPresentation->setEnabled( false );
1513     emit setWindowCaption("");
1514     emit enablePrintAction(false);
1515     m_realUrl = KUrl();
1516     if ( url().isLocalFile() )
1517     {
1518         m_watcher->removeFile( localFilePath() );
1519         QFileInfo fi(localFilePath());
1520         m_watcher->removeDir( fi.absolutePath() );
1521         if ( fi.isSymLink() ) m_watcher->removeFile( fi.readLink() );
1522     }
1523     m_fileWasRemoved = false;
1524     if ( m_generatorGuiClient )
1525         factory()->removeClient( m_generatorGuiClient );
1526     m_generatorGuiClient = 0;
1527     m_document->closeDocument();
1528     updateViewActions();
1529     delete m_tempfile;
1530     m_tempfile = 0;
1531     if ( widget() )
1532     {
1533         m_searchWidget->clearText();
1534         m_topMessage->setVisible( false );
1535         m_formsMessage->setVisible( false );
1536     }
1537 #ifdef OKULAR_KEEP_FILE_OPEN
1538     m_keeper->close();
1539 #endif
1540     bool r = KParts::ReadWritePart::closeUrl();
1541     setUrl(KUrl());
1542
1543     return r;
1544 }
1545
1546 bool Part::closeUrl()
1547 {
1548     return closeUrl( true );
1549 }
1550
1551 void Part::guiActivateEvent(KParts::GUIActivateEvent *event)
1552 {
1553     updateViewActions();
1554
1555     KParts::ReadWritePart::guiActivateEvent(event);
1556 }
1557
1558 void Part::close()
1559 {
1560     if ( m_embedMode == NativeShellMode )
1561     {
1562         closeUrl();
1563     }
1564     else KMessageBox::information( widget(), i18n( "This link points to a close document action that does not work when using the embedded viewer." ), QString(), "warnNoCloseIfNotInOkular" );
1565 }
1566
1567
1568 void Part::cannotQuit()
1569 {
1570     KMessageBox::information( widget(), i18n( "This link points to a quit application action that does not work when using the embedded viewer." ), QString(), "warnNoQuitIfNotInOkular" );
1571 }
1572
1573
1574 void Part::slotShowLeftPanel()
1575 {
1576     bool showLeft = m_showLeftPanel->isChecked();
1577     Okular::Settings::setShowLeftPanel( showLeft );
1578     Okular::Settings::self()->writeConfig();
1579     // show/hide left panel
1580     m_sidebar->setSidebarVisibility( showLeft );
1581 }
1582
1583 void Part::slotShowBottomBar()
1584 {
1585     const bool showBottom = m_showBottomBar->isChecked();
1586     Okular::Settings::setShowBottomBar( showBottom );
1587     Okular::Settings::self()->writeConfig();
1588     // show/hide bottom bar
1589     m_bottomBar->setVisible( showBottom );
1590 }
1591
1592 void Part::slotFileDirty( const QString& path )
1593 {
1594     // The beauty of this is that each start cancels the previous one.
1595     // This means that timeout() is only fired when there have
1596     // no changes to the file for the last 750 milisecs.
1597     // This ensures that we don't update on every other byte that gets
1598     // written to the file.
1599     if ( path == localFilePath() )
1600     {
1601         // Only start watching the file in case if it wasn't removed
1602         if (QFile::exists(localFilePath()))
1603             m_dirtyHandler->start( 750 );
1604         else
1605             m_fileWasRemoved = true;
1606     }
1607     else
1608     {
1609         const QFileInfo fi(localFilePath());
1610         if ( fi.absolutePath() == path )
1611         {
1612             // Our parent has been dirtified
1613             if (!QFile::exists(localFilePath()))
1614             {
1615                 m_fileWasRemoved = true;
1616             }
1617             else if (m_fileWasRemoved && QFile::exists(localFilePath()))
1618             {
1619                 // we need to watch the new file
1620                 m_watcher->removeFile(localFilePath());
1621                 m_watcher->addFile(localFilePath());
1622                 m_dirtyHandler->start( 750 );
1623             }
1624         }
1625         else if ( fi.isSymLink() && fi.readLink() == path )
1626         {
1627             if ( QFile::exists( fi.readLink() ))
1628                 m_dirtyHandler->start( 750 );
1629             else
1630                 m_fileWasRemoved = true;
1631         }
1632     }
1633 }
1634
1635
1636 void Part::slotDoFileDirty()
1637 {
1638     bool tocReloadPrepared = false;
1639     
1640     // do the following the first time the file is reloaded
1641     if ( m_viewportDirty.pageNumber == -1 )
1642     {
1643         // store the url of the current document
1644         m_oldUrl = url();
1645
1646         // store the current viewport
1647         m_viewportDirty = m_document->viewport();
1648
1649         // store the current toolbox pane
1650         m_dirtyToolboxIndex = m_sidebar->currentIndex();
1651         m_wasSidebarVisible = m_sidebar->isSidebarVisible();
1652         m_wasSidebarCollapsed = m_sidebar->isCollapsed();
1653
1654         // store if presentation view was open
1655         m_wasPresentationOpen = ((PresentationWidget*)m_presentationWidget != 0);
1656         
1657         // preserves the toc state after reload
1658         m_toc->prepareForReload();
1659         tocReloadPrepared = true;
1660
1661         // store the page rotation
1662         m_dirtyPageRotation = m_document->rotation();
1663
1664         // inform the user about the operation in progress
1665         // TODO: Remove this line and integrate reload info in queryClose
1666         m_pageView->displayMessage( i18n("Reloading the document...") );
1667     }
1668
1669     // close and (try to) reopen the document
1670     if ( !closeUrl() )
1671     {
1672         m_viewportDirty.pageNumber = -1;
1673
1674         if ( tocReloadPrepared ) 
1675         {
1676             m_toc->rollbackReload();
1677         }
1678         return;
1679     }
1680     
1681     if ( tocReloadPrepared )
1682         m_toc->finishReload();
1683
1684     // inform the user about the operation in progress
1685     m_pageView->displayMessage( i18n("Reloading the document...") );
1686
1687     if ( KParts::ReadWritePart::openUrl( m_oldUrl ) )
1688     {
1689         // on successful opening, restore the previous viewport
1690         if ( m_viewportDirty.pageNumber >= (int) m_document->pages() )
1691             m_viewportDirty.pageNumber = (int) m_document->pages() - 1;
1692         m_document->setViewport( m_viewportDirty );
1693         m_oldUrl = KUrl();
1694         m_viewportDirty.pageNumber = -1;
1695         m_document->setRotation( m_dirtyPageRotation );
1696         if ( m_sidebar->currentIndex() != m_dirtyToolboxIndex && m_sidebar->isItemEnabled( m_dirtyToolboxIndex )
1697             && !m_sidebar->isCollapsed() )
1698         {
1699             m_sidebar->setCurrentIndex( m_dirtyToolboxIndex );
1700         }
1701         if ( m_sidebar->isSidebarVisible() != m_wasSidebarVisible )
1702         {
1703             m_sidebar->setSidebarVisibility( m_wasSidebarVisible );
1704         }
1705         if ( m_sidebar->isCollapsed() != m_wasSidebarCollapsed )
1706         {
1707             m_sidebar->setCollapsed( m_wasSidebarCollapsed );
1708         }
1709         if (m_wasPresentationOpen) slotShowPresentation();
1710         emit enablePrintAction(true && m_document->printingSupport() != Okular::Document::NoPrinting);
1711     }
1712     else
1713     {
1714         // start watching the file again (since we dropped it on close) 
1715         addFileToWatcher( m_watcher, localFilePath() );
1716         m_dirtyHandler->start( 750 );
1717     }
1718 }
1719
1720
1721 void Part::updateViewActions()
1722 {
1723     bool opened = m_document->pages() > 0;
1724     if ( opened )
1725     {
1726         m_gotoPage->setEnabled( m_document->pages() > 1 );
1727         
1728         // Check if you are at the beginning or not
1729         if (m_document->currentPage() != 0)
1730         {
1731             m_beginningOfDocument->setEnabled( true );
1732             m_prevPage->setEnabled( true );
1733         }
1734         else 
1735         {
1736             if (m_pageView->verticalScrollBar()->value() != 0)
1737             {
1738                 // The page isn't at the very beginning
1739                 m_beginningOfDocument->setEnabled( true );
1740             }
1741             else
1742             {
1743                 // The page is at the very beginning of the document
1744                 m_beginningOfDocument->setEnabled( false );
1745             }
1746             // The document is at the first page, you can go to a page before
1747             m_prevPage->setEnabled( false );
1748         }
1749         
1750         if (m_document->pages() == m_document->currentPage() + 1 )
1751         {
1752             // If you are at the end, disable go to next page
1753             m_nextPage->setEnabled( false );
1754             if (m_pageView->verticalScrollBar()->value() == m_pageView->verticalScrollBar()->maximum())
1755             {
1756                 // If you are the end of the page of the last document, you can't go to the last page
1757                 m_endOfDocument->setEnabled( false );
1758             }
1759             else 
1760             {
1761                 // Otherwise you can move to the endif
1762                 m_endOfDocument->setEnabled( true );
1763             }
1764         }
1765         else 
1766         {
1767             // If you are not at the end, enable go to next page
1768             m_nextPage->setEnabled( true );
1769             m_endOfDocument->setEnabled( true );
1770         }
1771
1772         if (m_historyBack) m_historyBack->setEnabled( !m_document->historyAtBegin() );
1773         if (m_historyNext) m_historyNext->setEnabled( !m_document->historyAtEnd() );
1774         m_reload->setEnabled( true );
1775         if (m_copy) m_copy->setEnabled( true );
1776         if (m_selectAll) m_selectAll->setEnabled( true );
1777     }
1778     else
1779     {
1780         m_gotoPage->setEnabled( false );
1781         m_beginningOfDocument->setEnabled( false );
1782         m_endOfDocument->setEnabled( false );
1783         m_prevPage->setEnabled( false );
1784         m_nextPage->setEnabled( false );
1785         if (m_historyBack) m_historyBack->setEnabled( false );
1786         if (m_historyNext) m_historyNext->setEnabled( false );
1787         m_reload->setEnabled( false );
1788         if (m_copy) m_copy->setEnabled( false );
1789         if (m_selectAll) m_selectAll->setEnabled( false );
1790     }
1791
1792     if ( factory() )
1793     {
1794         QWidget *menu = factory()->container("menu_okular_part_viewer", this);
1795         if (menu) menu->setEnabled( opened );
1796
1797         menu = factory()->container("view_orientation", this);
1798         if (menu) menu->setEnabled( opened );
1799     }
1800     emit viewerMenuStateChange( opened );
1801
1802     updateBookmarksActions();
1803 }
1804
1805
1806 void Part::updateBookmarksActions()
1807 {
1808     bool opened = m_document->pages() > 0;
1809     if ( opened )
1810     {
1811         m_addBookmark->setEnabled( true );
1812         if ( m_document->bookmarkManager()->isBookmarked( m_document->viewport() ) )
1813         {
1814             m_addBookmark->setText( i18n( "Remove Bookmark" ) );
1815             m_addBookmark->setIcon( KIcon( "edit-delete-bookmark" ) );
1816             m_renameBookmark->setEnabled( true );
1817         }
1818         else
1819         {
1820             m_addBookmark->setText( m_addBookmarkText );
1821             m_addBookmark->setIcon( m_addBookmarkIcon );
1822             m_renameBookmark->setEnabled( false );
1823         }
1824     }
1825     else
1826     {
1827         m_addBookmark->setEnabled( false );
1828         m_addBookmark->setText( m_addBookmarkText );
1829         m_addBookmark->setIcon( m_addBookmarkIcon );
1830         m_renameBookmark->setEnabled( false );
1831     }
1832 }
1833
1834
1835 void Part::enableTOC(bool enable)
1836 {
1837     m_sidebar->setItemEnabled(0, enable);
1838
1839     // If present, show the TOC when a document is opened
1840     if ( enable && m_sidebar->currentIndex() != 0 )
1841     {
1842         m_sidebar->setCurrentIndex( 0, Sidebar::DoNotUncollapseIfCollapsed );
1843     }
1844 }
1845
1846 void Part::slotRebuildBookmarkMenu()
1847 {
1848     rebuildBookmarkMenu();
1849 }
1850
1851 void Part::slotShowFindBar()
1852 {
1853     m_findBar->show();
1854     m_findBar->focusAndSetCursor();
1855     m_closeFindBar->setEnabled( true );
1856 }
1857
1858 void Part::slotHideFindBar()
1859 {
1860     if ( m_findBar->maybeHide() )
1861     {
1862         m_pageView->setFocus();
1863         m_closeFindBar->setEnabled( false );
1864     }
1865 }
1866
1867 //BEGIN go to page dialog
1868 class GotoPageDialog : public KDialog
1869 {
1870     public:
1871         GotoPageDialog(QWidget *p, int current, int max) : KDialog(p)
1872         {
1873             setCaption(i18n("Go to Page"));
1874             setButtons(Ok | Cancel);
1875             setDefaultButton(Ok);
1876
1877             QWidget *w = new QWidget(this);
1878             setMainWidget(w);
1879
1880             QVBoxLayout *topLayout = new QVBoxLayout(w);
1881             topLayout->setMargin(0);
1882             topLayout->setSpacing(spacingHint());
1883             e1 = new KIntNumInput(current, w);
1884             e1->setRange(1, max);
1885             e1->setEditFocus(true);
1886             e1->setSliderEnabled(true);
1887
1888             QLabel *label = new QLabel(i18n("&Page:"), w);
1889             label->setBuddy(e1);
1890             topLayout->addWidget(label);
1891             topLayout->addWidget(e1);
1892                                  // A little bit extra space
1893             topLayout->addSpacing(spacingHint());
1894             topLayout->addStretch(10);
1895             e1->setFocus();
1896         }
1897
1898         int getPage() const
1899         {
1900             return e1->value();
1901         }
1902
1903     protected:
1904         KIntNumInput *e1;
1905 };
1906 //END go to page dialog
1907
1908 void Part::slotGoToPage()
1909 {
1910     GotoPageDialog pageDialog( m_pageView, m_document->currentPage() + 1, m_document->pages() );
1911     if ( pageDialog.exec() == QDialog::Accepted )
1912         m_document->setViewportPage( pageDialog.getPage() - 1 );
1913 }
1914
1915
1916 void Part::slotPreviousPage()
1917 {
1918     if ( m_document->isOpened() && !(m_document->currentPage() < 1) )
1919         m_document->setViewportPage( m_document->currentPage() - 1 );
1920 }
1921
1922
1923 void Part::slotNextPage()
1924 {
1925     if ( m_document->isOpened() && m_document->currentPage() < (m_document->pages() - 1) )
1926         m_document->setViewportPage( m_document->currentPage() + 1 );
1927 }
1928
1929
1930 void Part::slotGotoFirst()
1931 {
1932     if ( m_document->isOpened() ) {
1933         m_document->setViewportPage( 0 );
1934         m_beginningOfDocument->setEnabled( false );
1935     }
1936 }
1937
1938
1939 void Part::slotGotoLast()
1940 {
1941     if ( m_document->isOpened() )
1942     {
1943         DocumentViewport endPage(m_document->pages() -1 );
1944         endPage.rePos.enabled = true;
1945         endPage.rePos.normalizedX = 0;
1946         endPage.rePos.normalizedY = 1;
1947         endPage.rePos.pos = Okular::DocumentViewport::TopLeft;
1948         m_document->setViewport(endPage);
1949         m_endOfDocument->setEnabled(false);
1950     }
1951 }
1952
1953
1954 void Part::slotHistoryBack()
1955 {
1956     m_document->setPrevViewport();
1957 }
1958
1959
1960 void Part::slotHistoryNext()
1961 {
1962     m_document->setNextViewport();
1963 }
1964
1965
1966 void Part::slotAddBookmark()
1967 {
1968     DocumentViewport vp = m_document->viewport();
1969     if ( m_document->bookmarkManager()->isBookmarked( vp ) )
1970     {
1971         m_document->bookmarkManager()->removeBookmark( vp );
1972     }
1973     else
1974     {
1975         m_document->bookmarkManager()->addBookmark( vp );
1976     }
1977 }
1978
1979 void Part::slotRenameBookmark( const DocumentViewport &viewport )
1980 {
1981     Q_ASSERT(m_document->bookmarkManager()->isBookmarked( viewport ));
1982     if ( m_document->bookmarkManager()->isBookmarked( viewport ) )
1983     {
1984         KBookmark bookmark = m_document->bookmarkManager()->bookmark( viewport );
1985         const QString newName = KInputDialog::getText( i18n( "Rename Bookmark" ), i18n( "Enter the new name of the bookmark:" ), bookmark.fullText(), 0, widget());
1986         if (!newName.isEmpty())
1987         {
1988             m_document->bookmarkManager()->renameBookmark(&bookmark, newName);
1989         }
1990     }
1991 }
1992
1993 void Part::slotRenameBookmarkFromMenu()
1994 {
1995     QAction *action = qobject_cast<QAction *>(sender());
1996     Q_ASSERT( action );
1997     if ( action )
1998     {
1999         DocumentViewport vp( action->data().toString() );
2000         slotRenameBookmark( vp );
2001     }
2002 }
2003
2004 void Part::slotRenameCurrentViewportBookmark()
2005 {
2006     slotRenameBookmark( m_document->viewport() );
2007 }
2008
2009 void Part::slotAboutToShowContextMenu(KMenu * /*menu*/, QAction *action, QMenu *contextMenu)
2010 {
2011     const QList<QAction*> actions = contextMenu->findChildren<QAction*>("OkularPrivateRenameBookmarkActions");
2012     foreach(QAction *a, actions)
2013     {
2014         contextMenu->removeAction(a);
2015         delete a;
2016     }
2017
2018     KBookmarkAction *ba = qobject_cast<KBookmarkAction*>(action);
2019     if (ba != NULL)
2020     {
2021         QAction *separatorAction = contextMenu->addSeparator();
2022         separatorAction->setObjectName("OkularPrivateRenameBookmarkActions");
2023         QAction *renameAction = contextMenu->addAction( KIcon( "edit-rename" ), i18n( "Rename this Bookmark" ), this, SLOT(slotRenameBookmarkFromMenu()) );
2024         renameAction->setData(ba->property("htmlRef").toString());
2025         renameAction->setObjectName("OkularPrivateRenameBookmarkActions");
2026     }
2027 }
2028
2029 void Part::slotPreviousBookmark()
2030 {
2031     const KBookmark bookmark = m_document->bookmarkManager()->previousBookmark( m_document->viewport() );
2032
2033     if ( !bookmark.isNull() )
2034     {
2035         DocumentViewport vp( bookmark.url().fragment() );
2036         m_document->setViewport( vp );
2037     }
2038 }
2039
2040
2041 void Part::slotNextBookmark()
2042 {
2043     const KBookmark bookmark = m_document->bookmarkManager()->nextBookmark( m_document->viewport() );
2044
2045     if ( !bookmark.isNull() )
2046     {
2047         DocumentViewport vp( bookmark.url().fragment() );
2048         m_document->setViewport( vp );
2049     }
2050 }
2051
2052
2053 void Part::slotFind()
2054 {
2055     // when in presentation mode, there's already a search bar, taking care of
2056     // the 'find' requests
2057     if ( (PresentationWidget*)m_presentationWidget != 0 )
2058     {
2059         m_presentationWidget->slotFind();
2060     }
2061     else
2062     {
2063         slotShowFindBar();
2064     }
2065 }
2066
2067
2068 void Part::slotFindNext()
2069 {
2070     if (m_findBar->isHidden())
2071         slotShowFindBar();
2072     else
2073         m_findBar->findNext();
2074 }
2075
2076
2077 void Part::slotFindPrev()
2078 {
2079     if (m_findBar->isHidden())
2080         slotShowFindBar();
2081     else
2082         m_findBar->findPrev();
2083 }
2084
2085 bool Part::saveFile()
2086 {
2087     kDebug() << "Okular part doesn't support saving the file in the location from which it was opened";
2088     return false;
2089 }
2090
2091 void Part::slotSaveFileAs()
2092 {
2093     if ( m_embedMode == PrintPreviewMode )
2094        return;
2095
2096     /* Show a warning before saving if the generator can't save annotations,
2097      * unless we are going to save a .okular archive. */
2098     if ( !isDocumentArchive && !m_document->canSaveChanges( Document::SaveAnnotationsCapability ) )
2099     {
2100         /* Search local annotations */
2101         bool containsLocalAnnotations = false;
2102         const int pagecount = m_document->pages();
2103
2104         for ( int pageno = 0; pageno < pagecount; ++pageno )
2105         {
2106             const Okular::Page *page = m_document->page( pageno );
2107             foreach ( const Okular::Annotation *ann, page->annotations() )
2108             {
2109                 if ( !(ann->flags() & Okular::Annotation::External) )
2110                 {
2111                     containsLocalAnnotations = true;
2112                     break;
2113                 }
2114             }
2115             if ( containsLocalAnnotations )
2116                 break;
2117         }
2118
2119         /* Don't show it if there are no local annotations */
2120         if ( containsLocalAnnotations )
2121         {
2122             int res = KMessageBox::warningContinueCancel( widget(), i18n("Your annotations will not be exported.\nYou can export the annotated document using File -> Export As -> Document Archive") );
2123             if ( res != KMessageBox::Continue )
2124                 return; // Canceled
2125         }
2126     }
2127
2128     KUrl saveUrl = KFileDialog::getSaveUrl( url(),
2129                                             QString(), widget(), QString(),
2130                                             KFileDialog::ConfirmOverwrite );
2131     if ( !saveUrl.isValid() || saveUrl.isEmpty() )
2132         return;
2133
2134     saveAs( saveUrl );
2135 }
2136
2137 bool Part::saveAs( const KUrl & saveUrl )
2138 {
2139     KTemporaryFile tf;
2140     QString fileName;
2141     if ( !tf.open() )
2142     {
2143         KMessageBox::information( widget(), i18n("Could not open the temporary file for saving." ) );
2144             return false;
2145     }
2146     fileName = tf.fileName();
2147     tf.close();
2148
2149     QString errorText;
2150     bool saved;
2151
2152     if ( isDocumentArchive )
2153         saved = m_document->saveDocumentArchive( fileName );
2154     else
2155         saved = m_document->saveChanges( fileName, &errorText );
2156
2157     if ( !saved )
2158     {
2159         if (errorText.isEmpty())
2160         {
2161             KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", fileName ) );
2162         }
2163         else
2164         {
2165             KMessageBox::information( widget(), i18n("File could not be saved in '%1'. %2", fileName, errorText ) );
2166         }
2167         return false;
2168     }
2169
2170     KIO::Job *copyJob = KIO::file_copy( fileName, saveUrl, -1, KIO::Overwrite );
2171     if ( !KIO::NetAccess::synchronousRun( copyJob, widget() ) )
2172     {
2173         KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", saveUrl.prettyUrl() ) );
2174         return false;
2175     }
2176
2177     setModified( false );
2178     return true;
2179 }
2180
2181
2182 void Part::slotSaveCopyAs()
2183 {
2184     if ( m_embedMode == PrintPreviewMode )
2185        return;
2186
2187     KUrl saveUrl = KFileDialog::getSaveUrl( KUrl("kfiledialog:///okular/" + url().fileName()),
2188                                             QString(), widget(), QString(),
2189                                             KFileDialog::ConfirmOverwrite );
2190     if ( saveUrl.isValid() && !saveUrl.isEmpty() )
2191     {
2192         // make use of the already downloaded (in case of remote URLs) file,
2193         // no point in downloading that again
2194         KUrl srcUrl = KUrl::fromPath( localFilePath() );
2195         KTemporaryFile * tempFile = 0;
2196         // duh, our local file disappeared...
2197         if ( !QFile::exists( localFilePath() ) )
2198         {
2199             if ( url().isLocalFile() )
2200             {
2201 #ifdef OKULAR_KEEP_FILE_OPEN
2202                 // local file: try to get it back from the open handle on it
2203                 if ( ( tempFile = m_keeper->copyToTemporary() ) )
2204                     srcUrl = KUrl::fromPath( tempFile->fileName() );
2205 #else
2206                 const QString msg = i18n( "Okular cannot copy %1 to the specified location.\n\nThe document does not exist anymore.", localFilePath() );
2207                 KMessageBox::sorry( widget(), msg );
2208                 return;
2209 #endif
2210             }
2211             else
2212             {
2213                 // we still have the original remote URL of the document,
2214                 // so copy the document from there
2215                 srcUrl = url();
2216             }
2217         }
2218
2219         KIO::Job *copyJob = KIO::file_copy( srcUrl, saveUrl, -1, KIO::Overwrite );
2220         if ( !KIO::NetAccess::synchronousRun( copyJob, widget() ) )
2221             KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", saveUrl.prettyUrl() ) );
2222
2223         delete tempFile;
2224     }
2225 }
2226
2227
2228 void Part::slotPreferences()
2229 {
2230     // Create dialog
2231     PreferencesDialog * dialog = new PreferencesDialog( m_pageView, Okular::Settings::self(), m_embedMode );
2232     dialog->setAttribute( Qt::WA_DeleteOnClose );
2233
2234     // Show it
2235     dialog->show();
2236 }
2237
2238
2239 void Part::slotAnnotationPreferences()
2240 {
2241     // Create dialog
2242     PreferencesDialog * dialog = new PreferencesDialog( m_pageView, Okular::Settings::self(), m_embedMode );
2243     dialog->setAttribute( Qt::WA_DeleteOnClose );
2244
2245     // Show it
2246     dialog->switchToAnnotationsPage();
2247     dialog->show();
2248 }
2249
2250
2251 void Part::slotNewConfig()
2252 {
2253     // Apply settings here. A good policy is to check whether the setting has
2254     // changed before applying changes.
2255
2256     // Watch File
2257     setWatchFileModeEnabled(Okular::Settings::watchFile());
2258
2259     // Main View (pageView)
2260     m_pageView->reparseConfig();
2261
2262     // update document settings
2263     m_document->reparseConfig();
2264
2265     // update TOC settings
2266     if ( m_sidebar->isItemEnabled(0) )
2267         m_toc->reparseConfig();
2268
2269     // update ThumbnailList contents
2270     if ( Okular::Settings::showLeftPanel() && !m_thumbnailList->isHidden() )
2271         m_thumbnailList->updateWidgets();
2272
2273     // update Reviews settings
2274     if ( m_sidebar->isItemEnabled(2) )
2275         m_reviewsWidget->reparseConfig();
2276
2277     setWindowTitleFromDocument ();
2278 }
2279
2280
2281 void Part::slotPrintPreview()
2282 {
2283     if (m_document->pages() == 0) return;
2284
2285     QPrinter printer;
2286
2287     // Native printing supports QPrintPreviewDialog
2288     if ( m_document->printingSupport() == Okular::Document::NativePrinting )
2289     {
2290         QPrintPreviewDialog previewdlg( &printer, widget() );
2291         setupPrint( printer );
2292         connect( &previewdlg, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPrintRequested(QPrinter*)) );
2293         previewdlg.exec();
2294     }
2295     else
2296     {
2297         kWarning() << "non-native printing not supported";
2298     }
2299 }
2300
2301
2302 void Part::slotShowMenu(const Okular::Page *page, const QPoint &point)
2303 {
2304     if ( m_embedMode == PrintPreviewMode )
2305        return;
2306
2307     bool reallyShow = false;
2308     const bool currentPage = page && page->number() == m_document->viewport().pageNumber;
2309
2310     if (!m_actionsSearched)
2311     {
2312         // the quest for options_show_menubar
2313         KActionCollection *ac;
2314         QAction *act;
2315
2316         if (factory())
2317         {
2318             const QList<KXMLGUIClient*> clients(factory()->clients());
2319             for(int i = 0 ; (!m_showMenuBarAction || !m_showFullScreenAction) && i < clients.size(); ++i)
2320             {
2321                 ac = clients.at(i)->actionCollection();
2322                 // show_menubar
2323                 act = ac->action("options_show_menubar");
2324                 if (act && qobject_cast<KToggleAction*>(act))
2325                     m_showMenuBarAction = qobject_cast<KToggleAction*>(act);
2326                 // fullscreen
2327                 act = ac->action("fullscreen");
2328                 if (act && qobject_cast<KToggleFullScreenAction*>(act))
2329                     m_showFullScreenAction = qobject_cast<KToggleFullScreenAction*>(act);
2330             }
2331         }
2332         m_actionsSearched = true;
2333     }
2334
2335     KMenu *popup = new KMenu( widget() );
2336     QAction *addBookmark = 0;
2337     QAction *removeBookmark = 0;
2338     QAction *fitPageWidth = 0;
2339     if (page)
2340     {
2341         popup->addTitle( i18n( "Page %1", page->number() + 1 ) );
2342         if ( ( !currentPage && m_document->bookmarkManager()->isBookmarked( page->number() ) ) ||
2343                 ( currentPage && m_document->bookmarkManager()->isBookmarked( m_document->viewport() ) ) )
2344             removeBookmark = popup->addAction( KIcon("edit-delete-bookmark"), i18n("Remove Bookmark") );
2345         else
2346             addBookmark = popup->addAction( KIcon("bookmark-new"), i18n("Add Bookmark") );
2347         if ( m_pageView->canFitPageWidth() )
2348             fitPageWidth = popup->addAction( KIcon("zoom-fit-best"), i18n("Fit Width") );
2349         popup->addAction( m_prevBookmark );
2350         popup->addAction( m_nextBookmark );
2351         reallyShow = true;
2352     }
2353     /*
2354         //Albert says: I have not ported this as i don't see it does anything
2355         if ( d->mouseOnRect ) // and rect->objectType() == ObjectRect::Image ...
2356         {
2357             m_popup->insertItem( SmallIcon("document-save"), i18n("Save Image..."), 4 );
2358             m_popup->setItemEnabled( 4, false );
2359     }*/
2360
2361     if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked()))
2362     {
2363         popup->addTitle( i18n( "Tools" ) );
2364         if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) popup->addAction(m_showMenuBarAction);
2365         if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) popup->addAction(m_showFullScreenAction);
2366         reallyShow = true;
2367
2368     }
2369
2370     if (reallyShow)
2371     {
2372         QAction *res = popup->exec(point);
2373         if (res)
2374         {
2375             if (res == addBookmark)
2376             {
2377                 if (currentPage)
2378                     m_document->bookmarkManager()->addBookmark( m_document->viewport() );
2379                 else
2380                     m_document->bookmarkManager()->addBookmark( page->number() );
2381             }
2382             else if (res == removeBookmark)
2383             {
2384                 if (currentPage)
2385                     m_document->bookmarkManager()->removeBookmark( m_document->viewport() );
2386                 else
2387                     m_document->bookmarkManager()->removeBookmark( page->number() );
2388             }
2389             else if (res == fitPageWidth)
2390             {
2391                 m_pageView->fitPageWidth( page->number() );
2392             }
2393         }
2394     }
2395     delete popup;
2396 }
2397
2398
2399 void Part::slotShowProperties()
2400 {
2401     PropertiesDialog *d = new PropertiesDialog(widget(), m_document);
2402     d->exec();
2403     delete d;
2404 }
2405
2406
2407 void Part::slotShowEmbeddedFiles()
2408 {
2409     EmbeddedFilesDialog *d = new EmbeddedFilesDialog(widget(), m_document);
2410     d->exec();
2411     delete d;
2412 }
2413
2414
2415 void Part::slotShowPresentation()
2416 {
2417     if ( !m_presentationWidget )
2418     {
2419         m_presentationWidget = new PresentationWidget( widget(), m_document, actionCollection() );
2420     }
2421 }
2422
2423
2424 void Part::slotHidePresentation()
2425 {
2426     if ( m_presentationWidget )
2427         delete (PresentationWidget*) m_presentationWidget;
2428 }
2429
2430
2431 void Part::slotTogglePresentation()
2432 {
2433     if ( m_document->isOpened() )
2434     {
2435         if ( !m_presentationWidget )
2436             m_presentationWidget = new PresentationWidget( widget(), m_document, actionCollection() );
2437         else delete (PresentationWidget*) m_presentationWidget;
2438     }
2439 }
2440
2441
2442 void Part::reload()
2443 {
2444     if ( m_document->isOpened() )
2445     {
2446         slotReload();
2447     }
2448 }
2449
2450 void Part::enableStartWithPrint()
2451 {
2452     m_cliPrint = true;
2453 }
2454
2455 void Part::slotAboutBackend()
2456 {
2457     const KComponentData *data = m_document->componentData();
2458     if ( !data )
2459         return;
2460
2461     KAboutData aboutData( *data->aboutData() );
2462
2463     if ( aboutData.programIconName().isEmpty() || aboutData.programIconName() == aboutData.appName() )
2464     {
2465         if ( const Okular::DocumentInfo *documentInfo = m_document->documentInfo() )
2466         {
2467             const QString mimeTypeName = documentInfo->get("mimeType");
2468             if ( !mimeTypeName.isEmpty() )
2469             {
2470                 if ( KMimeType::Ptr type = KMimeType::mimeType( mimeTypeName ) )
2471                     aboutData.setProgramIconName( type->iconName() );
2472             }
2473         }
2474     }
2475
2476     KAboutApplicationDialog dlg( &aboutData, widget() );
2477     dlg.exec();
2478 }
2479
2480
2481 void Part::slotExportAs(QAction * act)
2482 {
2483     QList<QAction*> acts = m_exportAs->menu() ? m_exportAs->menu()->actions() : QList<QAction*>();
2484     int id = acts.indexOf( act );
2485     if ( ( id < 0 ) || ( id >= acts.count() ) )
2486         return;
2487
2488     QString filter;
2489     switch ( id )
2490     {
2491         case 0:
2492             filter = "text/plain";
2493             break;
2494         case 1:
2495             filter = "application/vnd.kde.okular-archive";
2496             break;
2497         default:
2498             filter = m_exportFormats.at( id - 2 ).mimeType()->name();
2499             break;
2500     }
2501     QString fileName = KFileDialog::getSaveFileName( url().isLocalFile() ? url().directory() : QString(),
2502                                                      filter, widget(), QString(),
2503                                                      KFileDialog::ConfirmOverwrite );
2504     if ( !fileName.isEmpty() )
2505     {
2506         bool saved = false;
2507         switch ( id )
2508         {
2509             case 0:
2510                 saved = m_document->exportToText( fileName );
2511                 break;
2512             case 1:
2513                 saved = m_document->saveDocumentArchive( fileName );
2514                 break;
2515             default:
2516                 saved = m_document->exportTo( fileName, m_exportFormats.at( id - 2 ) );
2517                 break;
2518         }
2519         if ( !saved )
2520             KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", fileName ) );
2521     }
2522 }
2523
2524
2525 void Part::slotReload()
2526 {
2527     // stop the dirty handler timer, otherwise we may conflict with the
2528     // auto-refresh system
2529     m_dirtyHandler->stop();
2530
2531     slotDoFileDirty();
2532 }
2533
2534
2535 void Part::slotPrint()
2536 {
2537     if (m_document->pages() == 0) return;
2538
2539     QPrinter printer;
2540     QPrintDialog *printDialog = 0;
2541     QWidget *printConfigWidget = 0;
2542
2543     // Must do certain QPrinter setup before creating QPrintDialog
2544     setupPrint( printer );
2545
2546     // Create the Print Dialog with extra config widgets if required
2547     if ( m_document->canConfigurePrinter() )
2548     {
2549         printConfigWidget = m_document->printConfigurationWidget();
2550     }
2551     if ( printConfigWidget )
2552     {
2553         printDialog = KdePrint::createPrintDialog( &printer, QList<QWidget*>() << printConfigWidget, widget() );
2554     }
2555     else
2556     {
2557         printDialog = KdePrint::createPrintDialog( &printer, widget() );
2558     }
2559
2560     if ( printDialog )
2561     {
2562
2563         // Set the available Print Range
2564         printDialog->setMinMax( 1, m_document->pages() );
2565         printDialog->setFromTo( 1, m_document->pages() );
2566
2567         // If the user has bookmarked pages for printing, then enable Selection
2568         if ( !m_document->bookmarkedPageRange().isEmpty() )
2569         {
2570             printDialog->addEnabledOption( QAbstractPrintDialog::PrintSelection );
2571         }
2572
2573         // Enable the Current Page option in the dialog.
2574         if ( m_document->pages() > 1 && currentPage() > 0 )
2575         {
2576             printDialog->setOption( QAbstractPrintDialog::PrintCurrentPage );
2577         }
2578
2579         if ( printDialog->exec() )
2580             doPrint( printer );
2581         delete printDialog;
2582     }
2583 }
2584
2585
2586 void Part::setupPrint( QPrinter &printer )
2587 {
2588     printer.setOrientation(m_document->orientation());
2589
2590     // title
2591     QString title = m_document->metaData( "DocumentTitle" ).toString();
2592     if ( title.isEmpty() )
2593     {
2594         title = m_document->currentDocument().fileName();
2595     }
2596     if ( !title.isEmpty() )
2597     {
2598         printer.setDocName( title );
2599     }
2600 }
2601
2602 void Part::slotPrintRequested(QPrinter *printer)
2603 {
2604     doPrint(*printer);
2605 }
2606
2607 void Part::doPrint(QPrinter &printer)
2608 {
2609     if (!m_document->isAllowed(Okular::AllowPrint))
2610     {
2611         KMessageBox::error(widget(), i18n("Printing this document is not allowed."));
2612         return;
2613     }
2614
2615     if (!m_document->print(printer))
2616     {
2617         const QString error = m_document->printError();
2618         if (error.isEmpty())
2619         {
2620             KMessageBox::error(widget(), i18n("Could not print the document. Unknown error. Please report to bugs.kde.org"));
2621         }
2622         else
2623         {
2624             KMessageBox::error(widget(), i18n("Could not print the document. Detailed error is \"%1\". Please report to bugs.kde.org", error));
2625         }
2626     }
2627 }
2628
2629
2630 void Part::restoreDocument(const KConfigGroup &group)
2631 {
2632     KUrl url ( group.readPathEntry( "URL", QString() ) );
2633     if ( url.isValid() )
2634     {
2635         QString viewport = group.readEntry( "Viewport" );
2636         if (!viewport.isEmpty()) m_document->setNextDocumentViewport( Okular::DocumentViewport( viewport ) );
2637         openUrl( url );
2638     }
2639 }
2640
2641
2642 void Part::saveDocumentRestoreInfo(KConfigGroup &group)
2643 {
2644     group.writePathEntry( "URL", url().url() );
2645     group.writeEntry( "Viewport", m_document->viewport().toString() );
2646 }
2647
2648 void Part::displayInfoMessage( const QString &message, KMessageWidget::MessageType messageType, int duration )
2649 {
2650     if ( !Okular::Settings::showOSD() )
2651     {
2652         if (messageType == KMessageWidget::Error)
2653         {
2654             KMessageBox::error( widget(), message );
2655         }
2656         return;
2657     }
2658
2659     // hide messageWindow if string is empty
2660     if ( message.isEmpty() )
2661         m_infoMessage->animatedHide();
2662
2663     // display message (duration is length dependant)
2664     if ( duration < 0 )
2665     {
2666         duration = 500 + 100 * message.length();
2667     }
2668     m_infoTimer->start( duration );
2669     m_infoMessage->setText( message );
2670     m_infoMessage->setMessageType( messageType );
2671     m_infoMessage->setVisible( true );
2672 }
2673
2674
2675 void Part::errorMessage( const QString &message, int duration )
2676 {
2677     displayInfoMessage( message, KMessageWidget::Error, duration );
2678 }
2679
2680 void Part::warningMessage( const QString &message, int duration )
2681 {
2682     displayInfoMessage( message, KMessageWidget::Warning, duration );
2683 }
2684
2685 void Part::noticeMessage( const QString &message, int duration )
2686 {
2687     // less important message -> simpleer display widget in the PageView
2688     m_pageView->displayMessage( message, QString(), PageViewMessage::Info, duration );
2689 }
2690
2691
2692 void Part::unsetDummyMode()
2693 {
2694     if ( m_embedMode == PrintPreviewMode )
2695        return;
2696
2697     m_sidebar->setItemEnabled( 2, true );
2698     m_sidebar->setItemEnabled( 3, true );
2699     m_sidebar->setSidebarVisibility( Okular::Settings::showLeftPanel() );
2700
2701     // add back and next in history
2702     m_historyBack = KStandardAction::documentBack( this, SLOT(slotHistoryBack()), actionCollection() );
2703     m_historyBack->setWhatsThis( i18n( "Go to the place you were before" ) );
2704
2705     m_historyNext = KStandardAction::documentForward( this, SLOT(slotHistoryNext()), actionCollection());
2706     m_historyNext->setWhatsThis( i18n( "Go to the place you were after" ) );
2707
2708     m_pageView->setupActions( actionCollection() );
2709
2710     // attach the actions of the children widgets too
2711     m_formsMessage->addAction( m_pageView->toggleFormsAction() );
2712     m_formsMessage->setVisible( m_pageView->toggleFormsAction() != 0 );
2713
2714     // ensure history actions are in the correct state
2715     updateViewActions();
2716 }
2717
2718
2719 bool Part::handleCompressed( QString &destpath, const QString &path, const QString &compressedMimetype )
2720 {
2721     m_tempfile = 0;
2722
2723     // we are working with a compressed file, decompressing
2724     // temporary file for decompressing
2725     KTemporaryFile *newtempfile = new KTemporaryFile();
2726     newtempfile->setAutoRemove(true);
2727
2728     if ( !newtempfile->open() )
2729     {
2730         KMessageBox::error( widget(),
2731             i18n("<qt><strong>File Error!</strong> Could not create temporary file "
2732             "<nobr><strong>%1</strong></nobr>.</qt>",
2733             strerror(newtempfile->error())));
2734         delete newtempfile;
2735         return false;
2736     }
2737
2738     // decompression file
2739     QFile pathfile(path);
2740     KDecompressor kdecompressor;
2741     if ( !pathfile.open(QFile::ReadOnly) || !kdecompressor.setType(KDecompressor::typeForMime(compressedMimetype)) )
2742     {
2743         KMessageBox::detailedError( widget(),
2744             i18n("<qt><strong>File Error!</strong> Could not open the file "
2745             "<nobr><strong>%1</strong></nobr> for uncompression. "
2746             "The file will not be loaded.</qt>", path),
2747             i18n("<qt>This error typically occurs if you do "
2748             "not have enough permissions to read the file. "
2749             "You can check ownership and permissions if you "
2750             "right-click on the file in the Dolphin "
2751             "file manager and then choose the 'Properties' tab.</qt>"));
2752
2753         delete newtempfile;
2754         return false;
2755     }
2756
2757     if (!kdecompressor.process(pathfile.readAll()))
2758     {
2759         KMessageBox::detailedError(widget(),
2760             i18n("<qt><strong>File Error!</strong> Could not uncompress "
2761             "the file <nobr><strong>%1</strong></nobr>. "
2762             "The file will not be loaded.</qt>", path ),
2763             i18n("<qt>This error typically occurs if the file is corrupt. "
2764             "If you want to be sure, try to decompress the file manually "
2765             "using command-line tools.</qt>"));
2766         delete newtempfile;
2767         return false;
2768     }
2769
2770     const QByteArray uncompressed = kdecompressor.result();
2771     if (newtempfile->write(uncompressed.constData(), uncompressed.size()) != uncompressed.size())
2772     {
2773         KMessageBox::detailedError(widget(),
2774             i18n("<qt><strong>File Error!</strong> Could not write uncompressed data to"
2775             "the file <nobr><strong>%1</strong></nobr>. "
2776             "The file will not be loaded.</qt>", path ),
2777             i18n("<qt>This error typically occurs if there is not enough space. "
2778             "If you want to be sure, try to decompress the file manually "
2779             "using command-line tools.</qt>"));
2780         delete newtempfile;
2781         return false;
2782     }
2783
2784     m_tempfile = newtempfile;
2785     destpath = m_tempfile->fileName();
2786     return true;
2787 }
2788
2789 void Part::rebuildBookmarkMenu( bool unplugActions )
2790 {
2791     if ( unplugActions )
2792     {
2793         unplugActionList( "bookmarks_currentdocument" );
2794         qDeleteAll( m_bookmarkActions );
2795         m_bookmarkActions.clear();
2796     }
2797     KUrl u = m_document->currentDocument();
2798     if ( u.isValid() )
2799     {
2800         m_bookmarkActions = m_document->bookmarkManager()->actionsForUrl( u );
2801     }
2802     bool havebookmarks = true;
2803     if ( m_bookmarkActions.isEmpty() )
2804     {
2805         havebookmarks = false;
2806         QAction * a = new KAction( 0 );
2807         a->setText( i18n( "No Bookmarks" ) );
2808         a->setEnabled( false );
2809         m_bookmarkActions.append( a );
2810     }
2811     plugActionList( "bookmarks_currentdocument", m_bookmarkActions );
2812     
2813     if (factory())
2814     {
2815         const QList<KXMLGUIClient*> clients(factory()->clients());
2816         bool containerFound = false;
2817         for (int i = 0; !containerFound && i < clients.size(); ++i)
2818         {
2819             QWidget *container = factory()->container("bookmarks", clients[i]);
2820             if (container && container->actions().contains(m_bookmarkActions.first()))
2821             {
2822                 Q_ASSERT(qobject_cast<KMenu*>(container));
2823                 disconnect(container, 0, this, 0);
2824                 connect(container, SIGNAL(aboutToShowContextMenu(KMenu*,QAction*,QMenu*)), this, SLOT(slotAboutToShowContextMenu(KMenu*,QAction*,QMenu*)));
2825                 containerFound = true;
2826             }
2827         }
2828     }
2829
2830     m_prevBookmark->setEnabled( havebookmarks );
2831     m_nextBookmark->setEnabled( havebookmarks );
2832 }
2833
2834 void Part::updateAboutBackendAction()
2835 {
2836     const KComponentData *data = m_document->componentData();
2837     if ( data )
2838     {
2839         m_aboutBackend->setEnabled( true );
2840     }
2841     else
2842     {
2843         m_aboutBackend->setEnabled( false );
2844     }
2845 }
2846
2847 void Part::resetStartArguments()
2848 {
2849     m_cliPrint = false;
2850 }
2851
2852 void Part::setReadWrite(bool readwrite)
2853 {
2854     m_document->setAnnotationEditingEnabled( readwrite );
2855     ReadWritePart::setReadWrite( readwrite );
2856 }
2857
2858 } // namespace Okular
2859
2860 #include "moc_part.cpp"
2861
2862 /* kate: replace-tabs on; indent-width 4; */