diff --git a/core/document.h b/core/document.h --- a/core/document.h +++ b/core/document.h @@ -326,6 +326,7 @@ /** * Returns the url of the currently opened document. + * May be a temporary file, e. g. if the document needed to be decompressed. */ QUrl currentDocument() const; @@ -905,6 +906,8 @@ * is used in the KPart to initialize the print dialog and in the * generators to check whether the document needs to be rotated or not. * + * The orientation is determined using the page sizes, as they were before the user rotated the view. + * * @since 0.14 (KDE 4.8) */ QPrinter::Orientation orientation() const; diff --git a/part.h b/part.h --- a/part.h +++ b/part.h @@ -101,10 +101,56 @@ }; /** + * @short Main Part + * * This is a "Part". It that does all the real work in a KPart * application. * - * @short Main Part + * @par Opening a Document + * @parblock + * This class provides two public methods to open documents, which will call openUrl(). + * - openDocument( const QString &url ) + * Is a slot accessible from D-Bus and opens a document from the URL @p url. + * Use this method to process user entered URLs, because they are parsed tolerantly. + * - openDocument( const QString &url, uint page ) + * Is not accessible from D-Bus and not a slot, but allows to specify the page explicitely. + * + * Internally, these methods handle the document opening. + * - openUrl( const QUrl &url ) + * Overrides ReadOnlyPart::openUrl( const QUrl& ) to redirect to the following method: + * - openUrl( const QUrl &url, bool swapInsteadOfOpening ) + * Uses the original implementation of ReadOnlyPart::openUrl( const QUrl& ), + * but allows to reload the file without interrupting the viewer. + * - openFile() + * Called by the original implementation of ReadOnlyPart::openUrl( const QUrl& ). + * Tries to determine the mimetype, and handles UI updating. + * - doOpenFile( const QMimeType &mime, const QString &fileNameToOpen, bool *out_isCompressedFile ) + * Called by openFile(), with exacty one mimetype. + * To actually open the file, this calls Document, which will get the correct Generator for the mimetype. + * + * Similarly to openDocument(), these protected slots are used for special use cases of opening. They also call openUrl(). + * - openUrlFromDocument( const QUrl &url ) + * For inter-document links from within the current document. + * - openUrlFromBookmarks( const QUrl &url ) + * For bookmarks from the side panel or the Bookmarks menu. + * - handleDroppedUrls( const QList< QUrl > &urls ) + * For URLs which are drag&dropped onto this Parts widget. + * + * When the document is opened, it may be decompressed to a temporary file. url() will return that file then, you can use realUrl() to get the URL of the real document file. + * + * When a URL is dropped via drag&drop, this Part will open it. + * @endparblock + * + * @par Closing the document + * Closing the document is less complex. + * - closeUrl() will close the document. + * - queryClose() only offers the user to save changes made to the document, but will not close. + * + * @par Actions + * This Part enables and disables its own actions automatically. + * However, it does not have own Open, Print, and Close actions, these shall be implemented by the parent application. + * The signals enablePrintAction() and enableCloseAction() can be used to keep their enabled state up to date. + * * @author Wilco Greven * @version 0.2 */ @@ -120,9 +166,11 @@ public: // Default constructor /** - * If one element of 'args' contains one of the strings "Print/Preview" or "ViewerWidget", + * @param parentWidget TODO + * @param parent The parent object. + * @param args If one element contains one of the strings "Print/Preview" or "ViewerWidget", * the part will be set up in the corresponding mode. Additionally, it is possible to specify - * which config file should be used by adding a string containing "ConfigFileName=" + * which config file should be used by adding a string containing "ConfigFileName=\" * to 'args'. **/ Part(QWidget* parentWidget, QObject* parent, const QVariantList& args); @@ -135,12 +183,28 @@ void notifyViewportChanged( bool smoothMove ) override; void notifyPageChanged( int page, int flags ) override; + // Reimplemented from KDocumentViewer + /** + * Opens a document from the given URL at the given page. + * + * @param url Path to the document file. + * @param page The number of the page, where 1 is the first page. + * + * @return Whether the document was opened successfully. + */ bool openDocument(const QUrl &url, uint page) override; void startPresentation() override; QStringList supportedMimeTypes() const override; + /** + * If, and only if, the opened document was compressed and needed to be decompressed to a temporary file, + * this returns the URL of the original, compressed file. + */ QUrl realUrl() const; + /** + * TODO + */ void showSourceLocation(const QString& fileName, int line, int column, bool showGraphically = true) override; void clearLastShownSourceLocation() override; bool isWatchFileModeEnabled() const override; @@ -151,123 +215,651 @@ public Q_SLOTS: // dbus Q_SCRIPTABLE Q_NOREPLY void goToPage(uint page) override; + + /** + * Opens a document from @p doc, which will tolerantly be parsed as URL. + * Use this to open a document from an URL which was input by a user. + */ Q_SCRIPTABLE Q_NOREPLY void openDocument( const QString &doc ); + + /** + * Returns the page count of the current document, where 1 is one page. + * May return 0 in some cases. + */ Q_SCRIPTABLE uint pages(); + + /** + * Returns the number of the current page, where 1 is the first page. + * May return 0 in some cases. + */ Q_SCRIPTABLE uint currentPage(); + + /** + * Returns the path to the actually opened file. + * May be a temporary file, e. g. if the document needed to be decompressed. + */ Q_SCRIPTABLE QString currentDocument(); + + /** + * Returns the metadata entry for the key @p metaData. + * + * @see DocumentInfo + */ Q_SCRIPTABLE QString documentMetaData( const QString &metaData ) const; + + /** + * Opens the viewer configuration dialog (i. e. not the backend configuration dialog). + */ Q_SCRIPTABLE void slotPreferences(); + + /** + * Shows and focuses the incremental find bar. Also works in presentation mode. + */ Q_SCRIPTABLE void slotFind(); + + /** + * Opens the print preview dialog. + */ Q_SCRIPTABLE void slotPrintPreview(); Q_SCRIPTABLE void slotPreviousPage(); Q_SCRIPTABLE void slotNextPage(); Q_SCRIPTABLE void slotGotoFirst(); Q_SCRIPTABLE void slotGotoLast(); + + /** + * Turns presentation mode on or off. + * Creates or deletes the presentation widget as needed. + */ Q_SCRIPTABLE void slotTogglePresentation(); + + /** + * Turns the Change Colors feature on or off. + * The new state is written to the configuration file. + */ Q_SCRIPTABLE void slotToggleChangeColors(); + + /** + * Turns the Change Colors feature on or off. + * The new state is written to the configuration file. + */ Q_SCRIPTABLE void slotSetChangeColors(bool active); + + /** + * Reloads the current document, if a document is opened. + * Continuously tries to reload, if the first try fails. + */ Q_SCRIPTABLE Q_NOREPLY void reload(); + + /** + * Will show the print dialog when the document is loaded the next time. + */ Q_SCRIPTABLE Q_NOREPLY void enableStartWithPrint(); + + /** + * Will exit the viewer (i. e. this Part) after printing or when the print dialog is closed. + */ Q_SCRIPTABLE Q_NOREPLY void enableExitAfterPrint(); + + /** + * Will open the find bar and search for the next occurence of @text, + * when the document is loaded the next time. + * Does not necessarily search from the beginning of the document. + * Does not necessarily search case sensitive. + * + * @param text The text to search for. Must not be empty. + */ Q_SCRIPTABLE Q_NOREPLY void enableStartWithFind(const QString &text); Q_SIGNALS: + /** + * This signal is emitted when the document changes, so it becomes printable or not. + * Used to enable/disable the Print action in the File menu. + */ void enablePrintAction(bool enable); void openSourceReference(const QString& absFileName, int line, int column); void viewerMenuStateChange(bool enabled); + + /** + * This signal is emitted when a document is loaded, so it can be closed. + * Used to enable/disable the Close action in the File menu. + */ void enableCloseAction(bool enable); + + /** + * This signal is emitted when a document is loaded. + * Used to set the tab icon according to the mime type. + */ void mimeTypeChanged(QMimeType mimeType); + + /** + * This signal is emitted when URLs were dropped on the viewer widget, + * and this Part is used in the native Shell with tabs enabled. + */ void urlsDropped( const QList& urls ); + + /** + * This signal is emitted when the Fit Window to Page action is triggered. + * + * @param pageViewPortSize The current size of the viewport, including scrollbars. + * @param pageSize The size of the area that shall become visible. + */ void fitWindowToPage( const QSize& pageViewPortSize, const QSize& pageSize ); protected: // reimplemented from KParts::ReadWritePart + /** + * Tries to open a document from localFilePath(). + * + * This is called from ReadOnlyPart::openUrl(), which made a local copy available at localFilePath(). + * + * If the mimetype was not set with setArguments() before, it will try to guess it. + * + * When the document was opened successfully, it will emit mimeTypeChanged() with the correct mimetype. + * Otherwise, it will emit mimeTypeChanged() with one of the incorrect mimetypes. + * + * If the document was opened successfully, it will set up all the document specific stuff, like all the actions. + * If the document or the given command line options request to e. g. open the print dialog, it will also do that. + * + * This function is called by ReadOnlyPart::openUrl(). + * + * @return Whether the document was opened successfully. + */ bool openFile() override; + + /** + * Makes openUrl(url, swapBacking = false) accessible as protected, overrides ReadOnlyPart::openUrl(). + */ bool openUrl(const QUrl &url) override; void guiActivateEvent(KParts::GUIActivateEvent *event) override; + + /** + * Shows an animated message widget above the view area. + * Error messages are even shown if Okular::Settings::showOSD is false. + */ void displayInfoMessage( const QString &message, KMessageWidget::MessageType messageType = KMessageWidget::Information, int duration = -1 ); + public: + /** + * If the user did changes to the file, will show a dialog asking whether to save or discard them. + * + * If the user choses to save them, saveFile() is called. + * + * Does not close the document. + * + * @return Whether all changes are saved or the unsaved changes may be discarded. + */ bool queryClose() override; + + /** + * Overloads closeUrl(promptToSave = true). + */ bool closeUrl() override; + + /** + * Will close the currently opened document, and, if applicable, offer to save changes. + * + * After closing, this will cleanup by disabling actions, removing temporary files, etc. + * + * If this is called through openUrl(const QUrl&, bool swapInsteadOfOpening = true), this will do nothing. + * + * @param promptToSave If true, and the user made changes to the file, will ask whether to save before closing. + * + * @return Whether the document was closed. + */ bool closeUrl(bool promptToSave) override; void setReadWrite(bool readwrite) override; bool saveAs(const QUrl & saveUrl) override; protected Q_SLOTS: // connected to actions + + /** + * Opens an URL in this Part. Closes any currently opened document. + * Use this to handle links which are embedded in documents. + * Will use BrowserExtension interface to notify the parent application about the URL change. + */ void openUrlFromDocument(const QUrl &url); + + /** + * Opens @p url, and goes to page N if given as URL fragment in the format #N. + * If the document is already opened, goes directly to page N, without reopening the document. + * + * This is used to visit bookmarks. + */ void openUrlFromBookmarks(const QUrl &url); + + /** + * Opens the first URL in @p urls if used as embedded viewer, + * or if the native shell is not set up to open documents in new tabs. + * + * Otherwise emits urlsDropped() with @p urls as argument. + * + * This is used to handle URLs which were dropped on the viewer widget. + * + * Will use BrowserExtension interface to notify the parent application about the URL change. + */ void handleDroppedUrls( const QList& urls ); + + /** + * Shows the Go to Page dialog. + */ void slotGoToPage(); + + /** + * Goes back in the viewport history. + */ void slotHistoryBack(); + + /** + * Goes forward in the viewport history. + */ void slotHistoryNext(); + + /** + * Adds or removes a bookmark for the current viewport. + * If the current viewport is already bookmarked, the bookmark is removed. + * Otherwise, a new bookmark is added. + */ void slotAddBookmark(); + + /** + * Opens a dialog to rename the bookmark. + * + * This slot must only be triggered by actions, which hold a viewport as data. + * The bookmark is determined using this data. + */ void slotRenameBookmarkFromMenu(); + + /** + * Removes the bookmark. + * + * This slot must only be triggered by actions, which hold a viewport as data. + * The bookmark is determined using this data. + */ void slotRemoveBookmarkFromMenu(); + + /** + * Shows a dialog to rename the bookmark of the current viewport. + */ void slotRenameCurrentViewportBookmark(); + + /** + * Moves the viewport to the previous bookmark for this document. + * The previous bookmark is searched from the current viewport on, without cycling. + */ void slotPreviousBookmark(); + + /** + * Moves the viewport to the next bookmark for this document. + * The next bookmark is searched from the current viewport on, without cycling. + */ void slotNextBookmark(); + + /** + * Shows the incremental find bar and searches for the next occurrence of the current search pattern. + */ void slotFindNext(); + + /** + * Shows the incremental find bar and searches backwards for the next occurrence of the current search pattern. + */ void slotFindPrev(); + + /** + * Shows the Save As dialog to save the current document. + * The user can choose whether to save in the original format or as Okular archive. + * In some embedding modes, does nothing and simply returns false. + * + * @return Whether the file was saved successfully. + */ bool slotSaveFileAs(bool showOkularArchiveAsDefaultFormat = false); + + /** + * Show a KNewStuff dialog to get books from the internet. + * + * @note + * Not implemented anymore, does nothing. + */ void slotGetNewStuff(); + + /** + * Reparses the configuration. + * Called when the KCoreConfigSkeleton changes. + */ void slotNewConfig(); + + /** + * This will open a popup menu, ideally on the view area. + * This is intended as general purpose context menu for a particular page. + * + * @param page The page which shall be subject of the popup menu + * @param point Where the menu will be shown, i. e. the cursor position + * + * @see showMenu() + */ void slotShowMenu(const Okular::Page *page, const QPoint &point); + + /** + * This will open a popup menu, ideally on the Contents side panel. + * This is intended as general purpose context menu for a TOC item. + * See showMenu() for the menu structure. + * + * @param vp The viewport which the TOC item would open, used for bookmark actions. + * @param point Where the menu will be shown, i. e. the cursor position. + * @param title The title of the TOC item, used for Add Bookmark action. + * + * @see showMenu() + */ void slotShowTOCMenu(const Okular::DocumentViewport &vp, const QPoint &point, const QString &title); + + /** + * Will show the Properties dialog for the current document. + * This dialog presents information like author, title, file path and size, ... and the fonts used in the document. + */ void slotShowProperties(); + + /** + * Will show the Embedded Files dialog for the current document. + * This document provides access to files which are embedded in the document. + * Embedding files is done e. g. with PDF documents. + */ void slotShowEmbeddedFiles(); + + /** + * Triggered by the Show Navigation Panel action. + */ void slotShowLeftPanel(); + + /** + * Triggered by the Show Page Bar action. + */ void slotShowBottomBar(); + + /** + * Will enter the Presentation mode. + * Creates the presentation widget if necessary, and shows it. + */ void slotShowPresentation(); + + /** + * Will leave the Presentation mode. + * Deletes the presentation widget, which was created by slotShowPresentation(). + */ void slotHidePresentation(); - void slotExportAs(QAction *); + + /** + * Exports the current document. Shows a dialog to get the output file name. + * + * @param action An action in the Export As menu, the position indicates the output format. + */ + void slotExportAs(QAction * action); + + /** + * Will asynchronously convert a PS file to a PDF file, and open the PDF file when completed. + * + * Shows a dialog to get the path to the PS file. + */ bool slotImportPSFile(); + + /** + * Will show the About Backend dialog with information about the Generator used for the current document. + */ void slotAboutBackend(); + + /** + * Triggered by the Reload action. + * + * @see slotAttemptReload() + */ void slotReload(); + + /** + * Closes the document if this Part is used in the native Okular shell, otherwise shows a message box. + * + * Triggered when the document itself wants to be closed, i. e. the user clicked a document close link. + */ void close(); + + /** + * Shows a message box to explain that the application can not be quit from within the document. + * + * If this Part is embedded in a parent application without slotQuit(), application quit requests + * of the document will be connected to this slot. + */ void cannotQuit(); + + /** + * Shows the incremental find bar, selects everything in the search pattern line edit, and focuses it. + */ void slotShowFindBar(); + + /** + * Maybe hides the incremental find bar. + * Find bar is not hidden if a search is ongoing. + */ void slotHideFindBar(); + + // TODO These three slots are connected to some KIO::Job stuff of ReadOnlyPart. void slotJobStarted(KIO::Job *job); void slotJobFinished(KJob *job); void loadCancelled(const QString &reason); + + /** + * Gets an appropiate title from the document and emits setWindowCaption( QString ), + * to set the window title. + */ void setWindowTitleFromDocument(); - // can be connected to widget elements + + /** + * Enables or disables view actions according to the state of the currently loaded document. + * View actions include actions that change the viewport, Reload, Copy, and selection actions. + * Bookmark actions are also updated. + */ void updateViewActions(); + + /** + * Updates bookmark actions according to the current document and viewport. + */ void updateBookmarksActions(); + + /** + * Enables or disables the Contents section in the sidebar. + */ void enableTOC(bool enable); + + /** + * Updates the Bookmarks actions, and updates the action list bookmarks_currentdocument. + * This way, the Bookmarks menu in the menubar represents a list of all bookmarks in the current document. + */ void slotRebuildBookmarkMenu(); + + /** + * Enables or disables the Layers section in the sidebar. + */ void enableLayers( bool enable ); + + /** + * Enables or disables the Signatures section in the sidebar. + */ void showSidebarSignaturesItem( bool show ); public Q_SLOTS: bool saveFile() override; // connected to Shell action (and browserExtension), not local one + + /** + * Will show the Print dialog to print the current document. + * + * The print dialog is a QPrintDialog, with these options enabled (if applicable): + * - Print to File, if supported by the Generator. + * - Current Page, to print the currently shown page. + * - Selection, to print pages which have bookmarks. + * and these tabs added: + * - Print Options (to choose the scale mode) + * + * If enableExitAfterPrint() was called, the viewer (i. e. this Part) will exit + * after printing or when the print dialog is closed. + * + * Algorithm: + * Configures a QPrinter using a QPrintDialog, and passes that to doPrint(). + */ void slotPrint(); void slotFileDirty( const QString& ); + + /** + * Will try to reload the document. + * + * After reloading, will restore the previous state of the user interface. + * + * @param oneShot If false, and reloading failed, will start watching the file, so it will be reloaded when it changes the next time. + * @param newUrl If set, the document will be reloaded from this URL instead of the original one. + * + * @return Whether the reload was successfull. If false, the document may still be reloaded later, because of watching. + */ bool slotAttemptReload( bool oneShot = false, const QUrl &newUrl = QUrl() ); + + /** + * Triggered by slotImportPSFile() trough QProcess::finished(), + * when a PS file was converted to a PDF file. + * + * Opens the resulting PDF file. + */ void psTransformEnded(int, QProcess::ExitStatus); + + /** + * Opens the generators configuration dialog (i. e. not the viewer configuration dialog). + */ KConfigDialog * slotGeneratorPreferences(); - void errorMessage( const QString &message, int duration = 0 ); + /** + * Shows an animated message above the view, even if OSD messages are disabled. + * + * @param message The text to show in the message. + * @param duration The display duration in milliseconds, -1 to choose automatically. + */ + void errorMessage( const QString &message, int duration ); + + /** + * Shows an animated message above the view, if OSD messages are enabled. + * + * @param message The text to show in the message. + * @param duration The display duration in milliseconds, -1 to choose automatically. + */ void warningMessage( const QString &message, int duration = -1 ); + + /** + * Shows an unintrusive, small message in the top of the view, if OSD messages are enabled. + * + * @param message The text to show in the message. + * @param duration The display duration in milliseconds, -1 to choose automatically. + */ void noticeMessage( const QString &message, int duration = -1 ); + /** + * Sets the size of the side panels at the left. + * + * @see slotShowLeftPanel() + */ void moveSplitter( const int sideWidgetSize ); private: + /** + * Populates a QMenu with actions to modify a bookmark. + * + * @param action The KBookmarkAction pointing to the bookmark. + * @param[out] contextMenu The menu to which the actions will be added. + * + * @return False, if bookmark could not be found. + */ bool aboutToShowContextMenu(QMenu *menu, QAction *action, QMenu *contextMenu); + + /** + * This opens a popup menu with various actions. + * Use this to show the intended context menu for the view area or the Contents side panel. + * + * If @p page is not nullptr, there will be a section with title "Page N", + * where N is the page number of @p page. It will contain bookmark and view actions specific to that page. + * + * In some cases it will contain a Tools section with some View actions + * (currently from the Settings menu, see bug 163493). + * + * It is possible that no menu is shown, if none of its actions apply. + * + * The action Add Bookmark will add a bookmark which points to some viewport. + * Tt will use the given viewport @p vp, if @p bookmarkTitle is also given. + * Otherwise, it will use the current viewport, if @p page is the currently shown page. + * Otherwise, it will use @p page as viewport. + * + * @param page The page which will be used for the section title, can be bookmarked by Add Bookmark. + * @param point Where the popup menu will be opened, i. e. the curser position. + * @param bookmarkTitle Will be used if the menu contains Add Bookmark. + * @param vp The viewport which shall be used by bookmark actions. + * @param showTOCActions Whether to add actions which affect the Contents side panel. + */ void showMenu(const Okular::Page *page, const QPoint &point, const QString &bookmarkTitle = QString(), const Okular::DocumentViewport &vp = DocumentViewport(), bool showTOCActions = false); + bool eventFilter(QObject * watched, QEvent * event) override; - Document::OpenResult doOpenFile(const QMimeType &mime, const QString &fileNameToOpen, bool *isCompressedFile); + + /** + * Tries to open a file. + * + * If openUrl(QUrl &url, bool swapInsteadOfOpening) was called with swapInsteadOfOpening = true, + * the backing file of the Generator will be changed, whitout interrupting the view. + * + * If a password is needed to open the document, it will try to fetch the password from the wallet or the user. + * After successfully opening a document with password, the user can choose to store the password in the wallet. + * + * If the file is opened successfully, m_fileLastModified is set to the current time, + * to allow watching the file for changes. + * + * Swapping the backing file is not possible with encrypted files. + * + * @param mime The mimetype of the file to open. If incorrect, opening will fail. + * @param fileNameToOpen Path to a local file, which will be opened. + * @param[out] out_isCompressedFile Whether the file was compressed and needed to be decompressed to a temporary file. + * + * @return Document::OpenSuccess or Document::OpenError. If the password could not be found, or it was intended to swap the backing file which needs a password, returns Document::OpenNeedsPassword. + */ + Document::OpenResult doOpenFile(const QMimeType &mime, const QString &fileNameToOpen, bool *out_isCompressedFile); + + /** + * Opens a document from @p url, or swaps the backing file if @p swapInsteadOfOpening is set. + * + * Will interpret the URL fragment as page number or named destination, and open the document at an appropiate position. + * + * To do the actual opening, this calls KParts::ReadWritePart::openUrl( url ), which will call doOpenFile(). + * + * @param url Path to the new document file. + * @param swapInsteadOfOpening If true, the current document is not closed, + * but the generator will use the new file from now on. Useful to reload the document. + * + * @return Whether the document was opened successfully. + */ bool openUrl( const QUrl &url, bool swapInsteadOfOpening ); void setupViewerActions(); void setViewerShortcuts(); void setupActions(); + /** + * Sets orientation and document title of @p printer to match the current document as good as possible. + */ void setupPrint( QPrinter &printer ); + + /** + * Prints the document to the given @p printer, assuming it is fully configured. + */ bool doPrint( QPrinter &printer ); + + /** + * Opens a temporary file and tries to decompress the file @p path points to. + * + * @param[out] destpath Path to the created temporary file (only at success) + * @param path Path to the compressed file to read from + * @param compressionType Compression type of the compressed file. + * + * @return Whether the file was decompressed successfully. + */ bool handleCompressed(QString &destpath, const QString &path, KCompressionDevice::CompressionType compressionType ); void rebuildBookmarkMenu( bool unplugActions = true ); void updateAboutBackendAction(); @@ -310,7 +902,7 @@ SearchWidget *m_searchWidget; FindBar * m_findBar; KMessageWidget * m_migrationMessage; - KMessageWidget * m_topMessage; + KMessageWidget * m_embeddedFilesMessage; KMessageWidget * m_formsMessage; KMessageWidget * m_infoMessage; KMessageWidget * m_signatureMessage; @@ -427,3 +1019,5 @@ #endif /* kate: replace-tabs on; indent-width 4; */ + +post diff --git a/part.cpp b/part.cpp --- a/part.cpp +++ b/part.cpp @@ -493,14 +493,14 @@ m_migrationMessage->setMessageType( KMessageWidget::Warning ); m_migrationMessage->setText( i18n( "This document contains annotations or form data that were saved internally by a previous Okular version. Internal storage is no longer supported.
Please save to a file in order to move them if you want to continue to edit the document." ) ); rightLayout->addWidget( m_migrationMessage ); - m_topMessage = new KMessageWidget( rightContainer ); - m_topMessage->setVisible( false ); - m_topMessage->setWordWrap( true ); - m_topMessage->setMessageType( KMessageWidget::Information ); - m_topMessage->setText( i18n( "This document has embedded files. Click here to see them or go to File -> Embedded Files." ) ); - m_topMessage->setIcon( QIcon::fromTheme( QStringLiteral("mail-attachment") ) ); - connect( m_topMessage, &KMessageWidget::linkActivated, this, &Part::slotShowEmbeddedFiles ); - rightLayout->addWidget( m_topMessage ); + m_embeddedFilesMessage = new KMessageWidget( rightContainer ); + m_embeddedFilesMessage->setVisible( false ); + m_embeddedFilesMessage->setWordWrap( true ); + m_embeddedFilesMessage->setMessageType( KMessageWidget::Information ); + m_embeddedFilesMessage->setText( i18n( "This document has embedded files. Click here to see them or go to File -> Embedded Files." ) ); + m_embeddedFilesMessage->setIcon( QIcon::fromTheme( QStringLiteral("mail-attachment") ) ); + connect( m_embeddedFilesMessage, &KMessageWidget::linkActivated, this, &Part::slotShowEmbeddedFiles ); + rightLayout->addWidget( m_embeddedFilesMessage ); m_formsMessage = new KMessageWidget( rightContainer ); m_formsMessage->setVisible( false ); m_formsMessage->setWordWrap( true ); @@ -1367,7 +1367,7 @@ m_watchedFileSymlinkTarget.clear(); } -Document::OpenResult Part::doOpenFile( const QMimeType &mimeA, const QString &fileNameToOpenA, bool *isCompressedFile ) +Document::OpenResult Part::doOpenFile( const QMimeType &mimeA, const QString &fileNameToOpenA, bool *out_isCompressedFile ) { QMimeDatabase db; Document::OpenResult openResult = Document::OpenError; @@ -1377,13 +1377,13 @@ KFilterDev::CompressionType compressionType = compressionTypeFor( mime.name() ); if ( compressionType != KFilterDev::None ) { - *isCompressedFile = true; + *out_isCompressedFile = true; uncompressOk = handleCompressed( fileNameToOpen, localFilePath(), compressionType ); mime = db.mimeTypeForFile( fileNameToOpen ); } else { - *isCompressedFile = false; + *out_isCompressedFile = false; } if ( m_swapInsteadOfOpening ) @@ -1492,7 +1492,7 @@ { m_documentOpenWithPassword = true; - // 3. if the password is correct and the user chose to remember it, store it to the wallet + // 3. if the password is correct and the user chosed to remember it, store it to the wallet if (wallet && /*safety check*/ wallet->isOpen() && keep ) { wallet->writePassword( walletKey, password ); @@ -1511,12 +1511,15 @@ bool Part::openFile() { - QList mimes; + // Return if the file does not exist. QString fileNameToOpen = localFilePath(); const bool isstdin = url().isLocalFile() && url().fileName() == QLatin1String( "-" ); const QFileInfo fileInfo( fileNameToOpen ); if ( (!isstdin) && (!fileInfo.exists()) ) return false; + + // Get possible mimetypes in mimes. + QList mimes; QMimeDatabase db; QMimeType pathMime = db.mimeTypeForFile( fileNameToOpen ); if ( !arguments().mimeType().isEmpty() ) @@ -1549,34 +1552,41 @@ mimes << pathMime; } + // Try to open the document with the found mimetypes. + // Store used mimetype in mime. QMimeType mime; Document::OpenResult openResult = Document::OpenError; bool isCompressedFile = false; while ( !mimes.isEmpty() && openResult == Document::OpenError ) { mime = mimes.takeFirst(); openResult = doOpenFile( mime, fileNameToOpen, &isCompressedFile ); } - - bool canSearch = m_document->supportsSearching(); emit mimeTypeChanged( mime ); // update one-time actions + bool canSearch = m_document->supportsSearching(); const bool ok = openResult == Document::OpenSuccess; emit enableCloseAction( ok ); m_find->setEnabled( ok && canSearch ); m_findNext->setEnabled( ok && canSearch ); m_findPrev->setEnabled( ok && canSearch ); - if( m_save ) m_save->setEnabled( ok && !( isstdin || mime.inherits( "inode/directory" ) ) ); - if( m_saveAs ) m_saveAs->setEnabled( ok && !( isstdin || mime.inherits( "inode/directory" ) ) ); + if( m_save ) m_save->setEnabled( ok && !isstdin && !mime.inherits( "inode/directory" ) ); + if( m_saveAs ) m_saveAs->setEnabled( ok && !isstdin && !mime.inherits( "inode/directory" ) ); emit enablePrintAction( ok && m_document->printingSupport() != Okular::Document::NoPrinting ); m_printPreview->setEnabled( ok && m_document->printingSupport() != Okular::Document::NoPrinting ); + if ( m_showPresentation ) m_showPresentation->setEnabled( ok ); m_showProperties->setEnabled( ok ); bool hasEmbeddedFiles = ok && m_document->embeddedFiles() && m_document->embeddedFiles()->count() > 0; if ( m_showEmbeddedFiles ) m_showEmbeddedFiles->setEnabled( hasEmbeddedFiles ); - m_topMessage->setVisible( hasEmbeddedFiles && Okular::Settings::showOSD() ); + + // Show a message if embedded files are present. + m_embeddedFilesMessage->setVisible( hasEmbeddedFiles && Okular::Settings::showOSD() ); + + // Show a message if old data needs to be migrated. m_migrationMessage->setVisible( m_document->isDocdataMigrationNeeded() ); - // Warn the user that XFA forms are not supported yet (NOTE: poppler generator only) + // If XFA forms are present, warn the user that they are not supported yet (NOTE: poppler generator only), + // otherwise show a message if forms are present. if ( ok && m_document->metaData( QStringLiteral("HasUnsupportedXfaForm") ).toBool() == true ) { m_formsMessage->setText( i18n( "This document has XFA forms, which are currently unsupported." ) ); @@ -1596,6 +1606,7 @@ m_formsMessage->setVisible( false ); } + // Show a message if the document is digitally signed. if ( ok && m_document->metaData( QStringLiteral("IsDigitallySigned") ).toBool() ) { if ( m_embedMode == PrintPreviewMode ) @@ -1609,9 +1620,9 @@ m_signatureMessage->setVisible( true ); } - if ( m_showPresentation ) m_showPresentation->setEnabled( ok ); if ( ok ) { + // Build the Export As menu. if ( m_exportAs ) { m_exportFormats = m_document->exportFormats(); @@ -1623,7 +1634,9 @@ menu->addAction( actionForExportFormat( *it ) ); } } + #if PURPOSE_FOUND + // Build the Share menu. if ( m_share ) { m_shareMenu->model()->setInputData(QJsonObject{ @@ -1634,6 +1647,7 @@ m_shareMenu->reload(); } #endif + if ( isCompressedFile ) { m_realUrl = url(); @@ -1779,15 +1793,20 @@ bool Part::queryClose() { + // If the file is not modified, no need to ask whether to save it. if ( !isReadWrite() || !isModified() ) return true; // TODO When we get different saving backends we need to query the backend // as to if it can save changes even if the open file has been modified, // since we only have poppler as saving backend for now we're skipping that check + + // Check whether the file was modified by another program since we opened it. if ( m_fileLastModified != QFileInfo( localFilePath() ).lastModified() ) { int res; + + // Check why this function is called and show an appropiate dialog. if ( m_isReloading ) { res = KMessageBox::warningYesNo( widget(), @@ -1830,6 +1849,7 @@ if ( promptToSave && !queryClose() ) return false; + // This check could be in overriding closeUrl() instead. if ( m_swapInsteadOfOpening ) { // If we're swapping the backing file, we don't want to close the @@ -1895,7 +1915,7 @@ { m_searchWidget->clearText(); m_migrationMessage->setVisible( false ); - m_topMessage->setVisible( false ); + m_embeddedFilesMessage->setVisible( false ); m_formsMessage->setVisible( false ); m_signatureMessage->setVisible( false ); } @@ -1935,6 +1955,7 @@ void Part::cannotQuit() { KMessageBox::information( widget(), i18n( "This link points to a quit application action that does not work when using the embedded viewer." ), QString(), QStringLiteral("warnNoQuitIfNotInOkular") ); + // TODO does not check for application==Okular, but whether it has slotQuit(). } @@ -2014,6 +2035,7 @@ if ( m_viewportDirty.pageNumber == -1 ) { // store the url of the current document + // TODO Why not use a static variable? m_oldUrl = newUrl.isEmpty() ? url() : newUrl; // store the current viewport @@ -2084,6 +2106,7 @@ if (m_wasPresentationOpen) slotShowPresentation(); emit enablePrintAction(true && m_document->printingSupport() != Okular::Document::NoPrinting); + // TODO could simply return here. reloadSucceeded = true; } else if ( !oneShot ) @@ -2104,7 +2127,7 @@ { m_gotoPage->setEnabled( m_document->pages() > 1 ); - // Check if you are at the beginning or not + // Check if you are at the first page or not if (m_document->currentPage() != 0) { m_beginningOfDocument->setEnabled( true ); @@ -2114,30 +2137,30 @@ { if (m_pageView->verticalScrollBar()->value() != 0) { - // The page isn't at the very beginning + // We are not at the very beginning of the document m_beginningOfDocument->setEnabled( true ); } else { - // The page is at the very beginning of the document + // We are at the very beginning of the document m_beginningOfDocument->setEnabled( false ); } - // The document is at the first page, you can go to a page before + // The document is at the first page, you can't go to a page before m_prevPage->setEnabled( false ); } if (m_document->pages() == m_document->currentPage() + 1 ) { - // If you are at the end, disable go to next page + // If you are at the last page, disable go to next page m_nextPage->setEnabled( false ); if (m_pageView->verticalScrollBar()->value() == m_pageView->verticalScrollBar()->maximum()) { - // If you are the end of the page of the last document, you can't go to the last page + // If you are the end of the last page, you can't go to the end m_endOfDocument->setEnabled( false ); } else { - // Otherwise you can move to the endif + // Otherwise you can go to the end m_endOfDocument->setEnabled( true ); } } @@ -3044,9 +3067,8 @@ if ( m_embedMode == PrintPreviewMode ) return; - bool reallyShow = false; - const bool currentPage = page && page->number() == m_document->viewport().pageNumber; - + // Initialize m_showMenuBarAction and m_showFullScreenAction to point to the respective existing action. + // The existing actions are expected in some other KXMLGuiClient. if (!m_actionsSearched) { // the quest for options_show_menubar @@ -3072,7 +3094,13 @@ m_actionsSearched = true; } + const bool currentPage = page && page->number() == m_document->viewport().pageNumber; QMenu *popup = new QMenu( widget() ); + + // The following code will populate the popup menu with actions. + // If any actions were added, set reallyShow = true. + bool reallyShow = false; + if (showTOCActions) { popup->addAction( i18n("Expand whole section"),