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