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> *
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 ***************************************************************************/
27 #include <qapplication.h>
32 #include <QtGui/QPrinter>
33 #include <QtGui/QPrintDialog>
36 #include <kaboutapplicationdialog.h>
38 #include <kactioncollection.h>
39 #include <kdirwatch.h>
40 #include <kstandardaction.h>
41 #include <kparts/genericfactory.h>
42 #include <kfiledialog.h>
43 #include <kmessagebox.h>
44 #include <knuminput.h>
45 #include <kio/netaccess.h>
47 #include <kxmlguiclient.h>
48 #include <kxmlguifactory.h>
49 #include <kservicetypetrader.h>
50 #include <kstandarddirs.h>
51 #include <kstandardshortcut.h>
52 #include <ktemporaryfile.h>
53 #include <ktoggleaction.h>
54 #include <ktogglefullscreenaction.h>
57 #include <kfilterdev.h>
58 #include <knewstuff2/engine.h>
59 #include <kdeprintdialog.h>
60 #include <kprintpreview.h>
63 #include "aboutdata.h"
64 #include "extensions.h"
65 #include "ui/pageview.h"
67 #include "ui/searchwidget.h"
68 #include "ui/thumbnaillist.h"
69 #include "ui/side_reviews.h"
70 #include "ui/minibar.h"
71 #include "ui/embeddedfilesdialog.h"
72 #include "ui/propertiesdialog.h"
73 #include "ui/presentationwidget.h"
74 #include "ui/pagesizelabel.h"
75 #include "ui/bookmarklist.h"
76 #include "ui/findbar.h"
77 #include "ui/sidebar.h"
78 #include "ui/fileprinterpreview.h"
79 #include "ui/guiutils.h"
80 #include "conf/preferencesdialog.h"
82 #include "core/bookmarkmanager.h"
83 #include "core/document.h"
84 #include "core/generator.h"
85 #include "core/page.h"
86 #include "core/fileprinter.h"
102 void open( const QString
& path
)
105 m_handle
= std::fopen( QFile::encodeName( path
), "r" );
112 int ret
= std::fclose( m_handle
);
118 KTemporaryFile
* copyToTemporary() const
123 KTemporaryFile
* retFile
= new KTemporaryFile
;
126 std::rewind( m_handle
);
130 c
= std::fgetc( m_handle
);
133 if ( !retFile
->putChar( (char)c
) )
135 } while ( !feof( m_handle
) );
143 std::FILE * m_handle
;
146 K_PLUGIN_FACTORY( okularPartFactory
, registerPlugin
< Part
>(); )
147 K_EXPORT_PLUGIN( okularPartFactory( okularAboutData( "okular", I18N_NOOP( "Okular" ) ) ) )
149 static QAction
* actionForExportFormat( const Okular::ExportFormat
& format
, QObject
*parent
= 0 )
151 QAction
*act
= new QAction( format
.description(), parent
);
152 if ( !format
.icon().isNull() )
154 act
->setIcon( format
.icon() );
159 static QString
compressedMimeFor( const QString
& mime_to_check
)
161 static QHash
< QString
, QString
> compressedMimeMap
;
162 if ( compressedMimeMap
.isEmpty() )
164 compressedMimeMap
[ QString::fromLatin1( "application/x-gzip" ) ] =
165 QString::fromLatin1( "application/x-gzip" );
166 compressedMimeMap
[ QString::fromLatin1( "application/x-bzip" ) ] =
167 QString::fromLatin1( "application/x-bzip" );
168 compressedMimeMap
[ QString::fromLatin1( "application/x-bzpdf" ) ] =
169 QString::fromLatin1( "application/x-bzip" );
170 compressedMimeMap
[ QString::fromLatin1( "application/x-bzpostscript" ) ] =
171 QString::fromLatin1( "application/x-bzip" );
172 compressedMimeMap
[ QString::fromLatin1( "application/x-bzdvi" ) ] =
173 QString::fromLatin1( "application/x-bzip" );
175 QHash
< QString
, QString
>::const_iterator it
= compressedMimeMap
.constFind( mime_to_check
);
176 if ( it
!= compressedMimeMap
.constEnd() )
182 #undef OKULAR_KEEP_FILE_OPEN
184 #ifdef OKULAR_KEEP_FILE_OPEN
185 static bool keepFileOpen()
187 static bool keep_file_open
= !qgetenv("OKULAR_NO_KEEP_FILE_OPEN").toInt();
188 return keep_file_open
;
192 Part::Part(QWidget
*parentWidget
,
194 const QVariantList
&args
)
195 : KParts::ReadOnlyPart(parent
),
196 m_tempfile( 0 ), m_fileWasRemoved( false ), m_showMenuBarAction( 0 ), m_showFullScreenAction( 0 ), m_actionsSearched( false ),
197 m_cliPresentation(false), m_generatorGuiClient(0), m_keeper( 0 )
199 // first necessary step: copy the configuration from kpdf, if available
200 QString newokularconffile
= KStandardDirs::locateLocal( "config", "okularpartrc" );
201 if ( !QFile::exists( newokularconffile
) )
203 QString oldkpdfconffile
= KStandardDirs::locateLocal( "config", "kpdfpartrc" );
204 if ( QFile::exists( oldkpdfconffile
) )
205 QFile::copy( oldkpdfconffile
, newokularconffile
);
208 QDBusConnection::sessionBus().registerObject("/okular", this, QDBusConnection::ExportScriptableSlots
);
210 // connect the started signal to tell the job the mimetypes we like
211 connect(this, SIGNAL(started(KIO::Job
*)), this, SLOT(setMimeTypes(KIO::Job
*)));
213 // connect the completed signal so we can put the window caption when loading remote files
214 connect(this, SIGNAL(completed()), this, SLOT(setWindowTitleFromDocument()));
215 connect(this, SIGNAL(canceled(const QString
&)), this, SLOT(loadCancelled(const QString
&)));
217 // create browser extension (for printing when embedded into browser)
218 m_bExtension
= new BrowserExtension(this);
219 // create live connect extension (for integrating with browser scripting)
220 new OkularLiveConnectExtension( this );
222 // we need an instance
223 setComponentData(okularPartFactory::componentData());
225 GuiUtils::setIconLoader( iconLoader() );
227 m_sidebar
= new Sidebar( parentWidget
);
228 setWidget( m_sidebar
);
230 // build the document
231 m_document
= new Okular::Document(widget());
232 connect( m_document
, SIGNAL( linkFind() ), this, SLOT( slotFind() ) );
233 connect( m_document
, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) );
234 connect( m_document
, SIGNAL( linkPresentation() ), this, SLOT( slotShowPresentation() ) );
235 connect( m_document
, SIGNAL( linkEndPresentation() ), this, SLOT( slotHidePresentation() ) );
236 connect( m_document
, SIGNAL( openUrl(const KUrl
&) ), this, SLOT( openUrlFromDocument(const KUrl
&) ) );
237 connect( m_document
->bookmarkManager(), SIGNAL( openUrl(const KUrl
&) ), this, SLOT( openUrlFromBookmarks(const KUrl
&) ) );
238 connect( m_document
, SIGNAL( close() ), this, SLOT( close() ) );
240 if ( parent
&& parent
->metaObject()->indexOfSlot( QMetaObject::normalizedSignature( "slotQuit()" ) ) != -1 )
241 connect( m_document
, SIGNAL( quit() ), parent
, SLOT( slotQuit() ) );
243 connect( m_document
, SIGNAL( quit() ), this, SLOT( cannotQuit() ) );
244 // widgets: ^searchbar (toolbar containing label and SearchWidget)
245 // m_searchToolBar = new KToolBar( parentWidget, "searchBar" );
246 // m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() );
247 // QLabel * sLabel = new QLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" );
248 // m_searchWidget = new SearchWidget( m_searchToolBar, m_document );
249 // sLabel->setBuddy( m_searchWidget );
250 // m_searchToolBar->setStretchableWidget( m_searchWidget );
253 // [left toolbox: Table of Contents] | []
254 m_toc
= new TOC( 0, m_document
);
255 connect( m_toc
, SIGNAL( hasTOC( bool ) ), this, SLOT( enableTOC( bool ) ) );
256 tbIndex
= m_sidebar
->addItem( m_toc
, KIcon(QApplication::isLeftToRight() ? "format-justify-left" : "format-justify-right"), i18n("Contents") );
259 // [left toolbox: Thumbnails and Bookmarks] | []
260 KVBox
* thumbsBox
= new ThumbnailsBox( 0 );
261 thumbsBox
->setSpacing( 6 );
262 m_searchWidget
= new SearchWidget( thumbsBox
, m_document
);
263 m_thumbnailList
= new ThumbnailList( thumbsBox
, m_document
);
264 // ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList );
265 connect( m_thumbnailList
, SIGNAL( urlDropped( const KUrl
& ) ), SLOT( openUrlFromDocument( const KUrl
& )) );
266 connect( m_thumbnailList
, SIGNAL( rightClick(const Okular::Page
*, const QPoint
&) ), this, SLOT( slotShowMenu(const Okular::Page
*, const QPoint
&) ) );
267 tbIndex
= m_sidebar
->addItem( thumbsBox
, KIcon( "view-preview" ), i18n("Thumbnails") );
268 m_sidebar
->setCurrentIndex( tbIndex
);
270 // [left toolbox: Reviews] | []
271 m_reviewsWidget
= new Reviews( 0, m_document
);
272 m_sidebar
->addItem( m_reviewsWidget
, KIcon("draw-freehand"), i18n("Reviews") );
273 m_sidebar
->setItemEnabled( 2, false );
275 // [left toolbox: Bookmarks] | []
276 m_bookmarkList
= new BookmarkList( m_document
, 0 );
277 m_sidebar
->addItem( m_bookmarkList
, KIcon("bookmarks"), i18n("Bookmarks") );
278 m_sidebar
->setItemEnabled( 3, false );
280 // widgets: [../miniBarContainer] | []
281 #ifdef OKULAR_ENABLE_MINIBAR
282 QWidget
* miniBarContainer
= new QWidget( 0 );
283 m_sidebar
->setBottomWidget( miniBarContainer
);
284 QVBoxLayout
* miniBarLayout
= new QVBoxLayout( miniBarContainer
);
285 miniBarLayout
->setMargin( 0 );
286 // widgets: [../[spacer/..]] | []
287 miniBarLayout
->addItem( new QSpacerItem( 6, 6, QSizePolicy::Fixed
, QSizePolicy::Fixed
) );
288 // widgets: [../[../MiniBar]] | []
289 QFrame
* bevelContainer
= new QFrame( miniBarContainer
);
290 bevelContainer
->setFrameStyle( QFrame::StyledPanel
| QFrame::Sunken
);
291 QVBoxLayout
* bevelContainerLayout
= new QVBoxLayout( bevelContainer
);
292 bevelContainerLayout
->setMargin( 4 );
293 m_progressWidget
= new ProgressWidget( bevelContainer
, m_document
);
294 bevelContainerLayout
->addWidget( m_progressWidget
);
295 miniBarLayout
->addWidget( bevelContainer
);
296 miniBarLayout
->addItem( new QSpacerItem( 6, 6, QSizePolicy::Fixed
, QSizePolicy::Fixed
) );
299 // widgets: [] | [right 'pageView']
300 QWidget
* rightContainer
= new QWidget( 0 );
301 m_sidebar
->setMainWidget( rightContainer
);
302 QVBoxLayout
* rightLayout
= new QVBoxLayout( rightContainer
);
303 rightLayout
->setMargin( 0 );
304 rightLayout
->setSpacing( 0 );
305 // KToolBar * rtb = new KToolBar( rightContainer, "mainToolBarSS" );
306 // rightLayout->addWidget( rtb );
307 m_topMessage
= new PageViewTopMessage( rightContainer
);
308 m_topMessage
->setup( i18n( "This document has embedded files. <a href=\"okular:/embeddedfiles\">Click here to see them</a> or go to File -> Embedded Files." ), KIcon( "mail-attachment" ) );
309 connect( m_topMessage
, SIGNAL( action() ), this, SLOT( slotShowEmbeddedFiles() ) );
310 rightLayout
->addWidget( m_topMessage
);
311 m_formsMessage
= new PageViewTopMessage( rightContainer
);
312 m_formsMessage
->setup( i18n( "This document has forms. Click on the button to interact with them, or use View -> Show Forms." ) );
313 rightLayout
->addWidget( m_formsMessage
);
314 m_pageView
= new PageView( rightContainer
, m_document
);
315 m_pageView
->setFocus(); //usability setting
316 // m_splitter->setFocusProxy(m_pageView);
317 connect( m_pageView
, SIGNAL( urlDropped( const KUrl
& ) ), SLOT( openUrlFromDocument( const KUrl
& )));
318 connect( m_pageView
, SIGNAL( rightClick(const Okular::Page
*, const QPoint
&) ), this, SLOT( slotShowMenu(const Okular::Page
*, const QPoint
&) ) );
319 connect( m_document
, SIGNAL( error( const QString
&, int ) ), m_pageView
, SLOT( errorMessage( const QString
&, int ) ) );
320 connect( m_document
, SIGNAL( warning( const QString
&, int ) ), m_pageView
, SLOT( warningMessage( const QString
&, int ) ) );
321 connect( m_document
, SIGNAL( notice( const QString
&, int ) ), m_pageView
, SLOT( noticeMessage( const QString
&, int ) ) );
322 rightLayout
->addWidget( m_pageView
);
323 m_findBar
= new FindBar( m_document
, rightContainer
);
324 rightLayout
->addWidget( m_findBar
);
325 QWidget
* bottomBar
= new QWidget( rightContainer
);
326 QHBoxLayout
* bottomBarLayout
= new QHBoxLayout( bottomBar
);
327 m_pageSizeLabel
= new PageSizeLabel( bottomBar
, m_document
);
328 bottomBarLayout
->setMargin( 0 );
329 bottomBarLayout
->setSpacing( 0 );
330 bottomBarLayout
->addWidget( m_pageSizeLabel
->antiWidget() );
331 bottomBarLayout
->addItem( new QSpacerItem( 5, 5, QSizePolicy::Expanding
, QSizePolicy::Minimum
) );
332 m_miniBar
= new MiniBar( bottomBar
, m_document
);
333 bottomBarLayout
->addWidget( m_miniBar
);
334 bottomBarLayout
->addItem( new QSpacerItem( 5, 5, QSizePolicy::Expanding
, QSizePolicy::Minimum
) );
335 bottomBarLayout
->addWidget( m_pageSizeLabel
);
336 rightLayout
->addWidget( bottomBar
);
338 connect( m_reviewsWidget
, SIGNAL( setAnnotationWindow( Okular::Annotation
* ) ),
339 m_pageView
, SLOT( setAnnotationWindow( Okular::Annotation
* ) ) );
340 connect( m_reviewsWidget
, SIGNAL( removeAnnotationWindow( Okular::Annotation
* ) ),
341 m_pageView
, SLOT( removeAnnotationWindow( Okular::Annotation
* ) ) );
343 // add document observers
344 m_document
->addObserver( this );
345 m_document
->addObserver( m_thumbnailList
);
346 m_document
->addObserver( m_pageView
);
347 m_document
->registerView( m_pageView
);
348 m_document
->addObserver( m_toc
);
349 m_document
->addObserver( m_miniBar
);
350 #ifdef OKULAR_ENABLE_MINIBAR
351 m_document
->addObserver( m_progressWidget
);
353 m_document
->addObserver( m_reviewsWidget
);
354 m_document
->addObserver( m_pageSizeLabel
);
355 m_document
->addObserver( m_bookmarkList
);
357 connect( m_document
->bookmarkManager(), SIGNAL( saved() ),
358 this, SLOT( slotRebuildBookmarkMenu() ) );
361 KActionCollection
* ac
= actionCollection();
363 // Page Traversal actions
364 m_gotoPage
= KStandardAction::gotoPage( this, SLOT( slotGoToPage() ), ac
);
365 m_gotoPage
->setShortcut( QKeySequence(Qt::CTRL
+ Qt::Key_G
) );
366 // dirty way to activate gotopage when pressing miniBar's button
367 connect( m_miniBar
, SIGNAL( gotoPage() ), m_gotoPage
, SLOT( trigger() ) );
369 m_prevPage
= KStandardAction::prior(this, SLOT(slotPreviousPage()), ac
);
370 m_prevPage
->setIconText( i18nc( "Previous page", "Previous" ) );
371 m_prevPage
->setToolTip( i18n( "Go back to the Previous Page" ) );
372 m_prevPage
->setWhatsThis( i18n( "Moves to the previous page of the document" ) );
373 m_prevPage
->setShortcut( 0 );
374 // dirty way to activate prev page when pressing miniBar's button
375 connect( m_miniBar
, SIGNAL( prevPage() ), m_prevPage
, SLOT( trigger() ) );
376 #ifdef OKULAR_ENABLE_MINIBAR
377 connect( m_progressWidget
, SIGNAL( prevPage() ), m_prevPage
, SLOT( trigger() ) );
380 m_nextPage
= KStandardAction::next(this, SLOT(slotNextPage()), ac
);
381 m_nextPage
->setIconText( i18nc( "Next page", "Next" ) );
382 m_nextPage
->setToolTip( i18n( "Advance to the Next Page" ) );
383 m_nextPage
->setWhatsThis( i18n( "Moves to the next page of the document" ) );
384 m_nextPage
->setShortcut( 0 );
385 // dirty way to activate next page when pressing miniBar's button
386 connect( m_miniBar
, SIGNAL( nextPage() ), m_nextPage
, SLOT( trigger() ) );
387 #ifdef OKULAR_ENABLE_MINIBAR
388 connect( m_progressWidget
, SIGNAL( nextPage() ), m_nextPage
, SLOT( trigger() ) );
391 m_firstPage
= KStandardAction::firstPage( this, SLOT( slotGotoFirst() ), ac
);
392 ac
->addAction("first_page", m_firstPage
);
393 m_firstPage
->setWhatsThis( i18n( "Moves to the first page of the document" ) );
395 m_lastPage
= KStandardAction::lastPage( this, SLOT( slotGotoLast() ), ac
);
396 ac
->addAction("last_page",m_lastPage
);
397 m_lastPage
->setWhatsThis( i18n( "Moves to the last page of the document" ) );
399 // we do not want back and next in history in the dummy mode
403 m_addBookmark
= KStandardAction::addBookmark( this, SLOT( slotAddBookmark() ), ac
);
404 m_addBookmarkText
= m_addBookmark
->text();
405 m_addBookmarkIcon
= m_addBookmark
->icon();
407 m_prevBookmark
= ac
->addAction("previous_bookmark");
408 m_prevBookmark
->setText(i18n( "Previous Bookmark" ));
409 m_prevBookmark
->setIcon(KIcon( "go-up-search" ));
410 m_prevBookmark
->setWhatsThis( i18n( "Go to the previous bookmarked page" ) );
411 connect( m_prevBookmark
, SIGNAL( triggered() ), this, SLOT( slotPreviousBookmark() ) );
413 m_nextBookmark
= ac
->addAction("next_bookmark");
414 m_nextBookmark
->setText(i18n( "Next Bookmark" ));
415 m_nextBookmark
->setIcon(KIcon( "go-down-search" ));
416 m_nextBookmark
->setWhatsThis( i18n( "Go to the next bookmarked page" ) );
417 connect( m_nextBookmark
, SIGNAL( triggered() ), this, SLOT( slotNextBookmark() ) );
419 m_copy
= KStandardAction::create( KStandardAction::Copy
, m_pageView
, SLOT( copyTextSelection() ), ac
);
421 m_selectAll
= KStandardAction::selectAll( m_pageView
, SLOT( selectAll() ), ac
);
423 // Find and other actions
424 m_find
= KStandardAction::find( this, SLOT( slotShowFindBar() ), ac
);
425 QList
<QKeySequence
> s
= m_find
->shortcuts();
426 s
.append( QKeySequence( Qt::Key_Slash
) );
427 m_find
->setShortcuts( s
);
428 m_find
->setEnabled( false );
430 m_findNext
= KStandardAction::findNext( this, SLOT( slotFindNext() ), ac
);
431 m_findNext
->setEnabled( false );
433 m_saveCopyAs
= KStandardAction::saveAs( this, SLOT( slotSaveCopyAs() ), ac
);
434 m_saveCopyAs
->setText( i18n( "Save &Copy As..." ) );
435 ac
->addAction( "file_save_copy", m_saveCopyAs
);
436 m_saveCopyAs
->setEnabled( false );
438 m_saveAs
= KStandardAction::saveAs( this, SLOT( slotSaveFileAs() ), ac
);
439 m_saveAs
->setEnabled( false );
441 QAction
* prefs
= KStandardAction::preferences( this, SLOT( slotPreferences() ), ac
);
442 if ( parent
&& ( parent
->objectName() == QLatin1String( "okular::Shell" ) ) )
444 prefs
->setText( i18n( "Configure Okular..." ) );
448 // TODO: improve this message
449 prefs
->setText( i18n( "Configure Viewer..." ) );
452 KAction
* genPrefs
= new KAction( ac
);
453 ac
->addAction("options_configure_generators", genPrefs
);
454 genPrefs
->setText( i18n( "Configure Backends..." ) );
455 genPrefs
->setIcon( KIcon( "configure" ) );
456 genPrefs
->setEnabled( m_document
->configurableGenerators() > 0 );
457 connect( genPrefs
, SIGNAL( triggered( bool ) ), this, SLOT( slotGeneratorPreferences() ) );
459 m_printPreview
= KStandardAction::printPreview( this, SLOT( slotPrintPreview() ), ac
);
460 m_printPreview
->setEnabled( false );
462 m_showLeftPanel
= ac
->add
<KToggleAction
>("show_leftpanel");
463 m_showLeftPanel
->setText(i18n( "Show &Navigation Panel"));
464 m_showLeftPanel
->setIcon(KIcon( "view-sidetree" ));
465 connect( m_showLeftPanel
, SIGNAL( toggled( bool ) ), this, SLOT( slotShowLeftPanel() ) );
466 m_showLeftPanel
->setShortcut( Qt::Key_F7
);
467 m_showLeftPanel
->setChecked( Okular::Settings::showLeftPanel() );
470 QAction
* importPS
= ac
->addAction("import_ps");
471 importPS
->setText(i18n("&Import PostScript as PDF..."));
472 importPS
->setIcon(KIcon("document-import"));
473 connect(importPS
, SIGNAL(triggered()), this, SLOT(slotImportPSFile()));
475 QAction
* ghns
= ac
->addAction("get_new_stuff");
476 ghns
->setText(i18n("&Get Books From Internet..."));
477 ghns
->setIcon(KIcon("get-hot-new-stuff"));
478 connect(ghns
, SIGNAL(triggered()), this, SLOT(slotGetNewStuff()));
480 ghns
->setShortcut( Qt::Key_G
);
483 m_showProperties
= ac
->addAction("properties");
484 m_showProperties
->setText(i18n("&Properties"));
485 m_showProperties
->setIcon(KIcon("document-properties"));
486 connect(m_showProperties
, SIGNAL(triggered()), this, SLOT(slotShowProperties()));
487 m_showProperties
->setEnabled( false );
489 m_showEmbeddedFiles
= ac
->addAction("embedded_files");
490 m_showEmbeddedFiles
->setText(i18n("&Embedded Files"));
491 m_showEmbeddedFiles
->setIcon( KIcon( "mail-attachment" ) );
492 connect(m_showEmbeddedFiles
, SIGNAL(triggered()), this, SLOT(slotShowEmbeddedFiles()));
493 m_showEmbeddedFiles
->setEnabled( false );
495 m_showPresentation
= ac
->addAction("presentation");
496 m_showPresentation
->setText(i18n("P&resentation"));
497 m_showPresentation
->setIcon( KIcon( "view-presentation" ) );
498 connect(m_showPresentation
, SIGNAL(triggered()), this, SLOT(slotShowPresentation()));
499 m_showPresentation
->setShortcut( QKeySequence( Qt::CTRL
+ Qt::SHIFT
+ Qt::Key_P
) );
500 m_showPresentation
->setEnabled( false );
502 m_exportAs
= ac
->addAction("file_export_as");
503 m_exportAs
->setText(i18n("E&xport As"));
504 m_exportAs
->setIcon( KIcon( "document-export" ) );
505 m_exportAsMenu
= new QMenu();
506 connect(m_exportAsMenu
, SIGNAL(triggered(QAction
*)), this, SLOT(slotExportAs(QAction
*)));
507 m_exportAs
->setMenu( m_exportAsMenu
);
508 m_exportAsText
= actionForExportFormat( Okular::ExportFormat::standardFormat( Okular::ExportFormat::PlainText
), m_exportAsMenu
);
509 m_exportAsMenu
->addAction( m_exportAsText
);
510 m_exportAs
->setEnabled( false );
511 m_exportAsText
->setEnabled( false );
512 m_exportAsDocArchive
= actionForExportFormat( Okular::ExportFormat(
513 i18nc( "A document format, Okular-specific", "Document Archive" ),
514 KMimeType::mimeType( "application/vnd.kde.okular-archive" ) ), m_exportAsMenu
);
515 m_exportAsMenu
->addAction( m_exportAsDocArchive
);
516 m_exportAsDocArchive
->setEnabled( false );
518 m_aboutBackend
= ac
->addAction("help_about_backend");
519 m_aboutBackend
->setText(i18n("About Backend"));
520 m_aboutBackend
->setEnabled( false );
521 connect(m_aboutBackend
, SIGNAL(triggered()), this, SLOT(slotAboutBackend()));
523 KAction
*reload
= ac
->add
<KAction
>( "file_reload" );
524 reload
->setText( i18n( "Reloa&d" ) );
525 reload
->setIcon( KIcon( "view-refresh" ) );
526 reload
->setWhatsThis( i18n( "Reload the current document from disk." ) );
527 connect( reload
, SIGNAL(triggered()), this, SLOT(slotReload()) );
528 reload
->setShortcut( KStandardShortcut::reload() );
531 KAction
*closeFindBar
= new KAction( i18n( "Close &Find Bar" ), ac
);
532 ac
->addAction("close_find_bar", closeFindBar
);
533 connect(closeFindBar
, SIGNAL(triggered()), this, SLOT(slotHideFindBar()));
534 closeFindBar
->setShortcut( QKeySequence( Qt::Key_Escape
) );
535 widget()->addAction(closeFindBar
);
537 KToggleAction
*blackscreenAction
= new KToggleAction( i18n( "Switch Blackscreen Mode" ), ac
);
538 ac
->addAction( "switch_blackscreen_mode", blackscreenAction
);
539 blackscreenAction
->setShortcut( QKeySequence( Qt::Key_B
) );
540 blackscreenAction
->setIcon( KIcon( "view-presentation" ) );
542 // document watcher and reloader
543 m_watcher
= new KDirWatch( this );
544 connect( m_watcher
, SIGNAL( dirty( const QString
& ) ), this, SLOT( slotFileDirty( const QString
& ) ) );
545 m_dirtyHandler
= new QTimer( this );
546 m_dirtyHandler
->setSingleShot( true );
547 connect( m_dirtyHandler
, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) );
551 // [SPEECH] check for KTTSD presence and usability
552 KService::List offers
= KServiceTypeTrader::self()->query("DBUS/Text-to-Speech", "Name == 'KTTSD'");
553 Okular::Settings::setUseKTTSD( !offers
.isEmpty() );
554 Okular::Settings::self()->writeConfig();
556 rebuildBookmarkMenu( false );
558 // set our XML-UI resource file
559 setXMLFile("part.rc");
561 m_pageView
->setupBaseActions( actionCollection() );
563 // ensure history actions are in the correct state
567 m_sidebar
->setSidebarVisibility( false );
568 if ( !args
.contains( QVariant( "Print/Preview" ) ) ) unsetDummyMode();
570 #ifdef OKULAR_KEEP_FILE_OPEN
571 m_keeper
= new FileKeeper();
578 m_document
->removeObserver( this );
580 if ( m_document
->isOpened() )
585 delete m_thumbnailList
;
587 #ifdef OKULAR_ENABLE_MINIBAR
588 delete m_progressWidget
;
590 delete m_pageSizeLabel
;
591 delete m_reviewsWidget
;
592 delete m_bookmarkList
;
598 qDeleteAll( m_bookmarkActions
);
600 delete m_exportAsMenu
;
602 #ifdef OKULAR_KEEP_FILE_OPEN
608 bool Part::openDocument(const KUrl
& url
, uint page
)
610 Okular::DocumentViewport
vp( page
- 1 );
611 vp
.rePos
.enabled
= true;
612 vp
.rePos
.normalizedX
= 0;
613 vp
.rePos
.normalizedY
= 0;
614 vp
.rePos
.pos
= Okular::DocumentViewport::TopLeft
;
616 m_document
->setNextDocumentViewport( vp
);
617 return openUrl( url
);
621 void Part::startPresentation()
623 m_cliPresentation
= true;
627 QStringList
Part::supportedMimeTypes() const
629 return m_document
->supportedMimeTypes();
633 KUrl
Part::realUrl() const
635 if ( !m_realUrl
.isEmpty() )
642 void Part::openUrlFromDocument(const KUrl
&url
)
644 if (m_dummyMode
) return;
646 m_bExtension
->openUrlNotify();
647 m_bExtension
->setLocationBarUrl(url
.prettyUrl());
651 void Part::openUrlFromBookmarks(const KUrl
&_url
)
654 Okular::DocumentViewport
vp( _url
.htmlRef() );
656 m_document
->setNextDocumentViewport( vp
);
657 url
.setHTMLRef( QString() );
658 if ( m_document
->currentDocument() == url
)
661 m_document
->setViewport( vp
);
667 void Part::setMimeTypes(KIO::Job
*job
)
671 QStringList supportedMimeTypes
= m_document
->supportedMimeTypes();
672 job
->addMetaData("accept", supportedMimeTypes
.join(", ") + ", */*;q=0.5");
676 void Part::loadCancelled(const QString
&reason
)
678 emit
setWindowCaption( QString() );
680 // when m_viewportDirty.pageNumber != -1 we come from slotDoFileDirty
681 // so we don't want to show an ugly messagebox just because the document is
682 // taking more than usual to be recreated
683 if (m_viewportDirty
.pageNumber
== -1)
685 if (!reason
.isEmpty())
687 KMessageBox::error( widget(), i18n("Could not open %1. Reason: %2", url().prettyUrl(), reason
) );
691 KMessageBox::error( widget(), i18n("Could not open %1", url().prettyUrl() ) );
696 void Part::setWindowTitleFromDocument()
698 // if the document have a 'DocumentTitle' flag set (and it is not empty), set it as title
699 QString title
= m_document
->metaData( "DocumentTitle" ).toString();
700 if ( !title
.isEmpty() && !title
.trimmed().isEmpty() )
702 emit
setWindowCaption( title
);
706 emit
setWindowCaption( realUrl().fileName() );
710 void Part::slotGeneratorPreferences( )
712 // an instance the dialog could be already created and could be cached,
713 // in which case you want to display the cached dialog
714 if ( KConfigDialog::showDialog( "generator_prefs" ) )
717 // we didn't find an instance of this dialog, so lets create it
718 KConfigDialog
* dialog
= new KConfigDialog( m_pageView
, "generator_prefs", Okular::Settings::self() );
719 dialog
->setCaption( i18n( "Configure Backends" ) );
721 m_document
->fillConfigDialog( dialog
);
723 // keep us informed when the user changes settings
724 connect( dialog
, SIGNAL( settingsChanged( const QString
& ) ), this, SLOT( slotNewGeneratorConfig() ) );
729 void Part::notifySetup( const QVector
< Okular::Page
* > & /*pages*/, int setupFlags
)
731 if ( !( setupFlags
& Okular::DocumentObserver::DocumentChanged
) )
734 rebuildBookmarkMenu();
735 updateAboutBackendAction();
736 m_searchWidget
->setEnabled( m_document
->supportsSearching() );
739 void Part::notifyViewportChanged( bool /*smoothMove*/ )
741 // update actions if the page is changed
742 static int lastPage
= -1;
743 int viewportPage
= m_document
->viewport().pageNumber
;
744 if ( viewportPage
!= lastPage
)
747 lastPage
= viewportPage
;
751 void Part::notifyPageChanged( int page
, int flags
)
753 if ( !(flags
& Okular::DocumentObserver::Bookmark
) )
756 rebuildBookmarkMenu();
757 if ( page
== m_document
->viewport().pageNumber
)
758 updateBookmarksActions();
762 void Part::goToPage(uint i
)
764 if ( i
<= m_document
->pages() )
765 m_document
->setViewportPage( i
- 1 );
769 void Part::openDocument( const QString
&doc
)
771 openUrl( KUrl( doc
) );
777 return m_document
->pages();
781 uint
Part::currentPage()
783 return m_document
->pages() ? m_document
->currentPage() + 1 : 0;
787 QString
Part::currentDocument()
789 return m_document
->currentDocument().pathOrUrl();
793 bool Part::slotImportPSFile()
795 QString app
= KStandardDirs::findExe( "ps2pdf" );
798 // TODO point the user to their distro packages?
799 KMessageBox::error( widget(), i18n( "The program \"ps2pdf\" was not found, so Okular can not import PS files using it." ), i18n("ps2pdf not found") );
803 KUrl url
= KFileDialog::getOpenUrl( KUrl(), "application/postscript", this->widget() );
804 if ( url
.isLocalFile() )
807 tf
.setSuffix( ".pdf" );
808 tf
.setAutoRemove( false );
811 m_temporaryLocalFile
= tf
.fileName();
814 setLocalFilePath( url
.path() );
816 QProcess
*p
= new QProcess();
817 args
<< url
.toLocalFile() << m_temporaryLocalFile
;
818 m_pageView
->displayMessage(i18n("Importing PS file as PDF (this may take a while)..."));
819 connect(p
, SIGNAL(finished(int, QProcess::ExitStatus
)), this, SLOT(psTransformEnded(int, QProcess::ExitStatus
)));
824 m_temporaryLocalFile
.clear();
829 bool Part::openFile()
832 if ( !arguments().mimeType().isEmpty() )
834 mime
= KMimeType::mimeType( arguments().mimeType() );
838 mime
= KMimeType::findByPath( localFilePath() );
840 bool isCompressedFile
= false;
841 bool uncompressOk
= true;
842 QString fileNameToOpen
= localFilePath();
843 QString compressedMime
= compressedMimeFor( mime
->name() );
844 if ( compressedMime
.isEmpty() )
845 compressedMime
= compressedMimeFor( mime
->parentMimeType() );
846 if ( !compressedMime
.isEmpty() )
848 isCompressedFile
= true;
849 uncompressOk
= handleCompressed( fileNameToOpen
, localFilePath(), compressedMime
);
850 mime
= KMimeType::findByPath( fileNameToOpen
);
855 if ( mime
->is( "application/vnd.kde.okular-archive" ) )
856 ok
= m_document
->openDocumentArchive( fileNameToOpen
, url() );
858 ok
= m_document
->openDocument( fileNameToOpen
, url(), mime
);
860 bool canSearch
= m_document
->supportsSearching();
862 // update one-time actions
863 m_find
->setEnabled( ok
&& canSearch
);
864 m_findNext
->setEnabled( ok
&& canSearch
);
865 m_saveAs
->setEnabled( ok
&& m_document
->canSaveChanges() );
866 m_saveCopyAs
->setEnabled( ok
);
867 emit
enablePrintAction( ok
&& m_document
->printingSupport() != Okular::Document::NoPrinting
);
868 m_printPreview
->setEnabled( ok
&& m_document
->printingSupport() != Okular::Document::NoPrinting
);
869 m_showProperties
->setEnabled( ok
);
870 bool hasEmbeddedFiles
= ok
&& m_document
->embeddedFiles() && m_document
->embeddedFiles()->count() > 0;
871 m_showEmbeddedFiles
->setEnabled( hasEmbeddedFiles
);
872 m_topMessage
->setVisible( hasEmbeddedFiles
);
873 // m_pageView->toggleFormsAction() may be null on dummy mode
874 m_formsMessage
->setVisible( ok
&& m_pageView
->toggleFormsAction() && m_pageView
->toggleFormsAction()->isEnabled() );
875 m_showPresentation
->setEnabled( ok
);
878 m_exportFormats
= m_document
->exportFormats();
879 QList
<Okular::ExportFormat
>::ConstIterator it
= m_exportFormats
.constBegin();
880 QList
<Okular::ExportFormat
>::ConstIterator itEnd
= m_exportFormats
.constEnd();
881 QMenu
*menu
= m_exportAs
->menu();
882 for ( ; it
!= itEnd
; ++it
)
884 menu
->addAction( actionForExportFormat( *it
) );
886 if ( isCompressedFile
)
890 #ifdef OKULAR_KEEP_FILE_OPEN
891 if ( keepFileOpen() )
892 m_keeper
->open( fileNameToOpen
);
895 m_exportAsText
->setEnabled( ok
&& m_document
->canExportToText() );
896 m_exportAsDocArchive
->setEnabled( ok
);
897 m_exportAs
->setEnabled( ok
);
899 // update viewing actions
902 m_fileWasRemoved
= false;
906 // if can't open document, update windows so they display blank contents
907 m_pageView
->widget()->update();
908 m_thumbnailList
->update();
912 // set the file to the fileWatcher
913 if ( url().isLocalFile() )
915 if ( !m_watcher
->contains( localFilePath() ) ) m_watcher
->addFile(localFilePath());
916 QFileInfo
fi(localFilePath());
917 if ( !m_watcher
->contains( fi
.absolutePath() ) ) m_watcher
->addDir(fi
.absolutePath());
920 // if the 'OpenTOC' flag is set, open the TOC
921 if ( m_document
->metaData( "OpenTOC" ).toBool() && m_sidebar
->isItemEnabled( 0 ) )
923 m_sidebar
->setCurrentIndex( 0 );
925 // if the 'StartFullScreen' flag is set, or the command line flag was
926 // specified, start presentation
927 if ( m_document
->metaData( "StartFullScreen" ).toBool() || m_cliPresentation
)
929 bool goAheadWithPresentationMode
= true;
930 if ( !m_cliPresentation
)
932 const QString text
= i18n( "The document requested to be launched in presentation mode.\n"
933 "Do you want to allow it?" );
934 const QString caption
= i18n( "Presentation Mode" );
935 const KGuiItem yesItem
= KGuiItem( i18n( "Allow" ), "dialog-ok", i18n( "Allow the presentation mode" ) );
936 const KGuiItem noItem
= KGuiItem( i18n( "Do Not Allow" ), "process-stop", i18n( "Do not allow the presentation mode" ) );
937 const int result
= KMessageBox::questionYesNo( widget(), text
, caption
, yesItem
, noItem
);
938 if ( result
== KMessageBox::No
)
939 goAheadWithPresentationMode
= false;
941 m_cliPresentation
= false;
942 if ( goAheadWithPresentationMode
)
943 QMetaObject::invokeMethod( this, "slotShowPresentation", Qt::QueuedConnection
);
945 m_generatorGuiClient
= factory() ? m_document
->guiClient() : 0;
946 if ( m_generatorGuiClient
)
947 factory()->addClient( m_generatorGuiClient
);
951 bool Part::openUrl(const KUrl
&url
)
953 // this calls in sequence the 'closeUrl' and 'openFile' methods
954 bool openOk
= KParts::ReadOnlyPart::openUrl( url
);
958 m_viewportDirty
.pageNumber
= -1;
960 setWindowTitleFromDocument();
967 bool Part::closeUrl()
969 if (!m_temporaryLocalFile
.isNull() && m_temporaryLocalFile
!= localFilePath())
971 QFile::remove( m_temporaryLocalFile
);
972 m_temporaryLocalFile
.clear();
975 slotHidePresentation();
976 m_find
->setEnabled( false );
977 m_findNext
->setEnabled( false );
978 m_saveAs
->setEnabled( false );
979 m_saveCopyAs
->setEnabled( false );
980 m_printPreview
->setEnabled( false );
981 m_showProperties
->setEnabled( false );
982 m_showEmbeddedFiles
->setEnabled( false );
983 m_exportAs
->setEnabled( false );
984 m_exportAsText
->setEnabled( false );
985 m_exportAsDocArchive
->setEnabled( false );
986 m_exportFormats
.clear();
987 QMenu
*menu
= m_exportAs
->menu();
988 QList
<QAction
*> acts
= menu
->actions();
989 int num
= acts
.count();
990 for ( int i
= 2; i
< num
; ++i
)
992 menu
->removeAction( acts
.at(i
) );
995 m_showPresentation
->setEnabled( false );
996 emit
setWindowCaption("");
997 emit
enablePrintAction(false);
999 if ( url().isLocalFile() )
1001 m_watcher
->removeFile( localFilePath() );
1002 QFileInfo
fi(localFilePath());
1003 m_watcher
->removeDir( fi
.absolutePath() );
1005 m_fileWasRemoved
= false;
1006 if ( m_generatorGuiClient
)
1007 factory()->removeClient( m_generatorGuiClient
);
1008 m_generatorGuiClient
= 0;
1009 m_document
->closeDocument();
1010 updateViewActions();
1015 m_searchWidget
->clearText();
1016 m_topMessage
->setVisible( false );
1017 m_formsMessage
->setVisible( false );
1019 #ifdef OKULAR_KEEP_FILE_OPEN
1022 return KParts::ReadOnlyPart::closeUrl();
1029 && (parent()->objectName() == QLatin1String("okular::Shell")
1030 || parent()->objectName() == QLatin1String("okular/okular__Shell")))
1034 else KMessageBox::information( widget(), i18n( "This link points to a close document action that does not work when using the embedded viewer." ), QString(), "warnNoCloseIfNotInOkular" );
1038 void Part::cannotQuit()
1040 KMessageBox::information( widget(), i18n( "This link points to a quit application action that does not work when using the embedded viewer." ), QString(), "warnNoQuitIfNotInOkular" );
1044 void Part::slotShowLeftPanel()
1046 bool showLeft
= m_showLeftPanel
->isChecked();
1047 Okular::Settings::setShowLeftPanel( showLeft
);
1048 Okular::Settings::self()->writeConfig();
1049 // show/hide left panel
1050 m_sidebar
->setSidebarVisibility( showLeft
);
1054 void Part::slotFileDirty( const QString
& path
)
1056 // The beauty of this is that each start cancels the previous one.
1057 // This means that timeout() is only fired when there have
1058 // no changes to the file for the last 750 milisecs.
1059 // This ensures that we don't update on every other byte that gets
1060 // written to the file.
1061 if ( path
== localFilePath() )
1063 m_dirtyHandler
->start( 750 );
1067 QFileInfo
fi(localFilePath());
1068 if ( fi
.absolutePath() == path
)
1070 // Our parent has been dirtified
1071 if (!QFile::exists(localFilePath()))
1073 m_fileWasRemoved
= true;
1075 else if (m_fileWasRemoved
&& QFile::exists(localFilePath()))
1077 // we need to watch the new file
1078 m_watcher
->removeFile(localFilePath());
1079 m_watcher
->addFile(localFilePath());
1080 m_dirtyHandler
->start( 750 );
1087 void Part::slotDoFileDirty()
1089 // do the following the first time the file is reloaded
1090 if ( m_viewportDirty
.pageNumber
== -1 )
1092 // store the current viewport
1093 m_viewportDirty
= m_document
->viewport();
1095 // store the current toolbox pane
1096 m_dirtyToolboxIndex
= m_sidebar
->currentIndex();
1097 m_wasSidebarVisible
= m_sidebar
->isSidebarVisible();
1099 // store if presentation view was open
1100 m_wasPresentationOpen
= ((PresentationWidget
*)m_presentationWidget
!= 0);
1102 // inform the user about the operation in progress
1103 m_pageView
->displayMessage( i18n("Reloading the document...") );
1106 // close and (try to) reopen the document
1107 if ( KParts::ReadOnlyPart::openUrl( url() ) )
1109 // on successful opening, restore the previous viewport
1110 if ( m_viewportDirty
.pageNumber
>= (int) m_document
->pages() )
1111 m_viewportDirty
.pageNumber
= (int) m_document
->pages() - 1;
1112 m_document
->setViewport( m_viewportDirty
);
1113 m_viewportDirty
.pageNumber
= -1;
1114 if ( m_sidebar
->currentIndex() != m_dirtyToolboxIndex
&& m_sidebar
->isItemEnabled( m_dirtyToolboxIndex
) )
1116 m_sidebar
->setCurrentIndex( m_dirtyToolboxIndex
);
1118 if ( m_sidebar
->isSidebarVisible() != m_wasSidebarVisible
)
1120 m_sidebar
->setCurrentIndex( m_sidebar
->currentIndex() );
1122 if (m_wasPresentationOpen
) slotShowPresentation();
1123 emit
enablePrintAction(true && m_document
->printingSupport() != Okular::Document::NoPrinting
);
1127 // start watching the file again (since we dropped it on close)
1128 m_watcher
->addFile(localFilePath());
1129 m_dirtyHandler
->start( 750 );
1134 void Part::updateViewActions()
1136 bool opened
= m_document
->pages() > 0;
1139 bool atBegin
= m_document
->currentPage() < 1;
1140 bool atEnd
= m_document
->currentPage() >= (m_document
->pages() - 1);
1141 m_gotoPage
->setEnabled( m_document
->pages() > 1 );
1142 m_firstPage
->setEnabled( !atBegin
);
1143 m_prevPage
->setEnabled( !atBegin
);
1144 m_lastPage
->setEnabled( !atEnd
);
1145 m_nextPage
->setEnabled( !atEnd
);
1146 if (m_historyBack
) m_historyBack
->setEnabled( !m_document
->historyAtBegin() );
1147 if (m_historyNext
) m_historyNext
->setEnabled( !m_document
->historyAtEnd() );
1148 m_reload
->setEnabled( true );
1149 m_copy
->setEnabled( true );
1150 m_selectAll
->setEnabled( true );
1154 m_gotoPage
->setEnabled( false );
1155 m_firstPage
->setEnabled( false );
1156 m_lastPage
->setEnabled( false );
1157 m_prevPage
->setEnabled( false );
1158 m_nextPage
->setEnabled( false );
1159 if (m_historyBack
) m_historyBack
->setEnabled( false );
1160 if (m_historyNext
) m_historyNext
->setEnabled( false );
1161 m_reload
->setEnabled( false );
1162 m_copy
->setEnabled( false );
1163 m_selectAll
->setEnabled( false );
1165 updateBookmarksActions();
1169 void Part::updateBookmarksActions()
1171 bool opened
= m_document
->pages() > 0;
1174 m_addBookmark
->setEnabled( true );
1175 if ( m_document
->bookmarkManager()->isBookmarked( m_document
->currentPage() ) )
1177 m_addBookmark
->setText( i18n( "Remove Bookmark" ) );
1178 m_addBookmark
->setIcon( KIcon( "edit-delete-bookmark" ) );
1182 m_addBookmark
->setText( m_addBookmarkText
);
1183 m_addBookmark
->setIcon( m_addBookmarkIcon
);
1188 m_addBookmark
->setEnabled( false );
1189 m_addBookmark
->setText( m_addBookmarkText
);
1190 m_addBookmark
->setIcon( m_addBookmarkIcon
);
1195 void Part::enableTOC(bool enable
)
1197 m_sidebar
->setItemEnabled(0, enable
);
1200 void Part::slotRebuildBookmarkMenu()
1202 rebuildBookmarkMenu();
1205 void Part::slotShowFindBar()
1208 m_findBar
->focusAndSetCursor();
1211 void Part::slotHideFindBar()
1214 m_pageView
->setFocus();
1217 //BEGIN go to page dialog
1218 class GotoPageDialog
: public KDialog
1221 GotoPageDialog(QWidget
*p
, int current
, int max
) : KDialog(p
)
1223 setCaption(i18n("Go to Page"));
1224 setButtons(Ok
| Cancel
);
1225 setDefaultButton(Ok
);
1227 QWidget
*w
= new QWidget(this);
1230 QVBoxLayout
*topLayout
= new QVBoxLayout(w
);
1231 topLayout
->setMargin(0);
1232 topLayout
->setSpacing(spacingHint());
1233 e1
= new KIntNumInput(current
, w
);
1234 e1
->setRange(1, max
);
1235 e1
->setEditFocus(true);
1236 e1
->setSliderEnabled(true);
1238 QLabel
*label
= new QLabel(i18n("&Page:"), w
);
1239 label
->setBuddy(e1
);
1240 topLayout
->addWidget(label
);
1241 topLayout
->addWidget(e1
);
1242 // A little bit extra space
1243 topLayout
->addSpacing(spacingHint());
1244 topLayout
->addStretch(10);
1256 //END go to page dialog
1258 void Part::slotGoToPage()
1260 GotoPageDialog
pageDialog( m_pageView
, m_document
->currentPage() + 1, m_document
->pages() );
1261 if ( pageDialog
.exec() == QDialog::Accepted
)
1262 m_document
->setViewportPage( pageDialog
.getPage() - 1 );
1266 void Part::slotPreviousPage()
1268 if ( m_document
->isOpened() && !(m_document
->currentPage() < 1) )
1269 m_document
->setViewportPage( m_document
->currentPage() - 1 );
1273 void Part::slotNextPage()
1275 if ( m_document
->isOpened() && m_document
->currentPage() < (m_document
->pages() - 1) )
1276 m_document
->setViewportPage( m_document
->currentPage() + 1 );
1280 void Part::slotGotoFirst()
1282 if ( m_document
->isOpened() )
1283 m_document
->setViewportPage( 0 );
1287 void Part::slotGotoLast()
1289 if ( m_document
->isOpened() )
1290 m_document
->setViewportPage( m_document
->pages() - 1 );
1294 void Part::slotHistoryBack()
1296 m_document
->setPrevViewport();
1300 void Part::slotHistoryNext()
1302 m_document
->setNextViewport();
1306 void Part::slotAddBookmark()
1308 uint current
= m_document
->currentPage();
1309 if ( m_document
->bookmarkManager()->isBookmarked( current
) )
1311 m_document
->bookmarkManager()->removeBookmark( current
);
1315 m_document
->bookmarkManager()->addBookmark( current
);
1320 void Part::slotPreviousBookmark()
1322 uint current
= m_document
->currentPage();
1323 // we are at the first page
1327 for ( int i
= current
- 1; i
>= 0; --i
)
1329 if ( m_document
->bookmarkManager()->isBookmarked( i
) )
1331 m_document
->setViewportPage( i
);
1338 void Part::slotNextBookmark()
1340 uint current
= m_document
->currentPage();
1341 uint pages
= m_document
->pages();
1342 // we are at the last page
1343 if ( current
== pages
)
1346 for ( uint i
= current
+ 1; i
< pages
; ++i
)
1348 if ( m_document
->bookmarkManager()->isBookmarked( i
) )
1350 m_document
->setViewportPage( i
);
1357 void Part::slotFind()
1359 // when in presentation mode, there's already a search bar, taking care of
1360 // the 'find' requests
1361 if ( (PresentationWidget
*)m_presentationWidget
!= 0 )
1363 m_presentationWidget
->slotFind();
1372 void Part::slotFindNext()
1374 if (m_findBar
->isHidden())
1377 m_findBar
->findNext();
1381 void Part::slotSaveFileAs()
1383 if (m_dummyMode
) return;
1385 KUrl saveUrl
= KFileDialog::getSaveUrl( url().isLocalFile() ? url().url() : url().fileName(), QString(), widget() );
1386 if ( !saveUrl
.isValid() || saveUrl
.isEmpty() )
1389 if ( saveUrl
.isLocalFile() )
1391 const QString fileName
= saveUrl
.toLocalFile();
1392 if ( QFile::exists( fileName
) )
1394 if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?", saveUrl
.fileName()), QString(), KGuiItem(i18n("Overwrite"))) != KMessageBox::Continue
)
1398 if ( !m_document
->saveChanges( fileName
) )
1400 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", fileName
) );
1406 if ( KIO::NetAccess::exists( saveUrl
, KIO::NetAccess::DestinationSide
, widget() ) )
1408 if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?", saveUrl
.fileName()), QString(), KGuiItem(i18n("Overwrite"))) != KMessageBox::Continue
)
1416 KMessageBox::information( widget(), i18n("Could not open the temporary file for saving." ) );
1419 fileName
= tf
.fileName();
1422 if ( !m_document
->saveChanges( fileName
) )
1424 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", fileName
) );
1428 KIO::Job
*copyJob
= KIO::file_copy( fileName
, saveUrl
, -1, KIO::Overwrite
);
1429 if ( !KIO::NetAccess::synchronousRun( copyJob
, widget() ) )
1430 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", saveUrl
.prettyUrl() ) );
1435 void Part::slotSaveCopyAs()
1437 if (m_dummyMode
) return;
1439 KUrl saveUrl
= KFileDialog::getSaveUrl( url().isLocalFile() ? url().url() : url().fileName(), QString(), widget() );
1440 if ( saveUrl
.isValid() && !saveUrl
.isEmpty() )
1442 if ( KIO::NetAccess::exists( saveUrl
, KIO::NetAccess::DestinationSide
, widget() ) )
1444 if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?", saveUrl
.fileName()), QString(), KGuiItem(i18n("Overwrite"))) != KMessageBox::Continue
)
1448 // make use of the already downloaded (in case of remote URLs) file,
1449 // no point in downloading that again
1450 KUrl srcUrl
= KUrl::fromPath( localFilePath() );
1451 KTemporaryFile
* tempFile
= 0;
1452 // duh, our local file disappeared...
1453 if ( !QFile::exists( localFilePath() ) )
1455 if ( url().isLocalFile() )
1457 #ifdef OKULAR_KEEP_FILE_OPEN
1458 // local file: try to get it back from the open handle on it
1459 if ( ( tempFile
= m_keeper
->copyToTemporary() ) )
1460 srcUrl
= KUrl::fromPath( tempFile
->fileName() );
1462 const QString msg
= i18n( "Okular cannot copy %1 to the specified location.\n\nThe document does not exist anymore.", localFilePath() );
1463 KMessageBox::sorry( widget(), msg
);
1469 // we still have the original remote URL of the document,
1470 // so copy the document from there
1475 KIO::Job
*copyJob
= KIO::file_copy( srcUrl
, saveUrl
, -1, KIO::Overwrite
);
1476 if ( !KIO::NetAccess::synchronousRun( copyJob
, widget() ) )
1477 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", saveUrl
.prettyUrl() ) );
1484 void Part::slotGetNewStuff()
1486 KNS::Engine
engine(widget());
1487 engine
.init( "okular.knsrc" );
1488 // show the modal dialog over pageview and execute it
1489 KNS::Entry::List entries
= engine
.downloadDialogModal( m_pageView
);
1494 void Part::slotPreferences()
1496 // an instance the dialog could be already created and could be cached,
1497 // in which case you want to display the cached dialog
1498 if ( PreferencesDialog::showDialog( "preferences" ) )
1501 // we didn't find an instance of this dialog, so lets create it
1502 PreferencesDialog
* dialog
= new PreferencesDialog( m_pageView
, Okular::Settings::self() );
1503 // keep us informed when the user changes settings
1504 connect( dialog
, SIGNAL( settingsChanged( const QString
& ) ), this, SLOT( slotNewConfig() ) );
1510 void Part::slotNewConfig()
1512 // Apply settings here. A good policy is to check whether the setting has
1513 // changed before applying changes.
1516 bool watchFile
= Okular::Settings::watchFile();
1517 if ( watchFile
&& m_watcher
->isStopped() )
1518 m_watcher
->startScan();
1519 if ( !watchFile
&& !m_watcher
->isStopped() )
1521 m_dirtyHandler
->stop();
1522 m_watcher
->stopScan();
1525 // Main View (pageView)
1526 m_pageView
->reparseConfig();
1528 // update document settings
1529 m_document
->reparseConfig();
1531 // update TOC settings
1532 if ( m_sidebar
->isItemEnabled(0) )
1533 m_toc
->reparseConfig();
1535 // update ThumbnailList contents
1536 if ( Okular::Settings::showLeftPanel() && !m_thumbnailList
->isHidden() )
1537 m_thumbnailList
->updateWidgets();
1541 void Part::slotNewGeneratorConfig()
1543 // Apply settings here. A good policy is to check whether the setting has
1544 // changed before applying changes.
1546 // NOTE: it's not needed to reload the configuration of the Document,
1547 // the Document itself will take care of that
1549 // Main View (pageView)
1550 m_pageView
->reparseConfig();
1552 // update TOC settings
1553 if ( m_sidebar
->isItemEnabled(0) )
1554 m_toc
->reparseConfig();
1556 // update ThumbnailList contents
1557 if ( Okular::Settings::showLeftPanel() && !m_thumbnailList
->isHidden() )
1558 m_thumbnailList
->updateWidgets();
1562 void Part::slotPrintPreview()
1564 if (m_document
->pages() == 0) return;
1568 // Native printing supports KPrintPreview, Postscript needs to use FilePrinterPreview
1569 if ( m_document
->printingSupport() == Okular::Document::NativePrinting
)
1571 KPrintPreview
previewdlg( &printer
, widget() );
1572 setupPrint( printer
);
1578 // Generate a temp filename for Print to File, then release the file so generator can write to it
1580 tf
.setAutoRemove( true );
1581 tf
.setSuffix( ".ps" );
1583 printer
.setOutputFileName( tf
.fileName() );
1585 setupPrint( printer
);
1587 if ( QFile::exists( printer
.outputFileName() ) )
1589 Okular::FilePrinterPreview
previewdlg( printer
.outputFileName(), widget() );
1596 void Part::slotShowMenu(const Okular::Page
*page
, const QPoint
&point
)
1598 if (m_dummyMode
) return;
1600 bool reallyShow
= false;
1601 if (!m_actionsSearched
)
1603 // the quest for options_show_menubar
1604 KActionCollection
*ac
;
1609 QList
<KXMLGUIClient
*> clients(factory()->clients());
1610 for(int i
= 0 ; (!m_showMenuBarAction
|| !m_showFullScreenAction
) && i
< clients
.size(); ++i
)
1612 ac
= clients
.at(i
)->actionCollection();
1614 act
= ac
->action("options_show_menubar");
1615 if (act
&& qobject_cast
<KToggleAction
*>(act
))
1616 m_showMenuBarAction
= qobject_cast
<KToggleAction
*>(act
);
1618 act
= ac
->action("fullscreen");
1619 if (act
&& qobject_cast
<KToggleFullScreenAction
*>(act
))
1620 m_showFullScreenAction
= qobject_cast
<KToggleFullScreenAction
*>(act
);
1623 m_actionsSearched
= true;
1626 KMenu
*popup
= new KMenu( widget() );
1627 QAction
*addBookmark
= 0;
1628 QAction
*removeBookmark
= 0;
1629 QAction
*fitPageWidth
= 0;
1632 popup
->addTitle( i18n( "Page %1", page
->number() + 1 ) );
1633 if ( m_document
->bookmarkManager()->isBookmarked( page
->number() ) )
1634 removeBookmark
= popup
->addAction( KIcon("edit-delete-bookmark"), i18n("Remove Bookmark") );
1636 addBookmark
= popup
->addAction( KIcon("bookmark-new"), i18n("Add Bookmark") );
1637 if ( m_pageView
->canFitPageWidth() )
1638 fitPageWidth
= popup
->addAction( KIcon("zoom-fit-best"), i18n("Fit Width") );
1639 popup
->addAction( m_prevBookmark
);
1640 popup
->addAction( m_nextBookmark
);
1644 //Albert says: I have not ported this as i don't see it does anything
1645 if ( d->mouseOnRect ) // and rect->objectType() == ObjectRect::Image ...
1647 m_popup->insertItem( SmallIcon("document-save"), i18n("Save Image..."), 4 );
1648 m_popup->setItemEnabled( 4, false );
1651 if ((m_showMenuBarAction
&& !m_showMenuBarAction
->isChecked()) || (m_showFullScreenAction
&& m_showFullScreenAction
->isChecked()))
1653 popup
->addTitle( i18n( "Tools" ) );
1654 if (m_showMenuBarAction
&& !m_showMenuBarAction
->isChecked()) popup
->addAction(m_showMenuBarAction
);
1655 if (m_showFullScreenAction
&& m_showFullScreenAction
->isChecked()) popup
->addAction(m_showFullScreenAction
);
1662 QAction
*res
= popup
->exec(point
);
1665 if (res
== addBookmark
) m_document
->bookmarkManager()->addBookmark( page
->number() );
1666 else if (res
== removeBookmark
) m_document
->bookmarkManager()->removeBookmark( page
->number() );
1667 else if (res
== fitPageWidth
) m_pageView
->fitPageWidth( page
->number() );
1674 void Part::slotShowProperties()
1676 PropertiesDialog
*d
= new PropertiesDialog(widget(), m_document
);
1682 void Part::slotShowEmbeddedFiles()
1684 EmbeddedFilesDialog
*d
= new EmbeddedFilesDialog(widget(), m_document
);
1690 void Part::slotShowPresentation()
1692 if ( !m_presentationWidget
)
1694 m_presentationWidget
= new PresentationWidget( widget(), m_document
);
1695 m_presentationWidget
->setupActions( actionCollection() );
1700 void Part::slotHidePresentation()
1702 if ( m_presentationWidget
)
1703 delete (PresentationWidget
*) m_presentationWidget
;
1707 void Part::slotTogglePresentation()
1709 if ( m_document
->isOpened() )
1711 if ( !m_presentationWidget
)
1712 m_presentationWidget
= new PresentationWidget( widget(), m_document
);
1713 else delete (PresentationWidget
*) m_presentationWidget
;
1720 if ( m_document
->isOpened() )
1727 void Part::slotAboutBackend()
1729 const KComponentData
*data
= m_document
->componentData();
1733 KAboutApplicationDialog
dlg( data
->aboutData(), widget() );
1738 void Part::slotExportAs(QAction
* act
)
1740 QList
<QAction
*> acts
= m_exportAs
->menu() ? m_exportAs
->menu()->actions() : QList
<QAction
*>();
1741 int id
= acts
.indexOf( act
);
1742 if ( ( id
< 0 ) || ( id
>= acts
.count() ) )
1749 filter
= "text/plain";
1752 filter
= "application/vnd.kde.okular-archive";
1755 filter
= m_exportFormats
.at( id
- 2 ).mimeType()->name();
1758 QString fileName
= KFileDialog::getSaveFileName( url().isLocalFile() ? url().directory() : QString(), filter
, widget() );
1759 if ( !fileName
.isEmpty() )
1765 saved
= m_document
->exportToText( fileName
);
1768 saved
= m_document
->saveDocumentArchive( fileName
);
1771 saved
= m_document
->exportTo( fileName
, m_exportFormats
.at( id
- 2 ) );
1775 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", fileName
) );
1780 void Part::slotReload()
1782 // stop the dirty handler timer, otherwise we may conflict with the
1783 // auto-refresh system
1784 m_dirtyHandler
->stop();
1790 void Part::slotPrint()
1792 if (m_document
->pages() == 0) return;
1795 QPrintDialog
*printDialog
= 0;
1796 QWidget
*printConfigWidget
= 0;
1798 // Must do certain QPrinter setup before creating QPrintDialog
1799 setupPrint( printer
);
1801 // Create the Print Dialog with extra config widgets if required
1802 if ( m_document
->canConfigurePrinter() )
1804 printConfigWidget
= m_document
->printConfigurationWidget();
1806 if ( printConfigWidget
)
1808 printDialog
= KdePrint::createPrintDialog( &printer
, QList
<QWidget
*>() << printConfigWidget
, widget() );
1812 printDialog
= KdePrint::createPrintDialog( &printer
, widget() );
1818 // Set the available Print Range
1819 printDialog
->setMinMax( 1, m_document
->pages() );
1820 printDialog
->setFromTo( 1, m_document
->pages() );
1822 // If the user has bookmarked pages for printing, then enable Selection
1823 if ( !m_document
->bookmarkedPageRange().isEmpty() )
1825 printDialog
->addEnabledOption( QAbstractPrintDialog::PrintSelection
);
1828 // If the Document type doesn't support print to both PS & PDF then disable the Print Dialog option
1829 if ( printDialog
->isOptionEnabled( QAbstractPrintDialog::PrintToFile
) &&
1830 !m_document
->supportsPrintToFile() )
1832 printDialog
->setEnabledOptions( printDialog
->enabledOptions() ^ QAbstractPrintDialog::PrintToFile
);
1835 if ( printDialog
->exec() )
1842 void Part::setupPrint( QPrinter
&printer
)
1844 double width
, height
;
1845 int landscape
, portrait
;
1846 const Okular::Page
*page
;
1848 // if some pages are landscape and others are not the most common win as QPrinter does
1849 // not accept a per page setting
1852 for (uint i
= 0; i
< m_document
->pages(); i
++)
1854 page
= m_document
->page(i
);
1855 width
= page
->width();
1856 height
= page
->height();
1857 if (page
->orientation() == Okular::Rotation90
|| page
->orientation() == Okular::Rotation270
) qSwap(width
, height
);
1858 if (width
> height
) landscape
++;
1861 if (landscape
> portrait
) printer
.setOrientation(QPrinter::Landscape
);
1864 QString title
= m_document
->metaData( "DocumentTitle" ).toString();
1865 if ( title
.isEmpty() )
1867 title
= m_document
->currentDocument().fileName();
1869 if ( !title
.isEmpty() )
1871 printer
.setDocName( title
);
1876 void Part::doPrint(QPrinter
&printer
)
1878 if (!m_document
->isAllowed(Okular::AllowPrint
))
1880 KMessageBox::error(widget(), i18n("Printing this document is not allowed."));
1884 if (!m_document
->print(printer
))
1886 KMessageBox::error(widget(), i18n("Could not print the document. Please report to bugs.kde.org"));
1891 void Part::restoreDocument(const KConfigGroup
&group
)
1893 KUrl
url ( group
.readPathEntry( "URL", QString() ) );
1894 if ( url
.isValid() )
1896 QString viewport
= group
.readEntry( "Viewport" );
1897 if (!viewport
.isEmpty()) m_document
->setNextDocumentViewport( Okular::DocumentViewport( viewport
) );
1903 void Part::saveDocumentRestoreInfo(KConfigGroup
&group
)
1905 group
.writePathEntry( "URL", url().url() );
1906 group
.writeEntry( "Viewport", m_document
->viewport().toString() );
1910 void Part::psTransformEnded(int exit
, QProcess::ExitStatus status
)
1913 if ( status
!= QProcess::NormalExit
)
1916 QProcess
*senderobj
= sender() ? qobject_cast
< QProcess
* >( sender() ) : 0;
1920 senderobj
->deleteLater();
1923 setLocalFilePath( m_temporaryLocalFile
);
1924 openUrl( m_temporaryLocalFile
);
1925 m_temporaryLocalFile
.clear();
1929 void Part::unsetDummyMode()
1931 if (!m_dummyMode
) return;
1933 m_dummyMode
= false;
1935 m_sidebar
->setItemEnabled( 2, true );
1936 m_sidebar
->setItemEnabled( 3, true );
1937 m_sidebar
->setSidebarVisibility( Okular::Settings::showLeftPanel() );
1939 // add back and next in history
1940 m_historyBack
= KStandardAction::documentBack( this, SLOT( slotHistoryBack() ), actionCollection() );
1941 m_historyBack
->setWhatsThis( i18n( "Go to the place you were before" ) );
1943 m_historyNext
= KStandardAction::documentForward( this, SLOT( slotHistoryNext() ), actionCollection());
1944 m_historyNext
->setWhatsThis( i18n( "Go to the place you were after" ) );
1946 m_pageView
->setupActions( actionCollection() );
1948 // attach the actions of the children widgets too
1949 m_formsMessage
->setActionButton( m_pageView
->toggleFormsAction() );
1951 // ensure history actions are in the correct state
1952 updateViewActions();
1956 bool Part::handleCompressed( QString
&destpath
, const QString
&path
, const QString
&compressedMimetype
)
1960 // we are working with a compressed file, decompressing
1961 // temporary file for decompressing
1962 KTemporaryFile
*newtempfile
= new KTemporaryFile();
1963 newtempfile
->setAutoRemove(true);
1965 if ( !newtempfile
->open() )
1967 KMessageBox::error( widget(),
1968 i18n("<qt><strong>File Error!</strong> Could not create temporary file "
1969 "<nobr><strong>%1</strong></nobr>.</qt>",
1970 strerror(newtempfile
->error())));
1975 // decompression filer
1976 QIODevice
* filterDev
= KFilterDev::deviceForFile( path
, compressedMimetype
);
1983 if ( !filterDev
->open(QIODevice::ReadOnly
) )
1985 KMessageBox::detailedError( widget(),
1986 i18n("<qt><strong>File Error!</strong> Could not open the file "
1987 "<nobr><strong>%1</strong></nobr> for uncompression. "
1988 "The file will not be loaded.</qt>", path
),
1989 i18n("<qt>This error typically occurs if you do "
1990 "not have enough permissions to read the file. "
1991 "You can check ownership and permissions if you "
1992 "right-click on the file in the Dolphin "
1993 "file manager and then choose the 'Properties' tab.</qt>"));
2000 QByteArray
buf(1024, '\0');
2001 int read
= 0, wrtn
= 0;
2003 while ((read
= filterDev
->read(buf
.data(), buf
.size())) > 0)
2005 wrtn
= newtempfile
->write(buf
.data(), read
);
2010 if ((read
!= 0) || (newtempfile
->size() == 0))
2012 KMessageBox::detailedError(widget(),
2013 i18n("<qt><strong>File Error!</strong> Could not uncompress "
2014 "the file <nobr><strong>%1</strong></nobr>. "
2015 "The file will not be loaded.</qt>", path
),
2016 i18n("<qt>This error typically occurs if the file is corrupt. "
2017 "If you want to be sure, try to decompress the file manually "
2018 "using command-line tools.</qt>"));
2022 m_tempfile
= newtempfile
;
2023 destpath
= m_tempfile
->fileName();
2027 void Part::rebuildBookmarkMenu( bool unplugActions
)
2029 if ( unplugActions
)
2031 unplugActionList( "bookmarks_currentdocument" );
2032 qDeleteAll( m_bookmarkActions
);
2033 m_bookmarkActions
.clear();
2035 KUrl u
= m_document
->currentDocument();
2038 m_bookmarkActions
= m_document
->bookmarkManager()->actionsForUrl( u
);
2040 bool havebookmarks
= true;
2041 if ( m_bookmarkActions
.isEmpty() )
2043 havebookmarks
= false;
2044 QAction
* a
= new QAction( 0 );
2045 a
->setText( i18n( "No Bookmarks" ) );
2046 a
->setEnabled( false );
2047 m_bookmarkActions
.append( a
);
2049 for ( int i
= 0; i
< m_bookmarkActions
.count(); ++i
)
2051 actionCollection()->addAction( QString( "bookmark_action_%1" ).arg( i
), m_bookmarkActions
.at(i
) );
2053 plugActionList( "bookmarks_currentdocument", m_bookmarkActions
);
2055 m_prevBookmark
->setEnabled( havebookmarks
);
2056 m_nextBookmark
->setEnabled( havebookmarks
);
2059 void Part::updateAboutBackendAction()
2061 const KComponentData
*data
= m_document
->componentData();
2064 m_aboutBackend
->setEnabled( true );
2068 m_aboutBackend
->setEnabled( false );
2075 /* kate: replace-tabs on; indent-width 4; */