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>
34 #include <QtGui/QPrintPreviewDialog>
38 #include <kaboutapplicationdialog.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>
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>
60 #include <kdecompressor.h>
61 #include <kdeprintdialog.h>
62 #include <kbookmarkmenu.h>
63 #include <kpassworddialog.h>
64 #include <kpasswdstore.h>
67 #include "aboutdata.h"
68 #include "extensions.h"
69 #include "ui/pageview.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"
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"
107 void open( const QString & path )
110 m_handle = std::fopen( QFile::encodeName( path ), "r" );
117 int ret = std::fclose( m_handle );
123 KTemporaryFile* copyToTemporary() const
128 KTemporaryFile * retFile = new KTemporaryFile;
131 std::rewind( m_handle );
135 c = std::fgetc( m_handle );
138 if ( !retFile->putChar( (char)c ) )
140 } while ( !feof( m_handle ) );
148 std::FILE * m_handle;
151 Okular::PartFactory::PartFactory()
152 : KPluginFactory(okularAboutData( "okular", I18N_NOOP( "Okular" ) ))
156 Okular::PartFactory::~PartFactory()
160 QObject *Okular::PartFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString &keyword)
162 Q_UNUSED ( keyword );
164 Okular::Part *object = new Okular::Part( parentWidget, parent, args, componentData() );
165 object->setReadWrite( QLatin1String(iface) == QLatin1String("KParts::ReadWritePart") );
169 K_EXPORT_PLUGIN( Okular::PartFactory() )
171 static QAction* actionForExportFormat( const Okular::ExportFormat& format, QObject *parent = 0 )
173 QAction *act = new QAction( format.description(), parent );
174 if ( !format.icon().isNull() )
176 act->setIcon( format.icon() );
181 static QString compressedMimeFor( const QString& mime_to_check )
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 )
192 // check we can read bzip2-compressed files
193 if ( f.setType( KDecompressor::TypeBZip2 ) )
197 // check we can read XZ-compressed files
198 if ( f.setType( KDecompressor::TypeXZ ) )
202 supportChecked = true;
205 // The "is()" calls below check inheritance too
206 KMimeType::Ptr mime = KMimeType::mimeType( mime_to_check );
209 if ( mime->is( app_gzip ) )
211 else if ( supportBzip && mime->is( app_bzip ) )
213 else if ( supportXz && mime->is( app_xz ) )
220 static Okular::EmbedMode detectEmbedMode( QWidget *parentWidget, QObject *parent, const QVariantList &args )
222 Q_UNUSED( parentWidget );
225 && ( parent->objectName() == QLatin1String( "okular::Shell" )
226 || parent->objectName() == QLatin1String( "okular/okular__Shell" ) ) )
227 return Okular::NativeShellMode;
229 Q_FOREACH ( const QVariant &arg, args )
231 if ( arg.type() == QVariant::String )
233 if ( arg.toString() == QLatin1String( "Print/Preview" ) )
235 return Okular::PrintPreviewMode;
237 else if ( arg.toString() == QLatin1String( "ViewerWidget" ) )
239 return Okular::ViewerWidgetMode;
244 return Okular::UnknownEmbedMode;
247 static QString detectConfigFileName( const QVariantList &args )
249 Q_FOREACH ( const QVariant &arg, args )
251 if ( arg.type() == QVariant::String )
253 QString argString = arg.toString();
254 int separatorIndex = argString.indexOf( "=" );
255 if ( separatorIndex >= 0 && argString.left( separatorIndex ) == QLatin1String( "ConfigFileName" ) )
257 return argString.mid( separatorIndex + 1 );
265 #undef OKULAR_KEEP_FILE_OPEN
267 #ifdef OKULAR_KEEP_FILE_OPEN
268 static bool keepFileOpen()
270 static bool keep_file_open = !qgetenv("OKULAR_NO_KEEP_FILE_OPEN").toInt();
271 return keep_file_open;
275 int Okular::Part::numberOfParts = 0;
280 Part::Part(QWidget *parentWidget,
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 )
288 setObjectName(QString::fromLatin1("OkularPart"));
290 // first, we check if a config file name has been specified
291 QString configFileName = detectConfigFileName( args );
292 if ( configFileName.isEmpty() )
294 configFileName = KStandardDirs::locateLocal( "config", "okularpartrc" );
296 Okular::Settings::instance( configFileName );
299 if (numberOfParts == 1) {
300 QDBusConnection::sessionBus().registerObject("/okular", this, QDBusConnection::ExportScriptableSlots);
302 QDBusConnection::sessionBus().registerObject(QString("/okular%1").arg(numberOfParts), this, QDBusConnection::ExportScriptableSlots);
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*)));
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)));
313 // create browser extension (for printing when embedded into browser)
314 m_bExtension = new BrowserExtension(this);
316 // we need an instance
317 setComponentData( componentData );
319 m_sidebar = new Sidebar( parentWidget );
320 setWidget( m_sidebar );
321 connect( m_sidebar, SIGNAL(urlsDropped(KUrl::List)), SLOT(handleDroppedUrls(KUrl::List)) );
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()) );
333 if ( parent && parent->metaObject()->indexOfSlot( QMetaObject::normalizedSignature( "slotQuit()" ) ) != -1 )
334 connect( m_document, SIGNAL(quit()), parent, SLOT(slotQuit()) );
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 );
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") );
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 );
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 );
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 );
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 ) );
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 );
443 m_pageNumberTool = new MiniBar( 0, m_miniBarLogic );
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*)));
451 connect( m_reviewsWidget, SIGNAL(openAnnotationWindow(Okular::Annotation*,int)),
452 m_pageView, SLOT(openAnnotationWindow(Okular::Annotation*,int)) );
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 );
464 m_document->addObserver( m_reviewsWidget );
465 m_document->addObserver( m_pageSizeLabel );
466 m_document->addObserver( m_bookmarkList );
468 connect( m_document->bookmarkManager(), SIGNAL(saved()),
469 this, SLOT(slotRebuildBookmarkMenu()) );
471 setupViewerActions();
473 if ( m_embedMode != ViewerWidgetMode )
479 setViewerShortcuts();
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()) );
491 // keep us informed when the user changes settings
492 connect( Okular::Settings::self(), SIGNAL(configChanged()), this, SLOT(slotNewConfig()) );
494 rebuildBookmarkMenu( false );
496 if ( m_embedMode == ViewerWidgetMode ) {
497 // set the XML-UI resource file for the viewer mode
498 setXMLFile("part-viewermode.rc");
502 // set our main XML-UI resource file
503 setXMLFile("part.rc");
506 m_pageView->setupBaseActions( actionCollection() );
508 m_sidebar->setSidebarVisibility( false );
509 if ( m_embedMode != PrintPreviewMode )
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 )
520 // ensure history actions are in the correct state
523 // also update the state of the actions in the page view
524 m_pageView->updateActionState( false, false, false );
526 if ( m_embedMode == NativeShellMode )
527 m_sidebar->setAutoFillBackground( false );
529 #ifdef OKULAR_KEEP_FILE_OPEN
530 m_keeper = new FileKeeper();
534 void Part::setupViewerActions()
537 KActionCollection * ac = actionCollection();
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()) );
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()) );
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()) );
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" ) );
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" ) );
580 // we do not want back and next in history in the dummy mode
584 m_addBookmark = KStandardAction::addBookmark( this, SLOT(slotAddBookmark()), ac );
585 m_addBookmarkText = m_addBookmark->text();
586 m_addBookmarkIcon = m_addBookmark->icon();
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()) );
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()) );
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()) );
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 );
617 m_findNext = KStandardAction::findNext( this, SLOT(slotFindNext()), ac);
618 m_findNext->setEnabled( false );
620 m_findPrev = KStandardAction::findPrev( this, SLOT(slotFindPrev()), ac );
621 m_findPrev->setEnabled( false );
626 QAction * prefs = KStandardAction::preferences( this, SLOT(slotPreferences()), ac);
627 if ( m_embedMode == NativeShellMode )
629 prefs->setText( i18n( "Configure Okular..." ) );
633 // TODO: improve this message
634 prefs->setText( i18n( "Configure Viewer..." ) );
637 KAction * genPrefs = new KAction( ac );
638 ac->addAction("options_configure_generators", genPrefs);
639 if ( m_embedMode == ViewerWidgetMode )
641 genPrefs->setText( i18n( "Configure Viewer Backends..." ) );
645 genPrefs->setText( i18n( "Configure Backends..." ) );
647 genPrefs->setIcon( KIcon( "configure" ) );
648 genPrefs->setEnabled( m_document->configurableGenerators() > 0 );
649 connect( genPrefs, SIGNAL(triggered(bool)), this, SLOT(slotGeneratorPreferences()) );
651 m_printPreview = KStandardAction::printPreview( this, SLOT(slotPrintPreview()), ac );
652 m_printPreview->setEnabled( false );
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 );
663 m_showEmbeddedFiles = 0;
664 m_showPresentation = 0;
669 m_exportAsDocArchive = 0;
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()));
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() );
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 );
690 KAction *pageno = new KAction( i18n( "Page Number" ), ac );
691 pageno->setDefaultWidget( m_pageNumberTool );
692 ac->addAction( "page_number", pageno );
695 void Part::setViewerShortcuts()
697 KActionCollection * ac = actionCollection();
699 m_gotoPage->setShortcut( QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_G) );
700 m_find->setShortcuts( QList<QKeySequence>() );
702 m_findNext->setShortcut( QKeySequence() );
703 m_findPrev->setShortcut( QKeySequence() );
705 m_addBookmark->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_B ) );
707 m_beginningOfDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_Home ) );
708 m_endOfDocument->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_End ) );
710 KAction *action = static_cast<KAction*>( ac->action( "file_reload" ) );
711 if( action ) action->setShortcuts( QList<QKeySequence>() << QKeySequence( Qt::ALT + Qt::Key_F5 ) );
714 void Part::setupActions()
716 KActionCollection * ac = actionCollection();
718 m_copy = KStandardAction::create( KStandardAction::Copy, m_pageView, SLOT(copyTextSelection()), ac );
720 m_selectAll = KStandardAction::selectAll( m_pageView, SLOT(selectAll()), ac );
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 );
728 m_saveAs = KStandardAction::saveAs( this, SLOT(slotSaveFileAs()), ac );
729 m_saveAs->setEnabled( false );
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() );
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() );
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 );
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 );
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 );
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 );
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 );
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 );
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()));
795 KAction *playPauseAction = new KAction( i18n( "Play/Pause Presentation" ), ac );
796 ac->addAction( "presentation_play_pause", playPauseAction );
797 playPauseAction->setEnabled( false );
802 m_document->removeObserver( this );
803 m_document->removeObserver( m_toc );
805 if ( m_document->isOpened() )
806 Part::closeUrl( false );
810 delete m_thumbnailList;
812 delete m_pageNumberTool;
813 delete m_miniBarLogic;
815 #ifdef OKULAR_ENABLE_MINIBAR
816 delete m_progressWidget;
818 delete m_pageSizeLabel;
819 delete m_reviewsWidget;
820 delete m_bookmarkList;
827 qDeleteAll( m_bookmarkActions );
829 delete m_exportAsMenu;
831 #ifdef OKULAR_KEEP_FILE_OPEN
837 bool Part::openDocument(const KUrl& url, uint page)
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;
845 m_document->setNextDocumentViewport( vp );
846 return openUrl( url );
850 void Part::startPresentation()
852 m_cliPresentation = true;
856 QStringList Part::supportedMimeTypes() const
858 return m_document->supportedMimeTypes();
862 KUrl Part::realUrl() const
864 if ( !m_realUrl.isEmpty() )
872 void Part::showSourceLocation(const QString& fileName, int line, int column, bool showGraphically)
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 )
879 m_pageView->setLastSourceLocationViewport( m_document->viewport() );
883 void Part::clearLastShownSourceLocation()
885 m_pageView->clearLastSourceLocationViewport();
888 bool Part::isWatchFileModeEnabled() const
893 void Part::setWatchFileModeEnabled(bool enabled)
895 if( !enabled && isWatchFileModeEnabled() )
897 m_dirtyHandler->stop();
901 bool Part::areSourceLocationsShownGraphically() const
903 return m_pageView->areSourceLocationsShownGraphically();
906 void Part::setShowSourceLocationsGraphically(bool show)
908 m_pageView->setShowSourceLocationsGraphically(show);
911 bool Part::openNewFilesInTabs() const
913 return Okular::Settings::self()->shellOpenFileInTabs();
916 void Part::slotHandleActivatedSourceReference(const QString& absFileName, int line, int col, bool *handled)
918 emit openSourceReference( absFileName, line, col );
919 if ( m_embedMode == Okular::ViewerWidgetMode )
925 void Part::openUrlFromDocument(const KUrl &url)
927 if ( m_embedMode == PrintPreviewMode )
930 if (KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, widget()))
932 m_bExtension->openUrlNotify();
933 m_bExtension->setLocationBarUrl(url.prettyUrl());
936 KMessageBox::error( widget(), i18n("Could not open '%1'. File does not exist", url.pathOrUrl() ) );
940 void Part::openUrlFromBookmarks(const KUrl &_url)
943 Okular::DocumentViewport vp( _url.fragment() );
945 m_document->setNextDocumentViewport( vp );
946 url.setFragment( QString() );
947 if ( m_document->currentDocument() == url )
950 m_document->setViewport( vp );
956 void Part::handleDroppedUrls( const KUrl::List& urls )
958 if ( urls.isEmpty() )
961 if ( m_embedMode != NativeShellMode || !openNewFilesInTabs() )
963 openUrlFromDocument( urls.first() );
967 emit urlsDropped( urls );
970 void Part::slotJobStarted(KIO::Job *job)
974 QStringList supportedMimeTypes = m_document->supportedMimeTypes();
975 job->addMetaData("accept", supportedMimeTypes.join(", ") + ", */*;q=0.5");
977 connect(job, SIGNAL(result(KJob*)), this, SLOT(slotJobFinished(KJob*)));
981 void Part::slotJobFinished(KJob *job)
983 if ( job->error() == KIO::ERR_USER_CANCELED )
985 m_pageView->displayMessage( i18n( "The loading of %1 has been canceled.", realUrl().pathOrUrl() ) );
989 void Part::loadCancelled(const QString &reason)
991 emit setWindowCaption( QString() );
992 resetStartArguments();
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)
999 if (!reason.isEmpty())
1001 KMessageBox::error( widget(), i18n("Could not open %1. Reason: %2", url().prettyUrl(), reason ) );
1006 void Part::setWindowTitleFromDocument()
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();
1012 if ( Okular::Settings::displayDocumentTitle() )
1014 const QString docTitle = m_document->metaData( "DocumentTitle" ).toString();
1015 if ( !docTitle.isEmpty() && !docTitle.trimmed().isEmpty() )
1021 emit setWindowCaption( title );
1024 KConfigDialog * Part::slotGeneratorPreferences( )
1027 KConfigDialog * dialog = new KConfigDialog( m_pageView, "generator_prefs", Okular::Settings::self() );
1028 dialog->setAttribute( Qt::WA_DeleteOnClose );
1030 if( m_embedMode == ViewerWidgetMode )
1032 dialog->setCaption( i18n( "Configure Viewer Backends" ) );
1036 dialog->setCaption( i18n( "Configure Backends" ) );
1039 m_document->fillConfigDialog( dialog );
1042 dialog->setWindowModality( Qt::ApplicationModal );
1049 void Part::notifySetup( const QVector< Okular::Page * > & /*pages*/, int setupFlags )
1051 if ( !( setupFlags & Okular::DocumentObserver::DocumentChanged ) )
1054 rebuildBookmarkMenu();
1055 updateAboutBackendAction();
1056 m_findBar->resetSearch();
1057 m_searchWidget->setEnabled( m_document->supportsSearching() );
1060 void Part::notifyViewportChanged( bool /*smoothMove*/ )
1062 updateViewActions();
1065 void Part::notifyPageChanged( int page, int flags )
1067 if ( flags & Okular::DocumentObserver::NeedSaveAs )
1070 if ( !(flags & Okular::DocumentObserver::Bookmark ) )
1073 rebuildBookmarkMenu();
1074 if ( page == m_document->viewport().pageNumber )
1075 updateBookmarksActions();
1079 void Part::goToPage(uint i)
1081 if ( i <= m_document->pages() )
1082 m_document->setViewportPage( i - 1 );
1086 void Part::openDocument( const QString &doc )
1088 openUrl( KUrl( doc ) );
1094 return m_document->pages();
1098 uint Part::currentPage()
1100 return m_document->pages() ? m_document->currentPage() + 1 : 0;
1104 QString Part::currentDocument()
1106 return m_document->currentDocument().pathOrUrl();
1110 QString Part::documentMetaData( const QString &metaData ) const
1112 const Okular::DocumentInfo * info = m_document->documentInfo();
1115 QDomElement docElement = info->documentElement();
1116 for ( QDomNode node = docElement.firstChild(); !node.isNull(); node = node.nextSibling() )
1118 const QDomElement element = node.toElement();
1119 if ( metaData.compare( element.tagName(), Qt::CaseInsensitive ) == 0 )
1120 return element.attribute( "value" );
1127 static void addFileToWatcher( KDirWatch *watcher, const QString &filePath)
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() );
1135 Document::OpenResult Part::doOpenFile( const KMimeType::Ptr &mimeA, const QString &fileNameToOpenA, bool *isCompressedFile )
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() );
1146 if ( !compressedMime.isEmpty() )
1148 *isCompressedFile = true;
1149 uncompressOk = handleCompressed( fileNameToOpen, localFilePath(), compressedMime );
1150 mime = KMimeType::findByPath( fileNameToOpen );
1154 *isCompressedFile = false;
1157 isDocumentArchive = false;
1160 if ( mime->is( "application/vnd.kde.okular-archive" ) )
1162 openResult = m_document->openDocumentArchive( fileNameToOpen, url() );
1163 isDocumentArchive = true;
1167 openResult = m_document->openDocument( fileNameToOpen, url(), mime );
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;
1176 while ( openResult == Document::OpenNeedsPassword )
1179 bool storeopened = false;
1180 const WId parentwid = widget()->effectiveWinId();
1182 QByteArray obscuredWalletKey = KPasswdStore::makeKey(walletKey);
1184 // 1.A. try to retrieve the first password from the kde store system
1185 if ( !triedWallet && !walletKey.isNull() )
1187 store.setStoreID(walletName);
1188 storeopened = store.openStore( parentwid );
1191 // look for the pass in that folder
1192 QString retrievedPass = store.getPasswd( obscuredWalletKey, parentwid );
1193 if (!retrievedPass.isEmpty())
1194 password = retrievedPass;
1199 // 1.B. if not retrieved, ask the password using the kde password dialog
1200 if ( password.isNull() )
1204 prompt = i18n( "Please enter the password to read the document:" );
1206 prompt = i18n( "Incorrect password. Try again:" );
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 );
1215 password = dlg.password();
1217 keep = dlg.keepPassword();
1220 // 2. reopen the document using the password
1221 if ( mime->is( "application/vnd.kde.okular-archive" ) )
1223 openResult = m_document->openDocumentArchive( fileNameToOpen, url(), password );
1224 isDocumentArchive = true;
1228 openResult = m_document->openDocument( fileNameToOpen, url(), mime, password );
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 )
1234 store.storePasswd( obscuredWalletKey, password, parentwid );
1242 bool Part::openFile()
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() )
1250 KMimeType::Ptr pathMime = KMimeType::findByPath( fileNameToOpen );
1251 if ( !arguments().mimeType().isEmpty() )
1253 KMimeType::Ptr argMime = KMimeType::mimeType( arguments().mimeType() );
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() ) )
1262 else if ( pathMime->is( argMime->name() ) )
1268 mimes << pathMime << argMime;
1271 if (mimes[0]->name() == "text/plain") {
1272 KMimeType::Ptr contentMime = KMimeType::findByFileContent( fileNameToOpen );
1273 mimes.prepend( contentMime );
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 );
1289 bool canSearch = m_document->supportsSearching();
1290 emit mimeTypeChanged( mime );
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() );
1307 // m_pageView->toggleFormsAction() may be null on dummy mode
1308 if ( ok && m_pageView->toggleFormsAction() && m_pageView->toggleFormsAction()->isEnabled() )
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 );
1316 m_formsMessage->setVisible( false );
1319 if ( m_showPresentation ) m_showPresentation->setEnabled( ok );
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 )
1330 menu->addAction( actionForExportFormat( *it ) );
1333 if ( isCompressedFile )
1337 #ifdef OKULAR_KEEP_FILE_OPEN
1338 if ( keepFileOpen() )
1339 m_keeper->open( fileNameToOpen );
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 );
1346 // update viewing actions
1347 updateViewActions();
1349 m_fileWasRemoved = false;
1353 // if can't open document, update windows so they display blank contents
1354 m_pageView->viewport()->update();
1355 m_thumbnailList->update();
1360 // set the file to the fileWatcher
1361 if ( url().isLocalFile() )
1363 addFileToWatcher( m_watcher, localFilePath() );
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 )
1369 m_sidebar->setCurrentIndex( 0, Sidebar::DoNotUncollapseIfCollapsed );
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 )
1375 bool goAheadWithPresentationMode = true;
1376 if ( !m_cliPresentation )
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;
1387 m_cliPresentation = false;
1388 if ( goAheadWithPresentationMode )
1389 QMetaObject::invokeMethod( this, "slotShowPresentation", Qt::QueuedConnection );
1391 m_generatorGuiClient = factory() ? m_document->guiClient() : 0;
1392 if ( m_generatorGuiClient )
1393 factory()->addClient( m_generatorGuiClient );
1402 bool Part::openUrl(const KUrl &_url)
1404 // Close current document if any
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) );
1418 if ( url.hasFragment() )
1420 const QString dest = url.fragment();
1422 const int page = dest.toInt( &ok );
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 );
1434 m_document->setNextDocumentDestination( dest );
1436 url.setFragment( QString() );
1439 // this calls in sequence the 'closeUrl' and 'openFile' methods
1440 bool openOk = KParts::ReadWritePart::openUrl( url );
1444 m_viewportDirty.pageNumber = -1;
1446 setWindowTitleFromDocument();
1450 resetStartArguments();
1451 KMessageBox::error( widget(), i18n("Could not open %1", url.pathOrUrl() ) );
1457 bool Part::queryClose()
1459 if ( !isReadWrite() || !isModified() )
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() );
1470 case KMessageBox::Yes: // Save as
1472 return !isModified(); // Only allow closing if file was really saved
1473 case KMessageBox::No: // Discard
1480 bool Part::closeUrl(bool promptToSave)
1482 if ( promptToSave && !queryClose() )
1485 setModified( false );
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();
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 )
1508 menu->removeAction( acts.at(i) );
1512 if ( m_showPresentation ) m_showPresentation->setEnabled( false );
1513 emit setWindowCaption("");
1514 emit enablePrintAction(false);
1516 if ( url().isLocalFile() )
1518 m_watcher->removeFile( localFilePath() );
1519 QFileInfo fi(localFilePath());
1520 m_watcher->removeDir( fi.absolutePath() );
1521 if ( fi.isSymLink() ) m_watcher->removeFile( fi.readLink() );
1523 m_fileWasRemoved = false;
1524 if ( m_generatorGuiClient )
1525 factory()->removeClient( m_generatorGuiClient );
1526 m_generatorGuiClient = 0;
1527 m_document->closeDocument();
1528 updateViewActions();
1533 m_searchWidget->clearText();
1534 m_topMessage->setVisible( false );
1535 m_formsMessage->setVisible( false );
1537 #ifdef OKULAR_KEEP_FILE_OPEN
1540 bool r = KParts::ReadWritePart::closeUrl();
1546 bool Part::closeUrl()
1548 return closeUrl( true );
1551 void Part::guiActivateEvent(KParts::GUIActivateEvent *event)
1553 updateViewActions();
1555 KParts::ReadWritePart::guiActivateEvent(event);
1560 if ( m_embedMode == NativeShellMode )
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" );
1568 void Part::cannotQuit()
1570 KMessageBox::information( widget(), i18n( "This link points to a quit application action that does not work when using the embedded viewer." ), QString(), "warnNoQuitIfNotInOkular" );
1574 void Part::slotShowLeftPanel()
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 );
1583 void Part::slotShowBottomBar()
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 );
1592 void Part::slotFileDirty( const QString& path )
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() )
1601 // Only start watching the file in case if it wasn't removed
1602 if (QFile::exists(localFilePath()))
1603 m_dirtyHandler->start( 750 );
1605 m_fileWasRemoved = true;
1609 const QFileInfo fi(localFilePath());
1610 if ( fi.absolutePath() == path )
1612 // Our parent has been dirtified
1613 if (!QFile::exists(localFilePath()))
1615 m_fileWasRemoved = true;
1617 else if (m_fileWasRemoved && QFile::exists(localFilePath()))
1619 // we need to watch the new file
1620 m_watcher->removeFile(localFilePath());
1621 m_watcher->addFile(localFilePath());
1622 m_dirtyHandler->start( 750 );
1625 else if ( fi.isSymLink() && fi.readLink() == path )
1627 if ( QFile::exists( fi.readLink() ))
1628 m_dirtyHandler->start( 750 );
1630 m_fileWasRemoved = true;
1636 void Part::slotDoFileDirty()
1638 bool tocReloadPrepared = false;
1640 // do the following the first time the file is reloaded
1641 if ( m_viewportDirty.pageNumber == -1 )
1643 // store the url of the current document
1646 // store the current viewport
1647 m_viewportDirty = m_document->viewport();
1649 // store the current toolbox pane
1650 m_dirtyToolboxIndex = m_sidebar->currentIndex();
1651 m_wasSidebarVisible = m_sidebar->isSidebarVisible();
1652 m_wasSidebarCollapsed = m_sidebar->isCollapsed();
1654 // store if presentation view was open
1655 m_wasPresentationOpen = ((PresentationWidget*)m_presentationWidget != 0);
1657 // preserves the toc state after reload
1658 m_toc->prepareForReload();
1659 tocReloadPrepared = true;
1661 // store the page rotation
1662 m_dirtyPageRotation = m_document->rotation();
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...") );
1669 // close and (try to) reopen the document
1672 m_viewportDirty.pageNumber = -1;
1674 if ( tocReloadPrepared )
1676 m_toc->rollbackReload();
1681 if ( tocReloadPrepared )
1682 m_toc->finishReload();
1684 // inform the user about the operation in progress
1685 m_pageView->displayMessage( i18n("Reloading the document...") );
1687 if ( KParts::ReadWritePart::openUrl( m_oldUrl ) )
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 );
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() )
1699 m_sidebar->setCurrentIndex( m_dirtyToolboxIndex );
1701 if ( m_sidebar->isSidebarVisible() != m_wasSidebarVisible )
1703 m_sidebar->setSidebarVisibility( m_wasSidebarVisible );
1705 if ( m_sidebar->isCollapsed() != m_wasSidebarCollapsed )
1707 m_sidebar->setCollapsed( m_wasSidebarCollapsed );
1709 if (m_wasPresentationOpen) slotShowPresentation();
1710 emit enablePrintAction(true && m_document->printingSupport() != Okular::Document::NoPrinting);
1714 // start watching the file again (since we dropped it on close)
1715 addFileToWatcher( m_watcher, localFilePath() );
1716 m_dirtyHandler->start( 750 );
1721 void Part::updateViewActions()
1723 bool opened = m_document->pages() > 0;
1726 m_gotoPage->setEnabled( m_document->pages() > 1 );
1728 // Check if you are at the beginning or not
1729 if (m_document->currentPage() != 0)
1731 m_beginningOfDocument->setEnabled( true );
1732 m_prevPage->setEnabled( true );
1736 if (m_pageView->verticalScrollBar()->value() != 0)
1738 // The page isn't at the very beginning
1739 m_beginningOfDocument->setEnabled( true );
1743 // The page is at the very beginning of the document
1744 m_beginningOfDocument->setEnabled( false );
1746 // The document is at the first page, you can go to a page before
1747 m_prevPage->setEnabled( false );
1750 if (m_document->pages() == m_document->currentPage() + 1 )
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())
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 );
1761 // Otherwise you can move to the endif
1762 m_endOfDocument->setEnabled( true );
1767 // If you are not at the end, enable go to next page
1768 m_nextPage->setEnabled( true );
1769 m_endOfDocument->setEnabled( true );
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 );
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 );
1794 QWidget *menu = factory()->container("menu_okular_part_viewer", this);
1795 if (menu) menu->setEnabled( opened );
1797 menu = factory()->container("view_orientation", this);
1798 if (menu) menu->setEnabled( opened );
1800 emit viewerMenuStateChange( opened );
1802 updateBookmarksActions();
1806 void Part::updateBookmarksActions()
1808 bool opened = m_document->pages() > 0;
1811 m_addBookmark->setEnabled( true );
1812 if ( m_document->bookmarkManager()->isBookmarked( m_document->viewport() ) )
1814 m_addBookmark->setText( i18n( "Remove Bookmark" ) );
1815 m_addBookmark->setIcon( KIcon( "edit-delete-bookmark" ) );
1816 m_renameBookmark->setEnabled( true );
1820 m_addBookmark->setText( m_addBookmarkText );
1821 m_addBookmark->setIcon( m_addBookmarkIcon );
1822 m_renameBookmark->setEnabled( false );
1827 m_addBookmark->setEnabled( false );
1828 m_addBookmark->setText( m_addBookmarkText );
1829 m_addBookmark->setIcon( m_addBookmarkIcon );
1830 m_renameBookmark->setEnabled( false );
1835 void Part::enableTOC(bool enable)
1837 m_sidebar->setItemEnabled(0, enable);
1839 // If present, show the TOC when a document is opened
1840 if ( enable && m_sidebar->currentIndex() != 0 )
1842 m_sidebar->setCurrentIndex( 0, Sidebar::DoNotUncollapseIfCollapsed );
1846 void Part::slotRebuildBookmarkMenu()
1848 rebuildBookmarkMenu();
1851 void Part::slotShowFindBar()
1854 m_findBar->focusAndSetCursor();
1855 m_closeFindBar->setEnabled( true );
1858 void Part::slotHideFindBar()
1860 if ( m_findBar->maybeHide() )
1862 m_pageView->setFocus();
1863 m_closeFindBar->setEnabled( false );
1867 //BEGIN go to page dialog
1868 class GotoPageDialog : public KDialog
1871 GotoPageDialog(QWidget *p, int current, int max) : KDialog(p)
1873 setCaption(i18n("Go to Page"));
1874 setButtons(Ok | Cancel);
1875 setDefaultButton(Ok);
1877 QWidget *w = new QWidget(this);
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);
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);
1906 //END go to page dialog
1908 void Part::slotGoToPage()
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 );
1916 void Part::slotPreviousPage()
1918 if ( m_document->isOpened() && !(m_document->currentPage() < 1) )
1919 m_document->setViewportPage( m_document->currentPage() - 1 );
1923 void Part::slotNextPage()
1925 if ( m_document->isOpened() && m_document->currentPage() < (m_document->pages() - 1) )
1926 m_document->setViewportPage( m_document->currentPage() + 1 );
1930 void Part::slotGotoFirst()
1932 if ( m_document->isOpened() ) {
1933 m_document->setViewportPage( 0 );
1934 m_beginningOfDocument->setEnabled( false );
1939 void Part::slotGotoLast()
1941 if ( m_document->isOpened() )
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);
1954 void Part::slotHistoryBack()
1956 m_document->setPrevViewport();
1960 void Part::slotHistoryNext()
1962 m_document->setNextViewport();
1966 void Part::slotAddBookmark()
1968 DocumentViewport vp = m_document->viewport();
1969 if ( m_document->bookmarkManager()->isBookmarked( vp ) )
1971 m_document->bookmarkManager()->removeBookmark( vp );
1975 m_document->bookmarkManager()->addBookmark( vp );
1979 void Part::slotRenameBookmark( const DocumentViewport &viewport )
1981 Q_ASSERT(m_document->bookmarkManager()->isBookmarked( viewport ));
1982 if ( m_document->bookmarkManager()->isBookmarked( viewport ) )
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())
1988 m_document->bookmarkManager()->renameBookmark(&bookmark, newName);
1993 void Part::slotRenameBookmarkFromMenu()
1995 QAction *action = qobject_cast<QAction *>(sender());
1999 DocumentViewport vp( action->data().toString() );
2000 slotRenameBookmark( vp );
2004 void Part::slotRenameCurrentViewportBookmark()
2006 slotRenameBookmark( m_document->viewport() );
2009 void Part::slotAboutToShowContextMenu(KMenu * /*menu*/, QAction *action, QMenu *contextMenu)
2011 const QList<QAction*> actions = contextMenu->findChildren<QAction*>("OkularPrivateRenameBookmarkActions");
2012 foreach(QAction *a, actions)
2014 contextMenu->removeAction(a);
2018 KBookmarkAction *ba = qobject_cast<KBookmarkAction*>(action);
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");
2029 void Part::slotPreviousBookmark()
2031 const KBookmark bookmark = m_document->bookmarkManager()->previousBookmark( m_document->viewport() );
2033 if ( !bookmark.isNull() )
2035 DocumentViewport vp( bookmark.url().fragment() );
2036 m_document->setViewport( vp );
2041 void Part::slotNextBookmark()
2043 const KBookmark bookmark = m_document->bookmarkManager()->nextBookmark( m_document->viewport() );
2045 if ( !bookmark.isNull() )
2047 DocumentViewport vp( bookmark.url().fragment() );
2048 m_document->setViewport( vp );
2053 void Part::slotFind()
2055 // when in presentation mode, there's already a search bar, taking care of
2056 // the 'find' requests
2057 if ( (PresentationWidget*)m_presentationWidget != 0 )
2059 m_presentationWidget->slotFind();
2068 void Part::slotFindNext()
2070 if (m_findBar->isHidden())
2073 m_findBar->findNext();
2077 void Part::slotFindPrev()
2079 if (m_findBar->isHidden())
2082 m_findBar->findPrev();
2085 bool Part::saveFile()
2087 kDebug() << "Okular part doesn't support saving the file in the location from which it was opened";
2091 void Part::slotSaveFileAs()
2093 if ( m_embedMode == PrintPreviewMode )
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 ) )
2100 /* Search local annotations */
2101 bool containsLocalAnnotations = false;
2102 const int pagecount = m_document->pages();
2104 for ( int pageno = 0; pageno < pagecount; ++pageno )
2106 const Okular::Page *page = m_document->page( pageno );
2107 foreach ( const Okular::Annotation *ann, page->annotations() )
2109 if ( !(ann->flags() & Okular::Annotation::External) )
2111 containsLocalAnnotations = true;
2115 if ( containsLocalAnnotations )
2119 /* Don't show it if there are no local annotations */
2120 if ( containsLocalAnnotations )
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 )
2128 KUrl saveUrl = KFileDialog::getSaveUrl( url(),
2129 QString(), widget(), QString(),
2130 KFileDialog::ConfirmOverwrite );
2131 if ( !saveUrl.isValid() || saveUrl.isEmpty() )
2137 bool Part::saveAs( const KUrl & saveUrl )
2143 KMessageBox::information( widget(), i18n("Could not open the temporary file for saving." ) );
2146 fileName = tf.fileName();
2152 if ( isDocumentArchive )
2153 saved = m_document->saveDocumentArchive( fileName );
2155 saved = m_document->saveChanges( fileName, &errorText );
2159 if (errorText.isEmpty())
2161 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", fileName ) );
2165 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. %2", fileName, errorText ) );
2170 KIO::Job *copyJob = KIO::file_copy( fileName, saveUrl, -1, KIO::Overwrite );
2171 if ( !KIO::NetAccess::synchronousRun( copyJob, widget() ) )
2173 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", saveUrl.prettyUrl() ) );
2177 setModified( false );
2182 void Part::slotSaveCopyAs()
2184 if ( m_embedMode == PrintPreviewMode )
2187 KUrl saveUrl = KFileDialog::getSaveUrl( KUrl("kfiledialog:///okular/" + url().fileName()),
2188 QString(), widget(), QString(),
2189 KFileDialog::ConfirmOverwrite );
2190 if ( saveUrl.isValid() && !saveUrl.isEmpty() )
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() ) )
2199 if ( url().isLocalFile() )
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() );
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 );
2213 // we still have the original remote URL of the document,
2214 // so copy the document from there
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() ) );
2228 void Part::slotPreferences()
2231 PreferencesDialog * dialog = new PreferencesDialog( m_pageView, Okular::Settings::self(), m_embedMode );
2232 dialog->setAttribute( Qt::WA_DeleteOnClose );
2239 void Part::slotAnnotationPreferences()
2242 PreferencesDialog * dialog = new PreferencesDialog( m_pageView, Okular::Settings::self(), m_embedMode );
2243 dialog->setAttribute( Qt::WA_DeleteOnClose );
2246 dialog->switchToAnnotationsPage();
2251 void Part::slotNewConfig()
2253 // Apply settings here. A good policy is to check whether the setting has
2254 // changed before applying changes.
2257 setWatchFileModeEnabled(Okular::Settings::watchFile());
2259 // Main View (pageView)
2260 m_pageView->reparseConfig();
2262 // update document settings
2263 m_document->reparseConfig();
2265 // update TOC settings
2266 if ( m_sidebar->isItemEnabled(0) )
2267 m_toc->reparseConfig();
2269 // update ThumbnailList contents
2270 if ( Okular::Settings::showLeftPanel() && !m_thumbnailList->isHidden() )
2271 m_thumbnailList->updateWidgets();
2273 // update Reviews settings
2274 if ( m_sidebar->isItemEnabled(2) )
2275 m_reviewsWidget->reparseConfig();
2277 setWindowTitleFromDocument ();
2281 void Part::slotPrintPreview()
2283 if (m_document->pages() == 0) return;
2287 // Native printing supports QPrintPreviewDialog
2288 if ( m_document->printingSupport() == Okular::Document::NativePrinting )
2290 QPrintPreviewDialog previewdlg( &printer, widget() );
2291 setupPrint( printer );
2292 connect( &previewdlg, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPrintRequested(QPrinter*)) );
2297 kWarning() << "non-native printing not supported";
2302 void Part::slotShowMenu(const Okular::Page *page, const QPoint &point)
2304 if ( m_embedMode == PrintPreviewMode )
2307 bool reallyShow = false;
2308 const bool currentPage = page && page->number() == m_document->viewport().pageNumber;
2310 if (!m_actionsSearched)
2312 // the quest for options_show_menubar
2313 KActionCollection *ac;
2318 const QList<KXMLGUIClient*> clients(factory()->clients());
2319 for(int i = 0 ; (!m_showMenuBarAction || !m_showFullScreenAction) && i < clients.size(); ++i)
2321 ac = clients.at(i)->actionCollection();
2323 act = ac->action("options_show_menubar");
2324 if (act && qobject_cast<KToggleAction*>(act))
2325 m_showMenuBarAction = qobject_cast<KToggleAction*>(act);
2327 act = ac->action("fullscreen");
2328 if (act && qobject_cast<KToggleFullScreenAction*>(act))
2329 m_showFullScreenAction = qobject_cast<KToggleFullScreenAction*>(act);
2332 m_actionsSearched = true;
2335 KMenu *popup = new KMenu( widget() );
2336 QAction *addBookmark = 0;
2337 QAction *removeBookmark = 0;
2338 QAction *fitPageWidth = 0;
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") );
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 );
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 ...
2357 m_popup->insertItem( SmallIcon("document-save"), i18n("Save Image..."), 4 );
2358 m_popup->setItemEnabled( 4, false );
2361 if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked()))
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);
2372 QAction *res = popup->exec(point);
2375 if (res == addBookmark)
2378 m_document->bookmarkManager()->addBookmark( m_document->viewport() );
2380 m_document->bookmarkManager()->addBookmark( page->number() );
2382 else if (res == removeBookmark)
2385 m_document->bookmarkManager()->removeBookmark( m_document->viewport() );
2387 m_document->bookmarkManager()->removeBookmark( page->number() );
2389 else if (res == fitPageWidth)
2391 m_pageView->fitPageWidth( page->number() );
2399 void Part::slotShowProperties()
2401 PropertiesDialog *d = new PropertiesDialog(widget(), m_document);
2407 void Part::slotShowEmbeddedFiles()
2409 EmbeddedFilesDialog *d = new EmbeddedFilesDialog(widget(), m_document);
2415 void Part::slotShowPresentation()
2417 if ( !m_presentationWidget )
2419 m_presentationWidget = new PresentationWidget( widget(), m_document, actionCollection() );
2424 void Part::slotHidePresentation()
2426 if ( m_presentationWidget )
2427 delete (PresentationWidget*) m_presentationWidget;
2431 void Part::slotTogglePresentation()
2433 if ( m_document->isOpened() )
2435 if ( !m_presentationWidget )
2436 m_presentationWidget = new PresentationWidget( widget(), m_document, actionCollection() );
2437 else delete (PresentationWidget*) m_presentationWidget;
2444 if ( m_document->isOpened() )
2450 void Part::enableStartWithPrint()
2455 void Part::slotAboutBackend()
2457 const KComponentData *data = m_document->componentData();
2461 KAboutData aboutData( *data->aboutData() );
2463 if ( aboutData.programIconName().isEmpty() || aboutData.programIconName() == aboutData.appName() )
2465 if ( const Okular::DocumentInfo *documentInfo = m_document->documentInfo() )
2467 const QString mimeTypeName = documentInfo->get("mimeType");
2468 if ( !mimeTypeName.isEmpty() )
2470 if ( KMimeType::Ptr type = KMimeType::mimeType( mimeTypeName ) )
2471 aboutData.setProgramIconName( type->iconName() );
2476 KAboutApplicationDialog dlg( &aboutData, widget() );
2481 void Part::slotExportAs(QAction * act)
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() ) )
2492 filter = "text/plain";
2495 filter = "application/vnd.kde.okular-archive";
2498 filter = m_exportFormats.at( id - 2 ).mimeType()->name();
2501 QString fileName = KFileDialog::getSaveFileName( url().isLocalFile() ? url().directory() : QString(),
2502 filter, widget(), QString(),
2503 KFileDialog::ConfirmOverwrite );
2504 if ( !fileName.isEmpty() )
2510 saved = m_document->exportToText( fileName );
2513 saved = m_document->saveDocumentArchive( fileName );
2516 saved = m_document->exportTo( fileName, m_exportFormats.at( id - 2 ) );
2520 KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", fileName ) );
2525 void Part::slotReload()
2527 // stop the dirty handler timer, otherwise we may conflict with the
2528 // auto-refresh system
2529 m_dirtyHandler->stop();
2535 void Part::slotPrint()
2537 if (m_document->pages() == 0) return;
2540 QPrintDialog *printDialog = 0;
2541 QWidget *printConfigWidget = 0;
2543 // Must do certain QPrinter setup before creating QPrintDialog
2544 setupPrint( printer );
2546 // Create the Print Dialog with extra config widgets if required
2547 if ( m_document->canConfigurePrinter() )
2549 printConfigWidget = m_document->printConfigurationWidget();
2551 if ( printConfigWidget )
2553 printDialog = KdePrint::createPrintDialog( &printer, QList<QWidget*>() << printConfigWidget, widget() );
2557 printDialog = KdePrint::createPrintDialog( &printer, widget() );
2563 // Set the available Print Range
2564 printDialog->setMinMax( 1, m_document->pages() );
2565 printDialog->setFromTo( 1, m_document->pages() );
2567 // If the user has bookmarked pages for printing, then enable Selection
2568 if ( !m_document->bookmarkedPageRange().isEmpty() )
2570 printDialog->addEnabledOption( QAbstractPrintDialog::PrintSelection );
2573 // Enable the Current Page option in the dialog.
2574 if ( m_document->pages() > 1 && currentPage() > 0 )
2576 printDialog->setOption( QAbstractPrintDialog::PrintCurrentPage );
2579 if ( printDialog->exec() )
2586 void Part::setupPrint( QPrinter &printer )
2588 printer.setOrientation(m_document->orientation());
2591 QString title = m_document->metaData( "DocumentTitle" ).toString();
2592 if ( title.isEmpty() )
2594 title = m_document->currentDocument().fileName();
2596 if ( !title.isEmpty() )
2598 printer.setDocName( title );
2602 void Part::slotPrintRequested(QPrinter *printer)
2607 void Part::doPrint(QPrinter &printer)
2609 if (!m_document->isAllowed(Okular::AllowPrint))
2611 KMessageBox::error(widget(), i18n("Printing this document is not allowed."));
2615 if (!m_document->print(printer))
2617 const QString error = m_document->printError();
2618 if (error.isEmpty())
2620 KMessageBox::error(widget(), i18n("Could not print the document. Unknown error. Please report to bugs.kde.org"));
2624 KMessageBox::error(widget(), i18n("Could not print the document. Detailed error is \"%1\". Please report to bugs.kde.org", error));
2630 void Part::restoreDocument(const KConfigGroup &group)
2632 KUrl url ( group.readPathEntry( "URL", QString() ) );
2633 if ( url.isValid() )
2635 QString viewport = group.readEntry( "Viewport" );
2636 if (!viewport.isEmpty()) m_document->setNextDocumentViewport( Okular::DocumentViewport( viewport ) );
2642 void Part::saveDocumentRestoreInfo(KConfigGroup &group)
2644 group.writePathEntry( "URL", url().url() );
2645 group.writeEntry( "Viewport", m_document->viewport().toString() );
2648 void Part::displayInfoMessage( const QString &message, KMessageWidget::MessageType messageType, int duration )
2650 if ( !Okular::Settings::showOSD() )
2652 if (messageType == KMessageWidget::Error)
2654 KMessageBox::error( widget(), message );
2659 // hide messageWindow if string is empty
2660 if ( message.isEmpty() )
2661 m_infoMessage->animatedHide();
2663 // display message (duration is length dependant)
2666 duration = 500 + 100 * message.length();
2668 m_infoTimer->start( duration );
2669 m_infoMessage->setText( message );
2670 m_infoMessage->setMessageType( messageType );
2671 m_infoMessage->setVisible( true );
2675 void Part::errorMessage( const QString &message, int duration )
2677 displayInfoMessage( message, KMessageWidget::Error, duration );
2680 void Part::warningMessage( const QString &message, int duration )
2682 displayInfoMessage( message, KMessageWidget::Warning, duration );
2685 void Part::noticeMessage( const QString &message, int duration )
2687 // less important message -> simpleer display widget in the PageView
2688 m_pageView->displayMessage( message, QString(), PageViewMessage::Info, duration );
2692 void Part::unsetDummyMode()
2694 if ( m_embedMode == PrintPreviewMode )
2697 m_sidebar->setItemEnabled( 2, true );
2698 m_sidebar->setItemEnabled( 3, true );
2699 m_sidebar->setSidebarVisibility( Okular::Settings::showLeftPanel() );
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" ) );
2705 m_historyNext = KStandardAction::documentForward( this, SLOT(slotHistoryNext()), actionCollection());
2706 m_historyNext->setWhatsThis( i18n( "Go to the place you were after" ) );
2708 m_pageView->setupActions( actionCollection() );
2710 // attach the actions of the children widgets too
2711 m_formsMessage->addAction( m_pageView->toggleFormsAction() );
2712 m_formsMessage->setVisible( m_pageView->toggleFormsAction() != 0 );
2714 // ensure history actions are in the correct state
2715 updateViewActions();
2719 bool Part::handleCompressed( QString &destpath, const QString &path, const QString &compressedMimetype )
2723 // we are working with a compressed file, decompressing
2724 // temporary file for decompressing
2725 KTemporaryFile *newtempfile = new KTemporaryFile();
2726 newtempfile->setAutoRemove(true);
2728 if ( !newtempfile->open() )
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())));
2738 // decompression file
2739 QFile pathfile(path);
2740 KDecompressor kdecompressor;
2741 if ( !pathfile.open(QFile::ReadOnly) || !kdecompressor.setType(KDecompressor::typeForMime(compressedMimetype)) )
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>"));
2757 if (!kdecompressor.process(pathfile.readAll()))
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>"));
2770 const QByteArray uncompressed = kdecompressor.result();
2771 if (newtempfile->write(uncompressed.constData(), uncompressed.size()) != uncompressed.size())
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>"));
2784 m_tempfile = newtempfile;
2785 destpath = m_tempfile->fileName();
2789 void Part::rebuildBookmarkMenu( bool unplugActions )
2791 if ( unplugActions )
2793 unplugActionList( "bookmarks_currentdocument" );
2794 qDeleteAll( m_bookmarkActions );
2795 m_bookmarkActions.clear();
2797 KUrl u = m_document->currentDocument();
2800 m_bookmarkActions = m_document->bookmarkManager()->actionsForUrl( u );
2802 bool havebookmarks = true;
2803 if ( m_bookmarkActions.isEmpty() )
2805 havebookmarks = false;
2806 QAction * a = new KAction( 0 );
2807 a->setText( i18n( "No Bookmarks" ) );
2808 a->setEnabled( false );
2809 m_bookmarkActions.append( a );
2811 plugActionList( "bookmarks_currentdocument", m_bookmarkActions );
2815 const QList<KXMLGUIClient*> clients(factory()->clients());
2816 bool containerFound = false;
2817 for (int i = 0; !containerFound && i < clients.size(); ++i)
2819 QWidget *container = factory()->container("bookmarks", clients[i]);
2820 if (container && container->actions().contains(m_bookmarkActions.first()))
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;
2830 m_prevBookmark->setEnabled( havebookmarks );
2831 m_nextBookmark->setEnabled( havebookmarks );
2834 void Part::updateAboutBackendAction()
2836 const KComponentData *data = m_document->componentData();
2839 m_aboutBackend->setEnabled( true );
2843 m_aboutBackend->setEnabled( false );
2847 void Part::resetStartArguments()
2852 void Part::setReadWrite(bool readwrite)
2854 m_document->setAnnotationEditingEnabled( readwrite );
2855 ReadWritePart::setReadWrite( readwrite );
2858 } // namespace Okular
2860 #include "moc_part.cpp"
2862 /* kate: replace-tabs on; indent-width 4; */