2019-01-05 22:30:25 +00:00
/***************************************************************************
2004-08-26 21:17:24 +00:00
* Copyright ( C ) 2002 by Wilco Greven < greven @ kde . org > *
* Copyright ( C ) 2002 by Chris Cheney < ccheney @ cheney . cx > *
* Copyright ( C ) 2002 by Malcolm Hunter < malcolm . hunter @ gmx . co . uk > *
* Copyright ( C ) 2003 - 2004 by Christophe Devriese *
* < Christophe . Devriese @ student . kuleuven . ac . be > *
* Copyright ( C ) 2003 by Daniel Molkentin < molkentin @ kde . org > *
* Copyright ( C ) 2003 by Andy Goossens < andygoossens @ telenet . be > *
* Copyright ( C ) 2003 by Dirk Mueller < mueller @ kde . org > *
* Copyright ( C ) 2003 by Laurent Montel < montel @ kde . org > *
* Copyright ( C ) 2004 by Dominique Devriese < devriese @ kde . org > *
* Copyright ( C ) 2004 by Christoph Cullmann < crossfire @ babylon2k . de > *
* Copyright ( C ) 2004 by Henrique Pinto < stampede @ coltec . ufmg . br > *
* Copyright ( C ) 2004 by Waldo Bastian < bastian @ kde . org > *
2008-03-17 23:02:33 +00:00
* Copyright ( C ) 2004 - 2008 by Albert Astals Cid < aacid @ kde . org > *
2004-09-02 18:11:19 +00:00
* Copyright ( C ) 2004 by Antti Markus < antti . markus @ starman . ee > *
2017-11-16 08:57:58 +00:00
* Copyright ( C ) 2017 Klarälvdalens Datakonsult AB , a KDAB Group *
* company , info @ kdab . com . Work sponsored by the *
* LiMux project of the city of Munich *
2004-08-26 21:17:24 +00:00
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-04-19 18:30:20 +00:00
# include "part.h"
2005-01-02 14:55:14 +00:00
// qt/kde includes
2016-07-15 18:08:34 +00:00
# include <QApplication>
2016-10-29 10:23:14 +00:00
# include <QContextMenuEvent>
2016-07-15 19:05:38 +00:00
# include <QDialog>
# include <QDialogButtonBox>
2016-07-15 18:08:34 +00:00
# include <QFile>
2016-07-15 19:05:38 +00:00
# include <QFileDialog>
# include <QInputDialog>
2016-07-15 18:08:34 +00:00
# include <QLabel>
# include <QLayout>
2016-07-15 19:05:38 +00:00
# include <QMenu>
# include <QPrintDialog>
# include <QPrintPreviewDialog>
# include <QPrinter>
2010-09-03 21:30:30 +00:00
# include <QScrollBar>
2016-07-15 18:08:34 +00:00
# include <QSlider>
# include <QSpinBox>
2016-07-15 19:05:38 +00:00
# include <QStandardPaths>
2016-07-15 18:08:34 +00:00
# include <QTemporaryFile>
# include <QTimer>
2016-07-15 19:05:38 +00:00
# include <QWidgetAction>
2007-10-15 23:01:27 +00:00
2020-09-24 13:31:49 +00:00
# include <KAboutPluginDialog>
2016-07-15 19:05:38 +00:00
# include <KActionCollection>
# include <KBookmarkAction>
# include <KDirWatch>
# include <KFilterBase>
# include <KFilterDev>
2019-06-28 15:41:15 +00:00
# include <KIO/OpenFileManagerWindowJob>
2016-07-11 21:37:13 +00:00
# include <KJobWidgets>
2016-07-15 19:05:38 +00:00
# include <KMessageBox>
2020-07-14 10:13:34 +00:00
# include <KParts/GUIActivateEvent>
2016-07-15 19:05:38 +00:00
# include <KPasswordDialog>
2015-12-08 16:22:33 +00:00
# include <KPluginMetaData>
2016-07-15 19:05:38 +00:00
# include <KSharedDataCache>
# include <KStandardShortcut>
# include <KToggleAction>
# include <KToggleFullScreenAction>
2020-09-09 12:13:09 +00:00
# include <Kdelibs4ConfigMigrator>
# include <Kdelibs4Migration>
# ifdef WITH_KWALLET
2016-07-15 19:05:38 +00:00
# include <KWallet>
2020-09-09 12:13:09 +00:00
# endif
2016-07-15 19:05:38 +00:00
# include <KXMLGUIClient>
# include <KXMLGUIFactory>
2017-10-11 15:45:02 +00:00
# if PURPOSE_FOUND
# include <Purpose/AlternativesModel>
# include <PurposeWidgets/Menu>
# endif
2009-12-26 16:23:36 +00:00
#if 0
2007-07-19 22:27:45 +00:00
# include <knewstuff2/engine.h>
2009-12-26 16:23:36 +00:00
# endif
2016-07-15 19:05:38 +00:00
2005-01-02 14:55:14 +00:00
// local includes
2007-03-10 23:45:12 +00:00
# include "aboutdata.h"
2005-01-02 14:29:37 +00:00
# include "conf/preferencesdialog.h"
2011-09-10 17:15:52 +00:00
# include "core/action.h"
2012-06-13 13:33:49 +00:00
# include "core/annotations.h"
2007-01-13 17:28:54 +00:00
# include "core/bookmarkmanager.h"
2018-10-08 20:53:51 +00:00
# include "core/document_p.h"
2007-11-26 21:43:54 +00:00
# include "core/fileprinter.h"
2020-09-05 17:57:57 +00:00
# include "core/form.h"
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
# include "core/generator.h"
2005-01-02 14:29:37 +00:00
# include "core/page.h"
Add option to ignore print margins for non-PDF generators
Summary:
This adds a combobox in the print dialog of the non-PDF
generators to allow selecting whether or not to take
print margins into account.
For the PDF case and rasterized printing, new print otions have
been implemented in commit 2e97d587508dff08aaf86ff149c8ed6b7658950d
already, which adds an additional option to do no scaling at all.
For consistency reasons, the same terms also used for the PDF
case are used in the combobox (i.e. the two of the three that
apply).
This adds a new abstract class 'PrintOptionsWidget' with a
'ignorePrintMargins()' method to indicate whether print margins
should be ignored or not, and a default implementation.
The existing widget for the PDF generator now derives from this
class.
In order to avoid an ABI breakage, the return value of
'Document::printConfigurationWidget' is left as a 'QWidget *'
and a dynamic_cast is done on use.
FilePrinter is adapted to take into account the value set by
'QPrinter::setFullPage()' and the margin options
are now passed accordingly (either the values set in the dialog or '0').
A big thanks to Albert Astals Cid <aacid@kde.org> for showing how
to extend the initial implementation to cover more generators.
Test Plan:
1) Open a PostScript file in Okular (using a document size that matches
a paper size available on the printer used later makes it easier
to see things behave as expected)
2) open print dialog, go to "Print options" and notice that there is a new
"Scale mode" combobox whose value is set to "Fit to printable area"
by default.
3) don't change any options, print to a printer that has hardware margins
Expected result: the document is scaled to the printable area (e.g.
scaled down so that the printer's hardware margins remain empty) as it
has been without this change.
4) Set the value of the "Print Options" -> "Scale mode" combobox to
"Fit to full page" and print again
Expected result: The document is scaled to the full page size, i.e. ignoring
the printer's hardware margins.
5) Try steps 1-4 with other document formats supported by Okular and
observe that they behave the same (except for the PDF case, where
there's a combobox with three options that has been implemented
independent of this change).
Reviewers: #okular, ngraham
Reviewed By: ngraham
Subscribers: fvogt, rkflx, arthurpeters, ltoscano, okular-devel, aacid, ngraham
Tags: #okular
Differential Revision: https://phabricator.kde.org/D10974
2019-04-03 13:58:21 +00:00
# include "core/printoptionswidget.h"
2008-04-01 09:10:46 +00:00
# include "extensions.h"
2006-03-28 22:22:10 +00:00
# include "settings.h"
2006-12-27 16:04:49 +00:00
# include "ui/bookmarklist.h"
2014-09-11 19:12:27 +00:00
# include "ui/debug_ui.h"
2015-08-22 20:15:32 +00:00
# include "ui/drawingtoolactions.h"
2006-05-28 16:54:54 +00:00
# include "ui/embeddedfilesdialog.h"
2007-12-03 00:17:12 +00:00
# include "ui/fileprinterpreview.h"
2007-03-17 22:58:41 +00:00
# include "ui/findbar.h"
2007-12-24 15:02:32 +00:00
# include "ui/guiutils.h"
2015-05-27 13:56:56 +00:00
# include "ui/layers.h"
2005-01-26 10:42:07 +00:00
# include "ui/minibar.h"
2016-12-28 16:03:28 +00:00
# include "ui/okmenutitle.h"
2006-10-15 19:37:14 +00:00
# include "ui/pagesizelabel.h"
2005-01-02 14:29:37 +00:00
# include "ui/pageview.h"
# include "ui/presentationwidget.h"
# include "ui/propertiesdialog.h"
2005-03-24 19:50:28 +00:00
# include "ui/searchwidget.h"
# include "ui/side_reviews.h"
2007-08-06 17:24:10 +00:00
# include "ui/sidebar.h"
2020-09-06 11:19:00 +00:00
# include "ui/signatureguiutils.h"
2019-01-05 22:30:25 +00:00
# include "ui/signaturepanel.h"
2005-03-24 19:50:28 +00:00
# include "ui/thumbnaillist.h"
2005-01-02 14:29:37 +00:00
# include "ui/toc.h"
2020-07-09 21:19:47 +00:00
# include "xmlgui_helper.h"
2010-08-14 15:16:07 +00:00
# include <memory>
2008-06-07 21:08:41 +00:00
2018-04-13 15:45:23 +00:00
# ifdef OKULAR_KEEP_FILE_OPEN
2008-06-07 21:08:41 +00:00
class FileKeeper
{
public :
FileKeeper ( )
2017-09-05 21:27:18 +00:00
: m_handle ( nullptr )
2008-06-07 21:08:41 +00:00
{
}
~ FileKeeper ( )
{
}
void open ( const QString & path )
{
if ( ! m_handle )
2014-08-10 18:36:41 +00:00
m_handle = std : : fopen ( QFile : : encodeName ( path ) . constData ( ) , " r " ) ;
2008-06-07 21:08:41 +00:00
}
void close ( )
{
if ( m_handle ) {
int ret = std : : fclose ( m_handle ) ;
Q_UNUSED ( ret )
2017-09-05 21:27:18 +00:00
m_handle = nullptr ;
2008-06-07 21:08:41 +00:00
}
2020-07-10 22:15:05 +00:00
}
2008-06-07 21:08:41 +00:00
2014-09-17 22:30:39 +00:00
QTemporaryFile * copyToTemporary ( ) const
2008-06-07 21:08:41 +00:00
{
if ( ! m_handle )
2017-09-05 21:27:18 +00:00
return nullptr ;
2008-06-07 21:08:41 +00:00
2014-09-17 22:30:39 +00:00
QTemporaryFile * retFile = new QTemporaryFile ;
2008-06-07 21:08:41 +00:00
retFile - > open ( ) ;
std : : rewind ( m_handle ) ;
int c = - 1 ;
do {
c = std : : fgetc ( m_handle ) ;
if ( c = = EOF )
break ;
if ( ! retFile - > putChar ( ( char ) c ) )
break ;
} while ( ! feof ( m_handle ) ) ;
retFile - > flush ( ) ;
return retFile ;
}
private :
std : : FILE * m_handle ;
} ;
2018-04-13 15:45:23 +00:00
# endif
2008-06-07 21:08:41 +00:00
2014-08-10 20:01:13 +00:00
K_PLUGIN_FACTORY ( OkularPartFactory , registerPlugin < Okular : : Part > ( ) ; )
2015-08-18 13:12:07 +00:00
static QAction * actionForExportFormat ( const Okular : : ExportFormat & format , QObject * parent = Q_NULLPTR )
2007-03-10 21:32:09 +00:00
{
QAction * act = new QAction ( format . description ( ) , parent ) ;
if ( ! format . icon ( ) . isNull ( ) ) {
act - > setIcon ( format . icon ( ) ) ;
}
return act ;
}
2016-07-11 21:52:42 +00:00
static KFilterDev : : CompressionType compressionTypeFor ( const QString & mime_to_check )
2007-07-29 00:55:17 +00:00
{
2013-05-27 21:33:34 +00:00
// The compressedMimeMap is here in case you have a very old shared mime database
// that doesn't have inheritance info for things like gzeps, etc
// Otherwise the "is()" calls below are just good enough
2016-07-11 21:52:42 +00:00
static QHash < QString , KFilterDev : : CompressionType > compressedMimeMap ;
2013-05-27 21:33:34 +00:00
static bool supportBzip = false ;
static bool supportXz = false ;
2015-10-29 12:37:11 +00:00
const QString app_gzip ( QStringLiteral ( " application/x-gzip " ) ) ;
const QString app_bzip ( QStringLiteral ( " application/x-bzip " ) ) ;
const QString app_xz ( QStringLiteral ( " application/x-xz " ) ) ;
2007-07-29 00:55:17 +00:00
if ( compressedMimeMap . isEmpty ( ) ) {
2015-04-09 01:37:24 +00:00
std : : unique_ptr < KFilterBase > f ;
2019-04-25 21:10:48 +00:00
compressedMimeMap [ QStringLiteral ( " image/x-gzeps " ) ] = KFilterDev : : GZip ;
2010-08-14 16:06:41 +00:00
// check we can read bzip2-compressed files
2014-08-10 12:42:51 +00:00
f . reset ( KCompressionDevice : : filterForCompressionType ( KCompressionDevice : : BZip2 ) ) ;
2010-08-14 16:06:41 +00:00
if ( f . get ( ) ) {
2013-05-27 21:33:34 +00:00
supportBzip = true ;
2019-04-25 21:10:48 +00:00
compressedMimeMap [ QStringLiteral ( " application/x-bzpdf " ) ] = KFilterDev : : BZip2 ;
compressedMimeMap [ QStringLiteral ( " application/x-bzpostscript " ) ] = KFilterDev : : BZip2 ;
compressedMimeMap [ QStringLiteral ( " application/x-bzdvi " ) ] = KFilterDev : : BZip2 ;
compressedMimeMap [ QStringLiteral ( " image/x-bzeps " ) ] = KFilterDev : : BZip2 ;
2010-08-14 16:06:41 +00:00
}
2014-08-09 23:08:54 +00:00
// check if we can read XZ-compressed files
2014-08-10 12:42:51 +00:00
f . reset ( KCompressionDevice : : filterForCompressionType ( KCompressionDevice : : Xz ) ) ;
2010-08-14 15:16:07 +00:00
if ( f . get ( ) ) {
2013-05-27 21:33:34 +00:00
supportXz = true ;
2010-08-14 15:16:07 +00:00
}
2007-07-29 00:55:17 +00:00
}
2016-07-11 21:52:42 +00:00
QHash < QString , KFilterDev : : CompressionType > : : const_iterator it = compressedMimeMap . constFind ( mime_to_check ) ;
2008-11-11 18:48:40 +00:00
if ( it ! = compressedMimeMap . constEnd ( ) )
2007-07-29 00:55:17 +00:00
return it . value ( ) ;
2014-09-11 13:18:05 +00:00
QMimeDatabase db ;
QMimeType mime = db . mimeTypeForName ( mime_to_check ) ;
if ( mime . isValid ( ) ) {
if ( mime . inherits ( app_gzip ) )
2016-07-11 21:52:42 +00:00
return KFilterDev : : GZip ;
2014-09-11 13:18:05 +00:00
else if ( supportBzip & & mime . inherits ( app_bzip ) )
2016-07-11 21:52:42 +00:00
return KFilterDev : : BZip2 ;
2014-09-11 13:18:05 +00:00
else if ( supportXz & & mime . inherits ( app_xz ) )
2016-07-11 21:52:42 +00:00
return KFilterDev : : Xz ;
2013-06-15 17:50:51 +00:00
}
2013-05-27 21:33:34 +00:00
2016-07-11 21:52:42 +00:00
return KFilterDev : : None ;
2007-07-29 00:55:17 +00:00
}
2011-10-12 19:36:01 +00:00
static Okular : : EmbedMode detectEmbedMode ( QWidget * parentWidget , QObject * parent , const QVariantList & args )
2009-03-22 18:38:38 +00:00
{
Q_UNUSED ( parentWidget ) ;
2015-05-13 22:58:21 +00:00
if ( parent & & ( parent - > objectName ( ) . startsWith ( QLatin1String ( " okular::Shell " ) ) | | parent - > objectName ( ) . startsWith ( QLatin1String ( " okular/okular__Shell " ) ) ) )
2011-10-12 19:36:01 +00:00
return Okular : : NativeShellMode ;
2009-03-22 18:38:38 +00:00
2009-03-23 15:40:09 +00:00
if ( parent & & ( QByteArray ( " KHTMLPart " ) = = parent - > metaObject ( ) - > className ( ) ) )
2011-10-12 19:36:01 +00:00
return Okular : : KHTMLPartMode ;
2009-03-23 15:40:09 +00:00
2019-12-12 22:48:27 +00:00
for ( const QVariant & arg : args ) {
2009-03-22 18:38:38 +00:00
if ( arg . type ( ) = = QVariant : : String ) {
2011-10-23 13:22:58 +00:00
if ( arg . toString ( ) = = QLatin1String ( " Print/Preview " ) ) {
2011-10-12 19:36:01 +00:00
return Okular : : PrintPreviewMode ;
2011-10-23 13:22:58 +00:00
} else if ( arg . toString ( ) = = QLatin1String ( " ViewerWidget " ) ) {
2011-10-12 19:36:01 +00:00
return Okular : : ViewerWidgetMode ;
2011-09-10 17:15:52 +00:00
}
2009-03-22 18:38:38 +00:00
}
}
2011-10-12 19:36:01 +00:00
return Okular : : UnknownEmbedMode ;
2009-03-22 18:38:38 +00:00
}
2011-10-05 20:50:12 +00:00
static QString detectConfigFileName ( const QVariantList & args )
{
2019-12-12 22:48:27 +00:00
for ( const QVariant & arg : args ) {
2011-10-05 20:50:12 +00:00
if ( arg . type ( ) = = QVariant : : String ) {
QString argString = arg . toString ( ) ;
2015-10-29 12:37:11 +00:00
int separatorIndex = argString . indexOf ( QStringLiteral ( " = " ) ) ;
2011-10-05 20:50:12 +00:00
if ( separatorIndex > = 0 & & argString . left ( separatorIndex ) = = QLatin1String ( " ConfigFileName " ) ) {
return argString . mid ( separatorIndex + 1 ) ;
}
}
}
2011-10-23 13:22:58 +00:00
return QString ( ) ;
2011-10-05 20:50:12 +00:00
}
2008-06-07 21:08:41 +00:00
# undef OKULAR_KEEP_FILE_OPEN
# ifdef OKULAR_KEEP_FILE_OPEN
static bool keepFileOpen ( )
{
static bool keep_file_open = ! qgetenv ( " OKULAR_NO_KEEP_FILE_OPEN " ) . toInt ( ) ;
return keep_file_open ;
}
# endif
2012-09-25 19:26:44 +00:00
int Okular : : Part : : numberOfParts = 0 ;
2009-10-26 20:59:24 +00:00
namespace Okular
{
2006-05-08 18:57:49 +00:00
Part : : Part ( QWidget * parentWidget , QObject * parent , const QVariantList & args )
2012-05-23 21:43:44 +00:00
: KParts : : ReadWritePart ( parent )
Initialize m_tocEnabled
Othewise we get an unitialized memory use
==38984== Conditional jump or move depends on uninitialised value(s)
==38984== at 0xE5B0125: Okular::Part::slotNewConfig() (part.cpp:3000)
==38984== by 0xE59FAF1: Okular::Part::Part(QWidget*, QObject*, QList<QVariant> const&) (part.cpp:595)
==38984== by 0xE5BB596: QObject* KPluginFactory::createPartInstance<Okular::Part>(QWidget*, QObject*, QList<QVariant> const&) (kpluginfactory.h:526)
==38984== by 0x5401674: KPluginFactory::create(char const*, QWidget*, QObject*, QList<QVariant> const&, QString const&) (in /usr/lib/libKF5CoreAddons.so.5.70.0)
==38984== by 0x124543: KParts::ReadWritePart* KPluginFactory::create<KParts::ReadWritePart>(QObject*, QList<QVariant> const&) (kpluginfactory.h:545)
==38984== by 0x11D126: Shell::Shell(QString const&) (shell.cpp:97)
==38984== by 0x11B250: Okular::main(QStringList const&, QString const&) (okular_main.cpp:169)
==38984== by 0x118418: main (main.cpp:82)
2020-06-02 21:07:50 +00:00
, m_tempfile ( nullptr )
, m_documentOpenWithPassword ( false )
, m_swapInsteadOfOpening ( false )
, m_tocEnabled ( false )
, m_isReloading ( false )
, m_fileWasRemoved ( false )
, m_showMenuBarAction ( nullptr )
, m_showFullScreenAction ( nullptr )
, m_actionsSearched ( false )
2018-03-03 16:21:15 +00:00
, m_cliPresentation ( false )
, m_cliPrint ( false )
, m_cliPrintAndExit ( false )
, m_embedMode ( detectEmbedMode ( parentWidget , parent , args ) )
, m_generatorGuiClient ( nullptr )
, m_keeper ( nullptr )
2002-08-30 09:14:01 +00:00
{
2015-11-28 15:08:19 +00:00
// make sure that the component name is okular otherwise the XMLGUI .rc files are not found
// when this part is used in an application other than okular (e.g. unit tests)
setComponentName ( QStringLiteral ( " okular " ) , QString ( ) ) ;
2016-07-12 20:06:20 +00:00
const QLatin1String configFileName ( " okularpartrc " ) ;
2011-10-05 20:50:12 +00:00
// first, we check if a config file name has been specified
2016-07-12 20:06:20 +00:00
QString configFilePath = detectConfigFileName ( args ) ;
if ( configFilePath . isEmpty ( ) ) {
configFilePath = QStandardPaths : : writableLocation ( QStandardPaths : : ConfigLocation ) + QLatin1Char ( ' / ' ) + configFileName ;
}
// Migrate old config
if ( ! QFile : : exists ( configFilePath ) ) {
qCDebug ( OkularUiDebug ) < < " Did not find a config file, attempting to look for old config " ;
// Migrate old config + UI
Kdelibs4ConfigMigrator configMigrator ( componentName ( ) ) ;
// UI file is handled automatically, we only need to specify config name because we're a part
configMigrator . setConfigFiles ( QStringList ( configFileName ) ) ;
// If there's no old okular config to migrate, look for kpdf
if ( ! configMigrator . migrate ( ) ) {
qCDebug ( OkularUiDebug ) < < " Did not find an old okular config file, attempting to look for kpdf config " ;
// First try the automatic detection, using $KDEHOME etc.
Kdelibs4Migration migration ;
QString kpdfConfig = migration . locateLocal ( " config " , QStringLiteral ( " kpdfpartrc " ) ) ;
// Fallback just in case it tried e. g. ~/.kde4
if ( kpdfConfig . isEmpty ( ) ) {
kpdfConfig = QDir : : homePath ( ) + QStringLiteral ( " /.kde/share/config/kpdfpartrc " ) ;
}
if ( QFile : : exists ( kpdfConfig ) ) {
qCDebug ( OkularUiDebug ) < < " Found old kpdf config " < < kpdfConfig < < " copying to " < < configFilePath ;
QFile : : copy ( kpdfConfig , configFilePath ) ;
} else {
qCDebug ( OkularUiDebug ) < < " Did not find an old kpdf config file " ;
}
} else {
qCDebug ( OkularUiDebug ) < < " Migrated old okular config " ;
}
2007-08-21 23:18:17 +00:00
}
2016-07-12 20:06:20 +00:00
Okular : : Settings : : instance ( configFilePath ) ;
2014-11-08 04:33:23 +00:00
2020-07-09 21:19:47 +00:00
// In part.rc 47 we introduced a new mandatory toolbar that kxmlgui doesn't know how to merge properly
// so unfortunately we have to remove any customized part.rc that is older than 47
const QStringList files = QStandardPaths : : locateAll ( QStandardPaths : : GenericDataLocation , QStringLiteral ( " kxmlgui5/okular/part.rc " ) ) ;
for ( const QString & file : files ) {
removeRCFileIfVersionSmallerThan ( file , 47 ) ;
}
2012-09-25 19:26:44 +00:00
numberOfParts + + ;
if ( numberOfParts = = 1 ) {
2017-08-30 22:10:50 +00:00
m_registerDbusName = QStringLiteral ( " /okular " ) ;
2012-09-25 19:26:44 +00:00
} else {
2017-08-30 22:10:50 +00:00
m_registerDbusName = QStringLiteral ( " /okular%1 " ) . arg ( numberOfParts ) ;
2012-09-25 19:26:44 +00:00
}
2017-08-30 22:10:50 +00:00
QDBusConnection : : sessionBus ( ) . registerObject ( m_registerDbusName , this , QDBusConnection : : ExportScriptableSlots ) ;
2007-01-13 00:33:50 +00:00
2010-08-20 16:07:36 +00:00
// connect the started signal to tell the job the mimetypes we like,
// and get some more information from it
2015-10-29 12:37:11 +00:00
connect ( this , & KParts : : ReadOnlyPart : : started , this , & Part : : slotJobStarted ) ;
2007-06-05 21:25:41 +00:00
// connect the completed signal so we can put the window caption when loading remote files
2020-02-20 14:48:08 +00:00
connect ( this , QOverload < > : : of ( & Part : : completed ) , this , & Part : : setWindowTitleFromDocument ) ;
2015-10-29 12:37:11 +00:00
connect ( this , & KParts : : ReadOnlyPart : : canceled , this , & Part : : loadCancelled ) ;
2007-06-05 21:25:41 +00:00
2007-01-13 00:33:50 +00:00
// create browser extension (for printing when embedded into browser)
m_bExtension = new BrowserExtension ( this ) ;
2008-03-30 23:36:15 +00:00
// create live connect extension (for integrating with browser scripting)
new OkularLiveConnectExtension ( this ) ;
2007-01-13 00:33:50 +00:00
2010-03-17 19:37:52 +00:00
GuiUtils : : addIconLoader ( iconLoader ( ) ) ;
2007-12-24 15:02:32 +00:00
2008-11-21 11:45:00 +00:00
m_sidebar = new Sidebar ( parentWidget ) ;
setWidget ( m_sidebar ) ;
2015-10-29 12:37:11 +00:00
connect ( m_sidebar , & Sidebar : : urlsDropped , this , & Part : : handleDroppedUrls ) ;
2007-08-06 17:24:10 +00:00
2007-01-13 00:33:50 +00:00
// build the document
2007-03-30 17:46:50 +00:00
m_document = new Okular : : Document ( widget ( ) ) ;
2015-10-29 12:37:11 +00:00
connect ( m_document , & Document : : linkFind , this , & Part : : slotFind ) ;
connect ( m_document , & Document : : linkGoToPage , this , & Part : : slotGoToPage ) ;
connect ( m_document , & Document : : linkPresentation , this , & Part : : slotShowPresentation ) ;
connect ( m_document , & Document : : linkEndPresentation , this , & Part : : slotHidePresentation ) ;
connect ( m_document , & Document : : openUrl , this , & Part : : openUrlFromDocument ) ;
connect ( m_document - > bookmarkManager ( ) , & BookmarkManager : : openUrl , this , & Part : : openUrlFromBookmarks ) ;
connect ( m_document , & Document : : close , this , & Part : : close ) ;
2017-11-14 13:52:02 +00:00
connect ( m_document , & Document : : undoHistoryCleanChanged , this , [ this ] ( bool clean ) {
setModified ( ! clean ) ;
setWindowTitleFromDocument ( ) ;
} ) ;
2007-01-13 00:33:50 +00:00
2014-08-10 18:36:41 +00:00
if ( parent & & parent - > metaObject ( ) - > indexOfSlot ( QMetaObject : : normalizedSignature ( " slotQuit() " ) . constData ( ) ) ! = - 1 )
2020-02-20 14:48:08 +00:00
connect ( m_document , SIGNAL ( quit ( ) ) , parent , SLOT ( slotQuit ( ) ) ) ; // clazy:exclude=old-style-connect
2007-01-13 00:33:50 +00:00
else
2015-10-29 12:37:11 +00:00
connect ( m_document , & Document : : quit , this , & Part : : cannotQuit ) ;
2007-01-13 00:33:50 +00:00
// widgets: ^searchbar (toolbar containing label and SearchWidget)
// m_searchToolBar = new KToolBar( parentWidget, "searchBar" );
// m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() );
// QLabel * sLabel = new QLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" );
// m_searchWidget = new SearchWidget( m_searchToolBar, m_document );
// sLabel->setBuddy( m_searchWidget );
// m_searchToolBar->setStretchableWidget( m_searchWidget );
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
// [left toolbox optional item: Table of Contents] | []
2017-09-05 21:27:18 +00:00
m_toc = new TOC ( nullptr , m_document ) ;
2015-10-29 12:37:11 +00:00
connect ( m_toc . data ( ) , & TOC : : hasTOC , this , & Part : : enableTOC ) ;
2017-03-23 00:22:08 +00:00
connect ( m_toc . data ( ) , & TOC : : rightClick , this , & Part : : slotShowTOCMenu ) ;
2007-01-13 00:33:50 +00:00
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
// [left toolbox optional item: Layers] | []
2017-09-05 21:27:18 +00:00
m_layers = new Layers ( nullptr , m_document ) ;
2015-10-29 12:37:11 +00:00
connect ( m_layers . data ( ) , & Layers : : hasLayers , this , & Part : : enableLayers ) ;
2015-05-27 13:56:56 +00:00
2007-01-13 00:33:50 +00:00
// [left toolbox: Thumbnails and Bookmarks] | []
2017-09-05 21:27:18 +00:00
QWidget * thumbsBox = new ThumbnailsBox ( nullptr ) ;
2015-03-17 22:15:20 +00:00
thumbsBox - > layout ( ) - > setSpacing ( 6 ) ;
2007-01-13 00:33:50 +00:00
m_searchWidget = new SearchWidget ( thumbsBox , m_document ) ;
2015-03-17 22:15:20 +00:00
thumbsBox - > layout ( ) - > addWidget ( m_searchWidget ) ;
2007-01-13 00:33:50 +00:00
m_thumbnailList = new ThumbnailList ( thumbsBox , m_document ) ;
2015-03-17 22:15:20 +00:00
thumbsBox - > layout ( ) - > addWidget ( m_thumbnailList ) ;
2007-01-13 00:33:50 +00:00
// ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList );
2015-10-29 12:37:11 +00:00
connect ( m_thumbnailList . data ( ) , & ThumbnailList : : rightClick , this , & Part : : slotShowMenu ) ;
m_sidebar - > addItem ( thumbsBox , QIcon : : fromTheme ( QStringLiteral ( " view-preview " ) ) , i18n ( " Thumbnails " ) ) ;
2015-09-15 23:18:17 +00:00
m_sidebar - > setCurrentItem ( thumbsBox ) ;
2007-01-13 00:33:50 +00:00
// [left toolbox: Reviews] | []
2017-09-05 21:27:18 +00:00
m_reviewsWidget = new Reviews ( nullptr , m_document ) ;
Overhaul annotations UX
Create a new new annotation toolbar to replace the current one as discussed in the task T8076.
Fixes:
BUG: 386578
BUG: 374728
BUG: 352310
BUG: 330518
BUG: 341914
BUG: 157289
BUG: 358057
BUG: 412767
BUG: 413595
BUG: 420462
FIXED-IN: 1.11.0
Test Plan
Before testing this revision
Delete or Temporary move aside the following files:
~/.config/okularpartrc
~/.config/okularrc
~/.local/share/kxmlgui5/okular/part.rc
~/.local/share/kxmlgui5/okular/shell.rc
Nomenclature
Actions in the main toolbar:
Quick annotations
Actions in the annotation toolbar:
Annotation actions Highlighter, Underline, Squiggle, Strike out, Typewriter,
Inline note, Popup note, Freehand line, Arrow, Straight line, Rectangle, Ellipse,
Polygon, Stamp
Annotation config actions Line width, Color, Inner color, Opacity, Font, Annotation settings
Other actions Add to Quick Annotations, Pin
Autotests
First run: annotation toolbar is not visible
Selecting Tools > Annotations shows the annotation toolbar (below the main toolbar by default)
Select an annotation > toolbar is shown
Select a quick annotation > toolbar is shown
Hide action (red cross) on the toolbar hides the toolbar
Keys 1-9,0 select the (builtin) Annotation actions (one case tested)
Keys Alt+1-9,0 select the quick annotation actions (one case tested)
No annotation action selected: Quick Annotations is enabled, Add to quick annotations is disabled, Annotation config actions are disabled, Pin is enabled
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled (also in Quick annotations)
The current document is protected: All actions are disabled
Select annotation: the Annotation config actions are enabled and their values set to the ones for the current annotation (taken from okularpartrc)
Click an annotation action when none selected: browse mode is selected
Click the currently selected annotation action: the action is unchecked and the tool disabled (back to browse mode)
Click ESC: the currently selected annotation action is unchecked
If Pin unchecked the selected annotation is unchecked after it has be used once and we are back to Browse mode
The annotation systems works when multiple Okular tabs are open (the selected annotation is per-tab)
Manual tests
(TODO) Check that kconf_update updates the key AnnotationTools to QuickAnnotationTools in ~/.config/okularpartrc
Color icon is a format-text-color (if inline note or typewriter) or format-stroke-color for all other annotations
All actions have tooltips (some change based on the fact that the icon is enabled or not)
If a custom Line Width or Opacity is set through the Annotation Settings dialog, its value appears as a new checked action in the Line width or Opacity menu
If a custom stamp is selected through the Annotation Settings dialog, its name or filename (without path) appears as a new checked action in the Stamp menu
In Configure Okular > Annotations it is only possible to configure the quick annotations. Modifying them here updates the Quick annotations list after clicking Apply
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled in Quick annotations
The state of Pin action is remembered across Okular launches
Selecting a quick action selects the corresponding action and loads its config values (color, line width, ...)
Setting the color and fill color works for all annotations (to be tested carefully, can be problematic for typewriter and inline note given the different internal mechanism to store the color in the settings)
Test stamp annotation (handled differently from the rest of the annotations)
Merge Request: https://invent.kde.org/graphics/okular/-/merge_requests/105
2020-06-04 13:01:31 +00:00
m_sidebar - > addItem ( m_reviewsWidget , QIcon : : fromTheme ( QStringLiteral ( " draw-freehand " ) ) , i18n ( " Annotations " ) ) ;
2007-01-13 00:33:50 +00:00
// [left toolbox: Bookmarks] | []
2017-09-05 21:27:18 +00:00
m_bookmarkList = new BookmarkList ( m_document , nullptr ) ;
2015-10-29 12:37:11 +00:00
m_sidebar - > addItem ( m_bookmarkList , QIcon : : fromTheme ( QStringLiteral ( " bookmarks " ) ) , i18n ( " Bookmarks " ) ) ;
2007-01-13 00:33:50 +00:00
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
// [left toolbox optional item: Signature Panel] | []
2019-01-05 22:30:25 +00:00
m_signaturePanel = new SignaturePanel ( m_document , nullptr ) ;
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
connect ( m_signaturePanel . data ( ) , & SignaturePanel : : documentHasSignatures , this , & Part : : enableSidebarSignaturesItem ) ;
2019-01-05 22:30:25 +00:00
2007-01-13 00:33:50 +00:00
// widgets: [../miniBarContainer] | []
2007-09-07 10:59:28 +00:00
# ifdef OKULAR_ENABLE_MINIBAR
2007-08-06 17:24:10 +00:00
QWidget * miniBarContainer = new QWidget ( 0 ) ;
m_sidebar - > setBottomWidget ( miniBarContainer ) ;
2007-01-13 00:33:50 +00:00
QVBoxLayout * miniBarLayout = new QVBoxLayout ( miniBarContainer ) ;
2019-09-18 11:35:04 +00:00
miniBarLayout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
2007-01-13 00:33:50 +00:00
// widgets: [../[spacer/..]] | []
miniBarLayout - > addItem ( new QSpacerItem ( 6 , 6 , QSizePolicy : : Fixed , QSizePolicy : : Fixed ) ) ;
// widgets: [../[../MiniBar]] | []
QFrame * bevelContainer = new QFrame ( miniBarContainer ) ;
bevelContainer - > setFrameStyle ( QFrame : : StyledPanel | QFrame : : Sunken ) ;
QVBoxLayout * bevelContainerLayout = new QVBoxLayout ( bevelContainer ) ;
2019-09-18 11:35:04 +00:00
bevelContainerLayout - > setContentsMargins ( 4 , 4 , 4 , 4 ) ;
2007-01-13 00:33:50 +00:00
m_progressWidget = new ProgressWidget ( bevelContainer , m_document ) ;
bevelContainerLayout - > addWidget ( m_progressWidget ) ;
miniBarLayout - > addWidget ( bevelContainer ) ;
miniBarLayout - > addItem ( new QSpacerItem ( 6 , 6 , QSizePolicy : : Fixed , QSizePolicy : : Fixed ) ) ;
2007-09-07 10:59:28 +00:00
# endif
2007-01-13 00:33:50 +00:00
// widgets: [] | [right 'pageView']
2017-09-05 21:27:18 +00:00
QWidget * rightContainer = new QWidget ( nullptr ) ;
2007-08-06 17:24:10 +00:00
m_sidebar - > setMainWidget ( rightContainer ) ;
2007-01-13 00:33:50 +00:00
QVBoxLayout * rightLayout = new QVBoxLayout ( rightContainer ) ;
2019-09-18 11:35:04 +00:00
rightLayout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
2007-01-13 00:33:50 +00:00
rightLayout - > setSpacing ( 0 ) ;
// KToolBar * rtb = new KToolBar( rightContainer, "mainToolBarSS" );
// rightLayout->addWidget( rtb );
2014-09-10 10:01:58 +00:00
m_migrationMessage = new KMessageWidget ( rightContainer ) ;
m_migrationMessage - > setVisible ( false ) ;
m_migrationMessage - > setWordWrap ( true ) ;
m_migrationMessage - > setMessageType ( KMessageWidget : : Warning ) ;
2017-11-13 14:35:06 +00:00
m_migrationMessage - > setText (
i18n ( " This document contains annotations or form data that were saved internally by a previous Okular version. Internal storage is <b>no longer supported</b>.<br/>Please save to a file in order to move them if you want to continue "
" to edit the document. " ) ) ;
2014-09-10 10:01:58 +00:00
rightLayout - > addWidget ( m_migrationMessage ) ;
2014-05-09 15:19:50 +00:00
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. <a href= \" okular:/embeddedfiles \" >Click here to see them</a> or go to File -> Embedded Files. " ) ) ;
2015-10-29 12:37:11 +00:00
m_topMessage - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " mail-attachment " ) ) ) ;
connect ( m_topMessage , & KMessageWidget : : linkActivated , this , & Part : : slotShowEmbeddedFiles ) ;
2007-01-13 00:33:50 +00:00
rightLayout - > addWidget ( m_topMessage ) ;
2014-05-09 15:19:50 +00:00
m_formsMessage = new KMessageWidget ( rightContainer ) ;
m_formsMessage - > setVisible ( false ) ;
m_formsMessage - > setWordWrap ( true ) ;
m_formsMessage - > setMessageType ( KMessageWidget : : Information ) ;
2007-02-25 00:07:59 +00:00
rightLayout - > addWidget ( m_formsMessage ) ;
2014-05-10 08:26:29 +00:00
m_infoMessage = new KMessageWidget ( rightContainer ) ;
m_infoMessage - > setVisible ( false ) ;
m_infoMessage - > setWordWrap ( true ) ;
m_infoMessage - > setMessageType ( KMessageWidget : : Information ) ;
rightLayout - > addWidget ( m_infoMessage ) ;
m_infoTimer = new QTimer ( ) ;
m_infoTimer - > setSingleShot ( true ) ;
2015-10-29 12:37:11 +00:00
connect ( m_infoTimer , & QTimer : : timeout , m_infoMessage , & KMessageWidget : : animatedHide ) ;
2019-01-05 22:30:25 +00:00
m_signatureMessage = new KMessageWidget ( rightContainer ) ;
m_signatureMessage - > setVisible ( false ) ;
m_signatureMessage - > setWordWrap ( true ) ;
rightLayout - > addWidget ( m_signatureMessage ) ;
2007-01-13 00:33:50 +00:00
m_pageView = new PageView ( rightContainer , m_document ) ;
2020-10-26 22:43:47 +00:00
rightContainer - > setFocusProxy ( m_pageView ) ;
2011-12-15 23:25:24 +00:00
QMetaObject : : invokeMethod ( m_pageView , " setFocus " , Qt : : QueuedConnection ) ; // usability setting
2007-08-06 17:24:10 +00:00
// m_splitter->setFocusProxy(m_pageView);
2015-10-29 12:37:11 +00:00
connect ( m_pageView . data ( ) , & PageView : : rightClick , this , & Part : : slotShowMenu ) ;
2019-08-25 10:19:43 +00:00
connect ( m_pageView , & PageView : : triggerSearch , this , [ this ] ( const QString & searchText ) {
m_findBar - > startSearch ( searchText ) ;
slotShowFindBar ( ) ;
} ) ;
2015-10-29 12:37:11 +00:00
connect ( m_document , & Document : : error , this , & Part : : errorMessage ) ;
connect ( m_document , & Document : : warning , this , & Part : : warningMessage ) ;
connect ( m_document , & Document : : notice , this , & Part : : noticeMessage ) ;
connect ( m_document , & Document : : sourceReferenceActivated , this , & Part : : slotHandleActivatedSourceReference ) ;
connect ( m_pageView . data ( ) , & PageView : : fitWindowToPage , this , & Part : : fitWindowToPage ) ;
2007-01-13 00:33:50 +00:00
rightLayout - > addWidget ( m_pageView ) ;
2015-07-20 16:55:35 +00:00
m_layers - > setPageView ( m_pageView ) ;
2019-01-05 22:30:25 +00:00
m_signaturePanel - > setPageView ( m_pageView ) ;
2007-03-17 22:58:41 +00:00
m_findBar = new FindBar ( m_document , rightContainer ) ;
rightLayout - > addWidget ( m_findBar ) ;
2010-10-29 21:47:17 +00:00
m_bottomBar = new QWidget ( rightContainer ) ;
QHBoxLayout * bottomBarLayout = new QHBoxLayout ( m_bottomBar ) ;
m_pageSizeLabel = new PageSizeLabel ( m_bottomBar , m_document ) ;
2019-09-18 11:35:04 +00:00
bottomBarLayout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
2007-01-13 00:33:50 +00:00
bottomBarLayout - > setSpacing ( 0 ) ;
bottomBarLayout - > addItem ( new QSpacerItem ( 5 , 5 , QSizePolicy : : Expanding , QSizePolicy : : Minimum ) ) ;
2012-02-02 18:55:40 +00:00
m_miniBarLogic = new MiniBarLogic ( this , m_document ) ;
m_miniBar = new MiniBar ( m_bottomBar , m_miniBarLogic ) ;
2007-01-13 00:33:50 +00:00
bottomBarLayout - > addWidget ( m_miniBar ) ;
bottomBarLayout - > addWidget ( m_pageSizeLabel ) ;
2010-10-29 21:47:17 +00:00
rightLayout - > addWidget ( m_bottomBar ) ;
2020-07-10 22:15:05 +00:00
2017-09-05 21:27:18 +00:00
m_pageNumberTool = new MiniBar ( nullptr , m_miniBarLogic ) ;
2020-07-10 22:15:05 +00:00
2020-02-20 14:48:08 +00:00
connect ( m_findBar , & FindBar : : forwardKeyPressEvent , m_pageView , & PageView : : externalKeyPressEvent ) ;
connect ( m_findBar , & FindBar : : onCloseButtonPressed , m_pageView , QOverload < > : : of ( & PageView : : setFocus ) ) ;
connect ( m_miniBar , & MiniBar : : forwardKeyPressEvent , m_pageView , & PageView : : externalKeyPressEvent ) ;
2015-10-29 12:37:11 +00:00
connect ( m_pageView . data ( ) , & PageView : : escPressed , m_findBar , & FindBar : : resetSearch ) ;
2020-02-20 14:48:08 +00:00
connect ( m_pageNumberTool , & MiniBar : : forwardKeyPressEvent , m_pageView , & PageView : : externalKeyPressEvent ) ;
2020-07-10 22:15:05 +00:00
2015-10-29 12:37:11 +00:00
connect ( m_reviewsWidget . data ( ) , & Reviews : : openAnnotationWindow , m_pageView . data ( ) , & PageView : : openAnnotationWindow ) ;
2007-01-13 00:33:50 +00:00
// add document observers
m_document - > addObserver ( this ) ;
m_document - > addObserver ( m_thumbnailList ) ;
m_document - > addObserver ( m_pageView ) ;
2008-04-27 11:17:05 +00:00
m_document - > registerView ( m_pageView ) ;
2007-01-13 00:33:50 +00:00
m_document - > addObserver ( m_toc ) ;
2012-02-02 18:55:40 +00:00
m_document - > addObserver ( m_miniBarLogic ) ;
2007-09-07 10:59:28 +00:00
# ifdef OKULAR_ENABLE_MINIBAR
2007-01-13 00:33:50 +00:00
m_document - > addObserver ( m_progressWidget ) ;
2007-09-07 10:59:28 +00:00
# endif
2008-09-22 22:58:32 +00:00
m_document - > addObserver ( m_reviewsWidget ) ;
2007-01-13 00:33:50 +00:00
m_document - > addObserver ( m_pageSizeLabel ) ;
2008-09-22 22:58:32 +00:00
m_document - > addObserver ( m_bookmarkList ) ;
2019-01-05 22:30:25 +00:00
m_document - > addObserver ( m_signaturePanel ) ;
2007-01-13 00:33:50 +00:00
2015-10-29 12:37:11 +00:00
connect ( m_document - > bookmarkManager ( ) , & BookmarkManager : : saved , this , & Part : : slotRebuildBookmarkMenu ) ;
2008-02-05 17:36:04 +00:00
2011-10-12 19:36:01 +00:00
setupViewerActions ( ) ;
if ( m_embedMode ! = ViewerWidgetMode ) {
setupActions ( ) ;
2011-10-24 20:30:05 +00:00
} else {
setViewerShortcuts ( ) ;
}
2011-10-12 19:36:01 +00:00
// document watcher and reloader
m_watcher = new KDirWatch ( this ) ;
2015-10-29 12:37:11 +00:00
connect ( m_watcher , & KDirWatch : : dirty , this , & Part : : slotFileDirty ) ;
2017-09-07 11:18:13 +00:00
connect ( m_watcher , & KDirWatch : : created , this , & Part : : slotFileDirty ) ;
2017-09-10 09:51:56 +00:00
connect ( m_watcher , & KDirWatch : : deleted , this , & Part : : slotFileDirty ) ;
2011-10-12 19:36:01 +00:00
m_dirtyHandler = new QTimer ( this ) ;
m_dirtyHandler - > setSingleShot ( true ) ;
2017-11-06 08:57:35 +00:00
connect ( m_dirtyHandler , & QTimer : : timeout , this , [ this ] { slotAttemptReload ( ) ; } ) ;
2011-10-12 19:36:01 +00:00
slotNewConfig ( ) ;
2013-05-28 10:46:27 +00:00
// keep us informed when the user changes settings
2015-10-29 12:37:11 +00:00
connect ( Okular : : Settings : : self ( ) , & KCoreConfigSkeleton : : configChanged , this , & Part : : slotNewConfig ) ;
2013-05-28 10:46:27 +00:00
2014-11-08 04:33:23 +00:00
# ifdef HAVE_SPEECH
// [SPEECH] check for TTS presence and usability
Okular : : Settings : : setUseTTS ( true ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2014-11-08 04:33:23 +00:00
# endif
2011-10-12 19:36:01 +00:00
rebuildBookmarkMenu ( false ) ;
if ( m_embedMode = = ViewerWidgetMode ) {
// set the XML-UI resource file for the viewer mode
2015-10-29 12:37:11 +00:00
setXMLFile ( QStringLiteral ( " part-viewermode.rc " ) ) ;
2011-10-12 19:36:01 +00:00
} else {
// set our main XML-UI resource file
2015-10-29 12:37:11 +00:00
setXMLFile ( QStringLiteral ( " part.rc " ) ) ;
2011-10-12 19:36:01 +00:00
}
m_pageView - > setupBaseActions ( actionCollection ( ) ) ;
m_sidebar - > setSidebarVisibility ( false ) ;
if ( m_embedMode ! = PrintPreviewMode ) {
// now set up actions that are required for all remaining modes
m_pageView - > setupViewerActions ( actionCollection ( ) ) ;
// and if we are not in viewer mode, we want the full GUI
if ( m_embedMode ! = ViewerWidgetMode ) {
unsetDummyMode ( ) ;
}
}
// ensure history actions are in the correct state
updateViewActions ( ) ;
2011-10-23 09:17:04 +00:00
// also update the state of the actions in the page view
2020-05-24 16:54:32 +00:00
m_pageView - > updateActionState ( false , false ) ;
2011-10-12 19:36:01 +00:00
if ( m_embedMode = = NativeShellMode )
m_sidebar - > setAutoFillBackground ( false ) ;
# ifdef OKULAR_KEEP_FILE_OPEN
m_keeper = new FileKeeper ( ) ;
# endif
}
void Part : : setupViewerActions ( )
{
2007-01-13 00:33:50 +00:00
// ACTIONS
KActionCollection * ac = actionCollection ( ) ;
// Page Traversal actions
2011-07-31 19:22:04 +00:00
m_gotoPage = KStandardAction : : gotoPage ( this , SLOT ( slotGoToPage ( ) ) , ac ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcuts ( m_gotoPage , KStandardShortcut : : gotoLine ( ) ) ;
2007-01-13 00:33:50 +00:00
// dirty way to activate gotopage when pressing miniBar's button
2015-10-29 12:37:11 +00:00
connect ( m_miniBar . data ( ) , & MiniBar : : gotoPage , m_gotoPage , & QAction : : trigger ) ;
connect ( m_pageNumberTool . data ( ) , & MiniBar : : gotoPage , m_gotoPage , & QAction : : trigger ) ;
2007-01-13 00:33:50 +00:00
m_prevPage = KStandardAction : : prior ( this , SLOT ( slotPreviousPage ( ) ) , ac ) ;
2007-08-20 20:25:22 +00:00
m_prevPage - > setIconText ( i18nc ( " Previous page " , " Previous " ) ) ;
m_prevPage - > setToolTip ( i18n ( " Go back to the Previous Page " ) ) ;
2007-01-13 00:33:50 +00:00
m_prevPage - > setWhatsThis ( i18n ( " Moves to the previous page of the document " ) ) ;
2015-05-13 23:46:03 +00:00
ac - > setDefaultShortcut ( m_prevPage , QKeySequence ( ) ) ;
2007-01-13 00:33:50 +00:00
// dirty way to activate prev page when pressing miniBar's button
2015-10-29 12:37:11 +00:00
connect ( m_miniBar . data ( ) , & MiniBar : : prevPage , m_prevPage , & QAction : : trigger ) ;
connect ( m_pageNumberTool . data ( ) , & MiniBar : : prevPage , m_prevPage , & QAction : : trigger ) ;
2007-09-07 10:59:28 +00:00
# ifdef OKULAR_ENABLE_MINIBAR
2011-07-31 19:22:04 +00:00
connect ( m_progressWidget , SIGNAL ( prevPage ( ) ) , m_prevPage , SLOT ( trigger ( ) ) ) ;
2007-09-07 10:59:28 +00:00
# endif
2007-01-13 00:33:50 +00:00
m_nextPage = KStandardAction : : next ( this , SLOT ( slotNextPage ( ) ) , ac ) ;
2007-08-20 20:25:22 +00:00
m_nextPage - > setIconText ( i18nc ( " Next page " , " Next " ) ) ;
m_nextPage - > setToolTip ( i18n ( " Advance to the Next Page " ) ) ;
2007-01-13 00:33:50 +00:00
m_nextPage - > setWhatsThis ( i18n ( " Moves to the next page of the document " ) ) ;
2015-05-13 23:46:03 +00:00
ac - > setDefaultShortcut ( m_nextPage , QKeySequence ( ) ) ;
2007-01-13 00:33:50 +00:00
// dirty way to activate next page when pressing miniBar's button
2015-10-29 12:37:11 +00:00
connect ( m_miniBar . data ( ) , & MiniBar : : nextPage , m_nextPage , & QAction : : trigger ) ;
connect ( m_pageNumberTool . data ( ) , & MiniBar : : nextPage , m_nextPage , & QAction : : trigger ) ;
2007-09-07 10:59:28 +00:00
# ifdef OKULAR_ENABLE_MINIBAR
2011-07-31 19:22:04 +00:00
connect ( m_progressWidget , SIGNAL ( nextPage ( ) ) , m_nextPage , SLOT ( trigger ( ) ) ) ;
2007-09-07 10:59:28 +00:00
# endif
2007-01-13 00:33:50 +00:00
2011-07-31 19:22:04 +00:00
m_beginningOfDocument = KStandardAction : : firstPage ( this , SLOT ( slotGotoFirst ( ) ) , ac ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " first_page " ) , m_beginningOfDocument ) ;
2010-09-03 21:30:30 +00:00
m_beginningOfDocument - > setText ( i18n ( " Beginning of the document " ) ) ;
m_beginningOfDocument - > setWhatsThis ( i18n ( " Moves to the beginning of the document " ) ) ;
2007-01-13 00:33:50 +00:00
2011-07-31 19:22:04 +00:00
m_endOfDocument = KStandardAction : : lastPage ( this , SLOT ( slotGotoLast ( ) ) , ac ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " last_page " ) , m_endOfDocument ) ;
2010-09-03 21:30:30 +00:00
m_endOfDocument - > setText ( i18n ( " End of the document " ) ) ;
m_endOfDocument - > setWhatsThis ( i18n ( " Moves to the end of the document " ) ) ;
2007-01-13 00:33:50 +00:00
2007-06-17 09:45:59 +00:00
// we do not want back and next in history in the dummy mode
2017-09-05 21:27:18 +00:00
m_historyBack = nullptr ;
m_historyNext = nullptr ;
2007-01-13 00:33:50 +00:00
2011-07-31 19:22:04 +00:00
m_addBookmark = KStandardAction : : addBookmark ( this , SLOT ( slotAddBookmark ( ) ) , ac ) ;
2007-05-01 14:43:30 +00:00
m_addBookmarkText = m_addBookmark - > text ( ) ;
2007-05-01 16:38:35 +00:00
m_addBookmarkIcon = m_addBookmark - > icon ( ) ;
2007-05-01 14:43:30 +00:00
2015-10-29 12:37:11 +00:00
m_renameBookmark = ac - > addAction ( QStringLiteral ( " rename_bookmark " ) ) ;
2011-10-25 20:21:22 +00:00
m_renameBookmark - > setText ( i18n ( " Rename Bookmark " ) ) ;
2015-10-29 12:37:11 +00:00
m_renameBookmark - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " edit-rename " ) ) ) ;
2012-03-26 18:01:01 +00:00
m_renameBookmark - > setWhatsThis ( i18n ( " Rename the current bookmark " ) ) ;
2015-10-29 12:37:11 +00:00
connect ( m_renameBookmark , & QAction : : triggered , this , & Part : : slotRenameCurrentViewportBookmark ) ;
2011-10-25 20:21:22 +00:00
2015-10-29 12:37:11 +00:00
m_prevBookmark = ac - > addAction ( QStringLiteral ( " previous_bookmark " ) ) ;
2007-01-13 00:33:50 +00:00
m_prevBookmark - > setText ( i18n ( " Previous Bookmark " ) ) ;
2015-10-29 12:37:11 +00:00
m_prevBookmark - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " go-up-search " ) ) ) ;
2012-03-26 18:01:01 +00:00
m_prevBookmark - > setWhatsThis ( i18n ( " Go to the previous bookmark " ) ) ;
2015-10-29 12:37:11 +00:00
connect ( m_prevBookmark , & QAction : : triggered , this , & Part : : slotPreviousBookmark ) ;
2007-01-13 00:33:50 +00:00
2015-10-29 12:37:11 +00:00
m_nextBookmark = ac - > addAction ( QStringLiteral ( " next_bookmark " ) ) ;
2007-01-13 00:33:50 +00:00
m_nextBookmark - > setText ( i18n ( " Next Bookmark " ) ) ;
2015-10-29 12:37:11 +00:00
m_nextBookmark - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " go-down-search " ) ) ) ;
2012-03-26 18:01:01 +00:00
m_nextBookmark - > setWhatsThis ( i18n ( " Go to the next bookmark " ) ) ;
2015-10-29 12:37:11 +00:00
connect ( m_nextBookmark , & QAction : : triggered , this , & Part : : slotNextBookmark ) ;
2007-01-13 00:33:50 +00:00
2017-09-05 21:27:18 +00:00
m_copy = nullptr ;
2007-01-13 00:33:50 +00:00
2017-09-05 21:27:18 +00:00
m_selectAll = nullptr ;
Add action in Edit menu to select the text on current page
BUG: 358868
Test Plan: Click on "Select All Text on Current Page" entry in Edit menu to select the entire page. The selected text can then be copied via Edit menu item "Copy"
Reviewers: aacid, #vdg, ngraham
Reviewed By: #vdg, ngraham
Subscribers: yurchor, michaelweghorn, kde-doc-english, davidhurka, abetts, loh.tar, alexde, ngraham, okular-devel
Tags: #okular, #documentation
Differential Revision: https://phabricator.kde.org/D18744
2019-04-21 23:06:54 +00:00
m_selectCurrentPage = nullptr ;
2007-09-03 21:35:05 +00:00
2007-01-13 00:33:50 +00:00
// Find and other actions
2011-07-31 19:22:04 +00:00
m_find = KStandardAction : : find ( this , SLOT ( slotShowFindBar ( ) ) , ac ) ;
2011-10-24 20:30:05 +00:00
QList < QKeySequence > s = m_find - > shortcuts ( ) ;
s . append ( QKeySequence ( Qt : : Key_Slash ) ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcuts ( m_find , s ) ;
2007-01-13 00:33:50 +00:00
m_find - > setEnabled ( false ) ;
2011-07-31 19:22:04 +00:00
m_findNext = KStandardAction : : findNext ( this , SLOT ( slotFindNext ( ) ) , ac ) ;
2007-01-13 00:33:50 +00:00
m_findNext - > setEnabled ( false ) ;
2011-07-31 19:22:04 +00:00
m_findPrev = KStandardAction : : findPrev ( this , SLOT ( slotFindPrev ( ) ) , ac ) ;
2009-02-14 17:11:29 +00:00
m_findPrev - > setEnabled ( false ) ;
2017-09-10 09:51:56 +00:00
m_save = nullptr ;
2017-09-05 21:27:18 +00:00
m_saveAs = nullptr ;
2019-06-28 15:41:15 +00:00
m_openContainingFolder = nullptr ;
2007-10-07 23:09:08 +00:00
2011-07-31 19:22:04 +00:00
QAction * prefs = KStandardAction : : preferences ( this , SLOT ( slotPreferences ( ) ) , ac ) ;
2009-03-22 18:38:38 +00:00
if ( m_embedMode = = NativeShellMode ) {
2008-01-20 15:35:19 +00:00
prefs - > setText ( i18n ( " Configure Okular... " ) ) ;
2007-01-13 00:33:50 +00:00
} else {
2007-05-19 10:11:04 +00:00
// TODO: improve this message
2007-01-13 00:33:50 +00:00
prefs - > setText ( i18n ( " Configure Viewer... " ) ) ;
}
2014-08-13 10:45:40 +00:00
QAction * genPrefs = new QAction ( ac ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " options_configure_generators " ) , genPrefs ) ;
2011-10-12 19:36:01 +00:00
if ( m_embedMode = = ViewerWidgetMode ) {
genPrefs - > setText ( i18n ( " Configure Viewer Backends... " ) ) ;
2011-10-23 13:22:58 +00:00
} else {
2011-10-12 19:36:01 +00:00
genPrefs - > setText ( i18n ( " Configure Backends... " ) ) ;
}
2015-10-29 12:37:11 +00:00
genPrefs - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " configure " ) ) ) ;
2007-07-12 17:52:14 +00:00
genPrefs - > setEnabled ( m_document - > configurableGenerators ( ) > 0 ) ;
2015-10-29 12:37:11 +00:00
connect ( genPrefs , & QAction : : triggered , this , & Part : : slotGeneratorPreferences ) ;
2007-01-13 00:33:50 +00:00
2011-07-31 19:22:04 +00:00
m_printPreview = KStandardAction : : printPreview ( this , SLOT ( slotPrintPreview ( ) ) , ac ) ;
2007-01-13 00:33:50 +00:00
m_printPreview - > setEnabled ( false ) ;
2017-09-05 21:27:18 +00:00
m_showLeftPanel = nullptr ;
m_showBottomBar = nullptr ;
2019-01-05 22:30:25 +00:00
m_showSignaturePanel = nullptr ;
2011-10-12 19:36:01 +00:00
2015-10-29 12:37:11 +00:00
m_showProperties = ac - > addAction ( QStringLiteral ( " properties " ) ) ;
2011-10-12 19:36:01 +00:00
m_showProperties - > setText ( i18n ( " &Properties " ) ) ;
2015-10-29 12:37:11 +00:00
m_showProperties - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " document-properties " ) ) ) ;
2020-05-27 15:03:22 +00:00
ac - > setDefaultShortcuts ( m_showProperties , { QKeySequence ( Qt : : ALT + Qt : : Key_Return ) } ) ;
2015-10-29 12:37:11 +00:00
connect ( m_showProperties , & QAction : : triggered , this , & Part : : slotShowProperties ) ;
2011-10-12 19:36:01 +00:00
m_showProperties - > setEnabled ( false ) ;
2017-09-05 21:27:18 +00:00
m_showEmbeddedFiles = nullptr ;
m_showPresentation = nullptr ;
2011-10-12 19:36:01 +00:00
2017-09-05 21:27:18 +00:00
m_exportAs = nullptr ;
m_exportAsMenu = nullptr ;
m_exportAsText = nullptr ;
m_exportAsDocArchive = nullptr ;
2017-10-11 15:45:02 +00:00
# if PURPOSE_FOUND
m_share = nullptr ;
m_shareMenu = nullptr ;
# endif
2017-09-05 21:27:18 +00:00
m_presentationDrawingActions = nullptr ;
2011-10-12 19:36:01 +00:00
2015-10-29 12:37:11 +00:00
m_aboutBackend = ac - > addAction ( QStringLiteral ( " help_about_backend " ) ) ;
2011-10-12 19:36:01 +00:00
m_aboutBackend - > setText ( i18n ( " About Backend " ) ) ;
m_aboutBackend - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
connect ( m_aboutBackend , & QAction : : triggered , this , & Part : : slotAboutBackend ) ;
2011-10-12 19:36:01 +00:00
2015-10-29 12:37:11 +00:00
QAction * reload = ac - > add < QAction > ( QStringLiteral ( " file_reload " ) ) ;
2011-10-12 19:36:01 +00:00
reload - > setText ( i18n ( " Reloa&d " ) ) ;
2015-10-29 12:37:11 +00:00
reload - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " view-refresh " ) ) ) ;
2011-10-12 19:36:01 +00:00
reload - > setWhatsThis ( i18n ( " Reload the current document from disk. " ) ) ;
2015-10-29 12:37:11 +00:00
connect ( reload , & QAction : : triggered , this , & Part : : slotReload ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcuts ( reload , KStandardShortcut : : reload ( ) ) ;
2011-10-12 19:36:01 +00:00
m_reload = reload ;
2015-10-29 12:37:11 +00:00
m_closeFindBar = ac - > addAction ( QStringLiteral ( " close_find_bar " ) , this , SLOT ( slotHideFindBar ( ) ) ) ;
2014-02-08 10:44:26 +00:00
m_closeFindBar - > setText ( i18n ( " Close &Find Bar " ) ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( m_closeFindBar , QKeySequence ( Qt : : Key_Escape ) ) ;
2014-02-08 10:44:26 +00:00
m_closeFindBar - > setEnabled ( false ) ;
2012-01-31 18:48:20 +00:00
2014-08-13 10:45:40 +00:00
QWidgetAction * pageno = new QWidgetAction ( ac ) ;
pageno - > setText ( i18n ( " Page Number " ) ) ;
2012-01-31 18:48:20 +00:00
pageno - > setDefaultWidget ( m_pageNumberTool ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " page_number " ) , pageno ) ;
2011-10-12 19:36:01 +00:00
}
2011-10-24 20:30:05 +00:00
void Part : : setViewerShortcuts ( )
2011-10-12 19:36:01 +00:00
{
KActionCollection * ac = actionCollection ( ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( m_gotoPage , QKeySequence ( Qt : : CTRL + Qt : : ALT + Qt : : Key_G ) ) ;
ac - > setDefaultShortcut ( m_find , QKeySequence ( ) ) ;
2011-10-24 20:30:05 +00:00
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( m_findNext , QKeySequence ( ) ) ;
ac - > setDefaultShortcut ( m_findPrev , QKeySequence ( ) ) ;
2011-10-24 20:30:05 +00:00
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( m_addBookmark , QKeySequence ( Qt : : CTRL + Qt : : ALT + Qt : : Key_B ) ) ;
2011-10-24 20:30:05 +00:00
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( m_beginningOfDocument , QKeySequence ( Qt : : CTRL + Qt : : ALT + Qt : : Key_Home ) ) ;
ac - > setDefaultShortcut ( m_endOfDocument , QKeySequence ( Qt : : CTRL + Qt : : ALT + Qt : : Key_End ) ) ;
2011-10-24 20:30:05 +00:00
2015-10-29 12:37:11 +00:00
QAction * action = static_cast < QAction * > ( ac - > action ( QStringLiteral ( " file_reload " ) ) ) ;
2014-10-04 19:48:01 +00:00
if ( action ) {
ac - > setDefaultShortcut ( action , QKeySequence ( Qt : : ALT + Qt : : Key_F5 ) ) ;
}
2011-10-24 20:30:05 +00:00
}
void Part : : setupActions ( )
{
KActionCollection * ac = actionCollection ( ) ;
2011-10-12 19:36:01 +00:00
m_copy = KStandardAction : : create ( KStandardAction : : Copy , m_pageView , SLOT ( copyTextSelection ( ) ) , ac ) ;
m_selectAll = KStandardAction : : selectAll ( m_pageView , SLOT ( selectAll ( ) ) , ac ) ;
Add action in Edit menu to select the text on current page
BUG: 358868
Test Plan: Click on "Select All Text on Current Page" entry in Edit menu to select the entire page. The selected text can then be copied via Edit menu item "Copy"
Reviewers: aacid, #vdg, ngraham
Reviewed By: #vdg, ngraham
Subscribers: yurchor, michaelweghorn, kde-doc-english, davidhurka, abetts, loh.tar, alexde, ngraham, okular-devel
Tags: #okular, #documentation
Differential Revision: https://phabricator.kde.org/D18744
2019-04-21 23:06:54 +00:00
// Setup select all action for the current page
m_selectCurrentPage = ac - > addAction ( QStringLiteral ( " edit_select_all_current_page " ) ) ;
m_selectCurrentPage - > setText ( i18n ( " Select All Text on Current Page " ) ) ;
connect ( m_selectCurrentPage , & QAction : : triggered , m_pageView , & PageView : : slotSelectPage ) ;
m_selectCurrentPage - > setEnabled ( false ) ;
2017-11-06 08:57:35 +00:00
m_save = KStandardAction : : save (
this , [ this ] { saveFile ( ) ; } , ac ) ;
2014-05-09 20:36:24 +00:00
m_save - > setEnabled ( false ) ;
2011-10-12 19:36:01 +00:00
m_saveAs = KStandardAction : : saveAs ( this , SLOT ( slotSaveFileAs ( ) ) , ac ) ;
m_saveAs - > setEnabled ( false ) ;
2014-09-10 10:01:58 +00:00
m_migrationMessage - > addAction ( m_saveAs ) ;
2011-10-12 19:36:01 +00:00
2015-10-29 12:37:11 +00:00
m_showLeftPanel = ac - > add < KToggleAction > ( QStringLiteral ( " show_leftpanel " ) ) ;
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
m_showLeftPanel - > setText ( i18n ( " Show S&idebar " ) ) ;
2015-10-29 12:37:11 +00:00
m_showLeftPanel - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " view-sidetree " ) ) ) ;
connect ( m_showLeftPanel , & QAction : : toggled , this , & Part : : slotShowLeftPanel ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( m_showLeftPanel , QKeySequence ( Qt : : Key_F7 ) ) ;
2007-01-13 00:33:50 +00:00
m_showLeftPanel - > setChecked ( Okular : : Settings : : showLeftPanel ( ) ) ;
slotShowLeftPanel ( ) ;
2015-10-29 12:37:11 +00:00
m_showBottomBar = ac - > add < KToggleAction > ( QStringLiteral ( " show_bottombar " ) ) ;
2010-10-29 21:47:17 +00:00
m_showBottomBar - > setText ( i18n ( " Show &Page Bar " ) ) ;
2015-10-29 12:37:11 +00:00
connect ( m_showBottomBar , & QAction : : toggled , this , & Part : : slotShowBottomBar ) ;
2010-10-29 21:47:17 +00:00
m_showBottomBar - > setChecked ( Okular : : Settings : : showBottomBar ( ) ) ;
slotShowBottomBar ( ) ;
2019-01-05 22:30:25 +00:00
m_showSignaturePanel = ac - > add < QAction > ( QStringLiteral ( " show_signatures " ) ) ;
m_showSignaturePanel - > setText ( i18n ( " Show &Signatures Panel " ) ) ;
connect ( m_showSignaturePanel , & QAction : : triggered , this , [ this ] {
if ( m_sidebar - > currentItem ( ) ! = m_signaturePanel ) {
m_sidebar - > setCurrentItem ( m_signaturePanel ) ;
}
2020-07-13 17:53:04 +00:00
m_showLeftPanel - > setChecked ( true ) ;
slotShowLeftPanel ( ) ;
2019-01-05 22:30:25 +00:00
} ) ;
2015-10-29 12:37:11 +00:00
m_showEmbeddedFiles = ac - > addAction ( QStringLiteral ( " embedded_files " ) ) ;
2007-01-13 00:33:50 +00:00
m_showEmbeddedFiles - > setText ( i18n ( " &Embedded Files " ) ) ;
2015-10-29 12:37:11 +00:00
m_showEmbeddedFiles - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " mail-attachment " ) ) ) ;
connect ( m_showEmbeddedFiles , & QAction : : triggered , this , & Part : : slotShowEmbeddedFiles ) ;
2007-01-13 00:33:50 +00:00
m_showEmbeddedFiles - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
m_exportAs = ac - > addAction ( QStringLiteral ( " file_export_as " ) ) ;
2007-01-13 00:33:50 +00:00
m_exportAs - > setText ( i18n ( " E&xport As " ) ) ;
2015-10-29 12:37:11 +00:00
m_exportAs - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " document-export " ) ) ) ;
2008-09-22 22:58:32 +00:00
m_exportAsMenu = new QMenu ( ) ;
2015-10-29 12:37:11 +00:00
connect ( m_exportAsMenu , & QMenu : : triggered , this , & Part : : slotExportAs ) ;
2008-09-22 22:58:32 +00:00
m_exportAs - > setMenu ( m_exportAsMenu ) ;
m_exportAsText = actionForExportFormat ( Okular : : ExportFormat : : standardFormat ( Okular : : ExportFormat : : PlainText ) , m_exportAsMenu ) ;
m_exportAsMenu - > addAction ( m_exportAsText ) ;
2007-09-07 09:09:39 +00:00
m_exportAs - > setEnabled ( false ) ;
2007-01-13 00:33:50 +00:00
m_exportAsText - > setEnabled ( false ) ;
2017-10-11 15:45:02 +00:00
# if PURPOSE_FOUND
m_share = ac - > addAction ( QStringLiteral ( " file_share " ) ) ;
m_share - > setText ( i18n ( " S&hare " ) ) ;
m_share - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " document-share " ) ) ) ;
m_share - > setEnabled ( false ) ;
m_shareMenu = new Purpose : : Menu ( ) ;
connect ( m_shareMenu , & Purpose : : Menu : : finished , this , & Part : : slotShareActionFinished ) ;
m_share - > setMenu ( m_shareMenu ) ;
# endif
2015-10-29 12:37:11 +00:00
m_showPresentation = ac - > addAction ( QStringLiteral ( " presentation " ) ) ;
2011-10-12 19:36:01 +00:00
m_showPresentation - > setText ( i18n ( " P&resentation " ) ) ;
2015-10-29 12:37:11 +00:00
m_showPresentation - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " view-presentation " ) ) ) ;
connect ( m_showPresentation , & QAction : : triggered , this , & Part : : slotShowPresentation ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( m_showPresentation , QKeySequence ( Qt : : CTRL + Qt : : SHIFT + Qt : : Key_P ) ) ;
2011-10-12 19:36:01 +00:00
m_showPresentation - > setEnabled ( false ) ;
2007-05-06 11:23:26 +00:00
2019-06-28 15:41:15 +00:00
m_openContainingFolder = ac - > addAction ( QStringLiteral ( " open_containing_folder " ) ) ;
m_openContainingFolder - > setText ( i18n ( " Open Con&taining Folder " ) ) ;
m_openContainingFolder - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " document-open-folder " ) ) ) ;
connect ( m_openContainingFolder , & QAction : : triggered , this , & Part : : slotOpenContainingFolder ) ;
m_openContainingFolder - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
QAction * importPS = ac - > addAction ( QStringLiteral ( " import_ps " ) ) ;
2011-10-12 19:36:01 +00:00
importPS - > setText ( i18n ( " &Import PostScript as PDF... " ) ) ;
2015-10-29 12:37:11 +00:00
importPS - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " document-import " ) ) ) ;
connect ( importPS , & QAction : : triggered , this , & Part : : slotImportPSFile ) ;
2011-10-12 19:36:01 +00:00
#if 0
QAction * ghns = ac - > addAction ( " get_new_stuff " ) ;
ghns - > setText ( i18n ( " &Get Books From Internet... " ) ) ;
2014-08-13 09:54:49 +00:00
ghns - > setIcon ( QIcon : : fromTheme ( " get-hot-new-stuff " ) ) ;
2011-10-12 19:36:01 +00:00
connect ( ghns , SIGNAL ( triggered ( ) ) , this , SLOT ( slotGetNewStuff ( ) ) ) ;
# endif
2007-03-17 22:58:41 +00:00
2008-09-11 08:40:00 +00:00
KToggleAction * blackscreenAction = new KToggleAction ( i18n ( " Switch Blackscreen Mode " ) , ac ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " switch_blackscreen_mode " ) , blackscreenAction ) ;
2014-10-04 19:48:01 +00:00
ac - > setDefaultShortcut ( blackscreenAction , QKeySequence ( Qt : : Key_B ) ) ;
2015-10-29 12:37:11 +00:00
blackscreenAction - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " view-presentation " ) ) ) ;
2012-06-07 14:35:13 +00:00
blackscreenAction - > setEnabled ( false ) ;
2008-09-11 08:40:00 +00:00
2015-08-22 20:15:32 +00:00
m_presentationDrawingActions = new DrawingToolActions ( ac ) ;
2018-12-21 18:09:18 +00:00
QAction * eraseDrawingAction = new QAction ( i18n ( " Erase Drawing " ) , ac ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " presentation_erase_drawings " ) , eraseDrawingAction ) ;
2018-12-21 11:40:49 +00:00
eraseDrawingAction - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " draw-eraser-delete-objects " ) ) ) ;
2012-06-07 14:35:13 +00:00
eraseDrawingAction - > setEnabled ( false ) ;
2013-05-28 21:55:10 +00:00
2014-08-13 10:45:40 +00:00
QAction * configureAnnotations = new QAction ( i18n ( " Configure Annotations... " ) , ac ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " options_configure_annotations " ) , configureAnnotations ) ;
configureAnnotations - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " configure " ) ) ) ;
connect ( configureAnnotations , & QAction : : triggered , this , & Part : : slotAnnotationPreferences ) ;
2014-02-24 22:08:39 +00:00
2014-08-13 10:45:40 +00:00
QAction * playPauseAction = new QAction ( i18n ( " Play/Pause Presentation " ) , ac ) ;
2015-10-29 12:37:11 +00:00
ac - > addAction ( QStringLiteral ( " presentation_play_pause " ) , playPauseAction ) ;
2014-02-24 21:39:08 +00:00
playPauseAction - > setEnabled ( false ) ;
2003-09-15 21:57:19 +00:00
}
2004-09-08 12:41:14 +00:00
Part : : ~ Part ( )
2003-09-15 21:09:49 +00:00
{
2017-08-30 22:10:50 +00:00
QDBusConnection : : sessionBus ( ) . unregisterObject ( m_registerDbusName ) ;
2010-03-17 19:37:52 +00:00
GuiUtils : : removeIconLoader ( iconLoader ( ) ) ;
2008-09-22 22:58:32 +00:00
m_document - > removeObserver ( this ) ;
2007-10-03 14:59:57 +00:00
if ( m_document - > isOpened ( ) )
2012-06-01 20:55:54 +00:00
Part : : closeUrl ( false ) ;
2007-10-03 14:59:57 +00:00
2006-02-18 12:06:52 +00:00
delete m_toc ;
2015-05-27 13:56:56 +00:00
delete m_layers ;
2006-02-18 12:06:52 +00:00
delete m_pageView ;
delete m_thumbnailList ;
delete m_miniBar ;
2012-01-31 18:48:20 +00:00
delete m_pageNumberTool ;
2012-02-02 18:55:40 +00:00
delete m_miniBarLogic ;
2010-10-29 21:47:17 +00:00
delete m_bottomBar ;
2007-09-07 10:59:28 +00:00
# ifdef OKULAR_ENABLE_MINIBAR
2006-10-15 15:59:22 +00:00
delete m_progressWidget ;
2007-09-07 10:59:28 +00:00
# endif
2006-10-15 19:37:14 +00:00
delete m_pageSizeLabel ;
2008-09-22 22:58:32 +00:00
delete m_reviewsWidget ;
delete m_bookmarkList ;
2014-05-10 08:26:29 +00:00
delete m_infoTimer ;
2019-01-05 22:30:25 +00:00
delete m_signaturePanel ;
2006-02-18 12:06:52 +00:00
2004-11-09 17:20:19 +00:00
delete m_document ;
2007-01-13 21:42:39 +00:00
delete m_tempfile ;
2007-01-13 17:28:54 +00:00
qDeleteAll ( m_bookmarkActions ) ;
2008-06-07 21:08:41 +00:00
2008-09-22 22:58:32 +00:00
delete m_exportAsMenu ;
2017-10-11 15:45:02 +00:00
# if PURPOSE_FOUND
delete m_shareMenu ;
# endif
2008-09-22 22:58:32 +00:00
2008-06-07 21:08:41 +00:00
# ifdef OKULAR_KEEP_FILE_OPEN
delete m_keeper ;
# endif
2003-09-15 21:09:49 +00:00
}
2007-01-04 00:20:50 +00:00
void Part : : startPresentation ( )
{
m_cliPresentation = true ;
}
2007-05-24 20:39:35 +00:00
QStringList Part : : supportedMimeTypes ( ) const
{
return m_document - > supportedMimeTypes ( ) ;
}
2015-01-29 19:55:57 +00:00
QUrl Part : : realUrl ( ) const
2007-07-25 10:08:38 +00:00
{
if ( ! m_realUrl . isEmpty ( ) )
return m_realUrl ;
return url ( ) ;
}
2011-09-10 17:15:52 +00:00
// ViewerInterface
2011-11-05 09:18:08 +00:00
void Part : : showSourceLocation ( const QString & fileName , int line , int column , bool showGraphically )
2011-09-10 17:15:52 +00:00
{
2016-07-11 20:57:11 +00:00
Q_UNUSED ( column ) ;
2015-10-29 12:37:11 +00:00
const QString u = QStringLiteral ( " src:%1 %2 " ) . arg ( line + 1 ) . arg ( fileName ) ;
2011-10-31 21:41:50 +00:00
GotoAction action ( QString ( ) , u ) ;
m_document - > processAction ( & action ) ;
2011-11-05 09:18:08 +00:00
if ( showGraphically ) {
m_pageView - > setLastSourceLocationViewport ( m_document - > viewport ( ) ) ;
}
}
void Part : : clearLastShownSourceLocation ( )
{
m_pageView - > clearLastSourceLocationViewport ( ) ;
2011-09-10 17:15:52 +00:00
}
2011-11-05 09:40:12 +00:00
bool Part : : isWatchFileModeEnabled ( ) const
{
2018-10-28 16:33:25 +00:00
return ! m_watcher - > signalsBlocked ( ) ;
2011-11-05 09:40:12 +00:00
}
2011-10-31 21:41:50 +00:00
void Part : : setWatchFileModeEnabled ( bool enabled )
2011-09-10 17:15:52 +00:00
{
2018-11-01 06:48:32 +00:00
// Don't call 'KDirWatch::stopScan()' in here (as of KDE Frameworks 5.51.0, see bug 400541)!
// 'KDirWatch::stopScan' has a bug that may affect other code paths that make use of KDirWatch
2018-10-28 16:33:25 +00:00
// (other loaded KParts, for example).
if ( isWatchFileModeEnabled ( ) = = enabled ) {
return ;
2011-09-10 17:15:52 +00:00
}
2018-10-28 16:33:25 +00:00
m_watcher - > blockSignals ( ! enabled ) ;
if ( ! enabled ) {
2011-09-10 17:15:52 +00:00
m_dirtyHandler - > stop ( ) ;
}
}
2011-11-05 09:40:12 +00:00
bool Part : : areSourceLocationsShownGraphically ( ) const
{
2011-11-07 21:07:10 +00:00
return m_pageView - > areSourceLocationsShownGraphically ( ) ;
2011-11-05 09:40:12 +00:00
}
2011-10-31 21:41:50 +00:00
void Part : : setShowSourceLocationsGraphically ( bool show )
2011-10-17 19:56:45 +00:00
{
2011-11-07 21:07:10 +00:00
m_pageView - > setShowSourceLocationsGraphically ( show ) ;
2011-10-17 19:56:45 +00:00
}
2014-02-08 11:15:15 +00:00
bool Part : : openNewFilesInTabs ( ) const
{
return Okular : : Settings : : self ( ) - > shellOpenFileInTabs ( ) ;
}
2020-04-23 07:39:32 +00:00
bool Part : : activateTabIfAlreadyOpenFile ( ) const
{
return Okular : : Settings : : self ( ) - > switchToTabIfOpen ( ) ;
}
2011-10-23 13:22:58 +00:00
void Part : : slotHandleActivatedSourceReference ( const QString & absFileName , int line , int col , bool * handled )
2011-09-10 17:15:52 +00:00
{
2011-10-31 21:41:50 +00:00
emit openSourceReference ( absFileName , line , col ) ;
if ( m_embedMode = = Okular : : ViewerWidgetMode ) {
2011-10-23 13:22:58 +00:00
* handled = true ;
2011-09-10 17:15:52 +00:00
}
}
2007-07-25 10:08:38 +00:00
2015-01-29 19:55:57 +00:00
void Part : : openUrlFromDocument ( const QUrl & url )
2005-11-04 11:59:51 +00:00
{
2009-03-22 18:38:38 +00:00
if ( m_embedMode = = PrintPreviewMode )
return ;
2007-06-05 20:49:00 +00:00
2016-07-11 21:37:13 +00:00
if ( url . isLocalFile ( ) ) {
if ( ! QFile : : exists ( url . toLocalFile ( ) ) ) {
KMessageBox : : error ( widget ( ) , i18n ( " Could not open '%1'. File does not exist " , url . toDisplayString ( ) ) ) ;
return ;
}
2011-08-10 09:15:37 +00:00
} else {
2016-07-11 21:37:13 +00:00
KIO : : StatJob * statJob = KIO : : stat ( url , KIO : : StatJob : : SourceSide , 0 ) ;
KJobWidgets : : setWindow ( statJob , widget ( ) ) ;
if ( ! statJob - > exec ( ) | | statJob - > error ( ) ) {
KMessageBox : : error ( widget ( ) , i18n ( " Could not open '%1' (%2) " , url . toDisplayString ( ) , statJob - > errorString ( ) ) ) ;
return ;
}
2011-08-10 09:15:37 +00:00
}
2016-07-11 21:37:13 +00:00
2020-02-19 15:54:54 +00:00
emit m_bExtension - > openUrlNotify ( ) ;
emit m_bExtension - > setLocationBarUrl ( url . toDisplayString ( ) ) ;
2016-07-11 21:37:13 +00:00
openUrl ( url ) ;
2005-11-04 11:59:51 +00:00
}
2015-01-29 19:55:57 +00:00
void Part : : openUrlFromBookmarks ( const QUrl & _url )
2007-01-13 17:28:54 +00:00
{
2015-01-29 19:55:57 +00:00
QUrl url = _url ;
Okular : : DocumentViewport vp ( _url . fragment ( QUrl : : FullyDecoded ) ) ;
2007-01-13 17:28:54 +00:00
if ( vp . isValid ( ) )
m_document - > setNextDocumentViewport ( vp ) ;
2015-01-29 19:55:57 +00:00
url . setFragment ( QString ( ) ) ;
2007-01-13 17:28:54 +00:00
if ( m_document - > currentDocument ( ) = = url ) {
if ( vp . isValid ( ) )
m_document - > setViewport ( vp ) ;
} else
openUrl ( url ) ;
}
2014-08-13 11:07:44 +00:00
void Part : : handleDroppedUrls ( const QList < QUrl > & urls )
2014-04-09 21:29:13 +00:00
{
2014-04-09 21:34:18 +00:00
if ( urls . isEmpty ( ) )
return ;
if ( m_embedMode ! = NativeShellMode | | ! openNewFilesInTabs ( ) ) {
2014-04-09 21:29:13 +00:00
openUrlFromDocument ( urls . first ( ) ) ;
return ;
}
emit urlsDropped ( urls ) ;
}
2010-08-20 16:07:36 +00:00
void Part : : slotJobStarted ( KIO : : Job * job )
2005-11-04 11:59:51 +00:00
{
if ( job ) {
2007-01-28 15:46:10 +00:00
QStringList supportedMimeTypes = m_document - > supportedMimeTypes ( ) ;
2016-07-11 20:11:43 +00:00
job - > addMetaData ( QStringLiteral ( " accept " ) , supportedMimeTypes . join ( QStringLiteral ( " , " ) ) + QStringLiteral ( " , */*;q=0.5 " ) ) ;
2010-08-20 16:20:17 +00:00
2015-10-29 12:37:11 +00:00
connect ( job , & KJob : : result , this , & Part : : slotJobFinished ) ;
2010-08-20 16:20:17 +00:00
}
}
void Part : : slotJobFinished ( KJob * job )
{
if ( job - > error ( ) = = KIO : : ERR_USER_CANCELED ) {
2015-01-29 19:55:57 +00:00
m_pageView - > displayMessage ( i18n ( " The loading of %1 has been canceled. " , realUrl ( ) . toDisplayString ( QUrl : : PreferLocalFile ) ) ) ;
2005-11-04 11:59:51 +00:00
}
}
2007-06-05 21:25:41 +00:00
void Part : : loadCancelled ( const QString & reason )
{
emit setWindowCaption ( QString ( ) ) ;
2013-03-11 21:52:25 +00:00
resetStartArguments ( ) ;
2008-01-14 23:03:53 +00:00
2014-05-11 08:53:56 +00:00
// when m_viewportDirty.pageNumber != -1 we come from slotAttemptReload
2008-01-14 23:03:53 +00:00
// so we don't want to show an ugly messagebox just because the document is
// taking more than usual to be recreated
if ( m_viewportDirty . pageNumber = = - 1 ) {
if ( ! reason . isEmpty ( ) ) {
2014-08-09 23:08:54 +00:00
KMessageBox : : error ( widget ( ) , i18n ( " Could not open %1. Reason: %2 " , url ( ) . toDisplayString ( ) , reason ) ) ;
2008-01-14 23:03:53 +00:00
}
2007-06-05 21:25:41 +00:00
}
}
void Part : : setWindowTitleFromDocument ( )
{
2008-11-29 14:36:14 +00:00
// If 'DocumentTitle' should be used, check if the document has one. If
// either case is false, use the file name.
2015-01-29 19:55:57 +00:00
QString title = Okular : : Settings : : displayDocumentNameOrPath ( ) = = Okular : : Settings : : EnumDisplayDocumentNameOrPath : : Path ? realUrl ( ) . toDisplayString ( QUrl : : PreferLocalFile ) : realUrl ( ) . fileName ( ) ;
2008-11-29 14:36:14 +00:00
if ( Okular : : Settings : : displayDocumentTitle ( ) ) {
2015-10-29 12:37:11 +00:00
const QString docTitle = m_document - > metaData ( QStringLiteral ( " DocumentTitle " ) ) . toString ( ) ;
2008-11-29 14:36:14 +00:00
if ( ! docTitle . isEmpty ( ) & & ! docTitle . trimmed ( ) . isEmpty ( ) ) {
title = docTitle ;
}
2007-06-05 21:25:41 +00:00
}
2008-11-29 14:36:14 +00:00
emit setWindowCaption ( title ) ;
2007-06-05 21:25:41 +00:00
}
2013-06-08 14:29:24 +00:00
KConfigDialog * Part : : slotGeneratorPreferences ( )
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
{
2013-05-28 19:10:50 +00:00
// Create dialog
2018-10-08 20:53:51 +00:00
KConfigDialog * dialog = new Okular : : BackendConfigDialog ( m_pageView , QStringLiteral ( " generator_prefs " ) , Okular : : Settings : : self ( ) ) ;
2013-05-28 19:10:50 +00:00
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
2013-05-28 10:58:23 +00:00
2011-10-12 19:36:01 +00:00
if ( m_embedMode = = ViewerWidgetMode ) {
2014-08-09 23:08:54 +00:00
dialog - > setWindowTitle ( i18n ( " Configure Viewer Backends " ) ) ;
2011-10-12 19:36:01 +00:00
} else {
2014-08-09 23:08:54 +00:00
dialog - > setWindowTitle ( i18n ( " Configure Backends " ) ) ;
2011-10-12 19:36:01 +00:00
}
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
2007-01-28 15:46:10 +00:00
m_document - > fillConfigDialog ( dialog ) ;
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
2013-05-28 19:10:50 +00:00
// Show it
2013-05-28 10:58:23 +00:00
dialog - > setWindowModality ( Qt : : ApplicationModal ) ;
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
dialog - > show ( ) ;
2013-06-08 14:29:24 +00:00
return dialog ;
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
}
2007-09-09 10:50:36 +00:00
void Part : : notifySetup ( const QVector < Okular : : Page * > & /*pages*/ , int setupFlags )
2007-01-13 17:28:54 +00:00
{
2014-09-10 10:01:58 +00:00
// Hide the migration message if the user has just migrated. Otherwise,
// if m_migrationMessage is already hidden, this does nothing.
if ( ! m_document - > isDocdataMigrationNeeded ( ) )
m_migrationMessage - > animatedHide ( ) ;
2007-09-09 10:50:36 +00:00
if ( ! ( setupFlags & Okular : : DocumentObserver : : DocumentChanged ) )
2007-01-13 17:28:54 +00:00
return ;
rebuildBookmarkMenu ( ) ;
2007-03-07 18:15:00 +00:00
updateAboutBackendAction ( ) ;
2012-07-25 00:29:49 +00:00
m_findBar - > resetSearch ( ) ;
2007-04-29 22:50:32 +00:00
m_searchWidget - > setEnabled ( m_document - > supportsSearching ( ) ) ;
2007-01-13 17:28:54 +00:00
}
2005-02-01 18:23:55 +00:00
void Part : : notifyViewportChanged ( bool /*smoothMove*/ )
2004-11-09 17:20:19 +00:00
{
2010-09-03 21:30:30 +00:00
updateViewActions ( ) ;
2004-11-09 17:20:19 +00:00
}
2007-05-01 14:43:30 +00:00
void Part : : notifyPageChanged ( int page , int flags )
2007-01-13 17:28:54 +00:00
{
if ( ! ( flags & Okular : : DocumentObserver : : Bookmark ) )
return ;
rebuildBookmarkMenu ( ) ;
2007-05-01 14:43:30 +00:00
if ( page = = m_document - > viewport ( ) . pageNumber )
updateBookmarksActions ( ) ;
2007-01-13 17:28:54 +00:00
}
2019-12-20 15:40:59 +00:00
void Part : : goToPage ( uint page )
2004-10-12 11:08:09 +00:00
{
2019-12-20 15:40:59 +00:00
if ( page < = m_document - > pages ( ) )
m_document - > setViewportPage ( page - 1 ) ;
2004-10-12 11:08:09 +00:00
}
2007-07-29 14:36:49 +00:00
void Part : : openDocument ( const QString & doc )
2004-10-12 11:08:09 +00:00
{
2015-01-29 19:55:57 +00:00
openUrl ( QUrl : : fromUserInput ( doc ) ) ;
2004-10-12 11:08:09 +00:00
}
uint Part : : pages ( )
{
2005-06-13 17:39:58 +00:00
return m_document - > pages ( ) ;
}
uint Part : : currentPage ( )
{
return m_document - > pages ( ) ? m_document - > currentPage ( ) + 1 : 0 ;
}
2007-07-29 14:36:49 +00:00
QString Part : : currentDocument ( )
2005-06-13 17:39:58 +00:00
{
2015-01-29 19:55:57 +00:00
return m_document - > currentDocument ( ) . toDisplayString ( QUrl : : PreferLocalFile ) ;
2004-10-12 11:08:09 +00:00
}
2009-05-30 17:00:16 +00:00
QString Part : : documentMetaData ( const QString & metaData ) const
{
2014-05-11 09:17:49 +00:00
const Okular : : DocumentInfo info = m_document - > documentInfo ( ) ;
return info . get ( metaData ) ;
2009-05-30 17:00:16 +00:00
}
2005-07-15 18:20:57 +00:00
bool Part : : slotImportPSFile ( )
{
2016-07-11 21:25:09 +00:00
QString app = QStandardPaths : : findExecutable ( QStringLiteral ( " ps2pdf " ) ) ;
2007-01-13 00:33:50 +00:00
if ( app . isEmpty ( ) ) {
// TODO point the user to their distro packages?
2008-01-20 15:35:19 +00:00
KMessageBox : : error ( widget ( ) , i18n ( " The program \" ps2pdf \" was not found, so Okular can not import PS files using it. " ) , i18n ( " ps2pdf not found " ) ) ;
2007-01-13 00:33:50 +00:00
return false ;
}
2006-04-13 11:57:16 +00:00
2016-07-11 21:16:42 +00:00
QMimeDatabase mimeDatabase ;
2016-11-16 21:27:13 +00:00
QString filter = i18n ( " PostScript files (%1) " , mimeDatabase . mimeTypeForName ( QStringLiteral ( " application/postscript " ) ) . globPatterns ( ) . join ( QLatin1Char ( ' ' ) ) ) ;
2016-07-11 21:16:42 +00:00
QUrl url = QFileDialog : : getOpenFileUrl ( widget ( ) , QString ( ) , QUrl ( ) , filter ) ;
2006-10-16 17:57:44 +00:00
if ( url . isLocalFile ( ) ) {
2014-09-17 22:30:39 +00:00
QTemporaryFile tf ( QDir : : tempPath ( ) + QLatin1String ( " /okular_XXXXXX.pdf " ) ) ;
2006-10-16 17:57:44 +00:00
tf . setAutoRemove ( false ) ;
if ( ! tf . open ( ) )
return false ;
m_temporaryLocalFile = tf . fileName ( ) ;
2005-07-15 18:20:57 +00:00
tf . close ( ) ;
2006-10-16 17:57:44 +00:00
2010-01-08 15:29:38 +00:00
setLocalFilePath ( url . toLocalFile ( ) ) ;
2007-03-27 00:00:41 +00:00
QStringList args ;
QProcess * p = new QProcess ( ) ;
args < < url . toLocalFile ( ) < < m_temporaryLocalFile ;
2005-07-15 18:20:57 +00:00
m_pageView - > displayMessage ( i18n ( " Importing PS file as PDF (this may take a while)... " ) ) ;
2020-02-20 14:48:08 +00:00
connect ( p , QOverload < int , QProcess : : ExitStatus > : : of ( & QProcess : : finished ) , this , & Part : : psTransformEnded ) ;
2007-03-27 00:00:41 +00:00
p - > start ( app , args ) ;
2005-07-15 18:20:57 +00:00
return true ;
}
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
2006-11-18 21:36:56 +00:00
m_temporaryLocalFile . clear ( ) ;
- Page/Link: tooltips for links backported
- Page: rotation does not switch height and width
- Document/Part/Generator:
1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel
also add possibility to merge an XML .rc file with menu layout. Relevant functions are:
QString Generator::getXMLFile(), returns a QString with your .rc file name.
void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface
2. Supporting backend settings:
If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings]
set to true) are found, a menu item: configure backends is created, clicking on it results in
loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg)
function should be overloaded by a generator and dlg->addPage should be used to add pages.
If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another.
3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration)
to the generator class, and sending a message to the user is as simple as emitting a signal!
4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your
event and return true if pageview is to proceed with its handling or false if not.
5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your
Generator::print()
6. PixmapRequest handling update:
a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async)
b.) Document::sendGeneratorRequests is a slot now
c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving)
is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is
run in three places:
1. in requestPixmaps when we receive a request
2. in requestDone if pixmapStack is not empty
3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async)
it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request
7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime
- TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks.
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
2005-08-10 16:14:39 +00:00
return false ;
2005-07-15 18:20:57 +00:00
}
2005-11-04 11:59:51 +00:00
2014-05-10 22:53:20 +00:00
void Part : : setFileToWatch ( const QString & filePath )
2011-09-06 18:01:41 +00:00
{
2014-05-10 22:53:20 +00:00
if ( ! m_watchedFilePath . isEmpty ( ) )
unsetFileToWatch ( ) ;
2011-09-06 18:01:41 +00:00
const QFileInfo fi ( filePath ) ;
2014-05-10 22:53:20 +00:00
m_watchedFilePath = filePath ;
m_watcher - > addFile ( m_watchedFilePath ) ;
if ( fi . isSymLink ( ) ) {
2019-03-12 12:21:07 +00:00
m_watchedFileSymlinkTarget = fi . symLinkTarget ( ) ;
2014-05-10 22:53:20 +00:00
m_watcher - > addFile ( m_watchedFileSymlinkTarget ) ;
} else {
m_watchedFileSymlinkTarget . clear ( ) ;
}
}
void Part : : unsetFileToWatch ( )
{
if ( m_watchedFilePath . isEmpty ( ) )
return ;
m_watcher - > removeFile ( m_watchedFilePath ) ;
if ( ! m_watchedFileSymlinkTarget . isEmpty ( ) )
m_watcher - > removeFile ( m_watchedFileSymlinkTarget ) ;
m_watchedFilePath . clear ( ) ;
m_watchedFileSymlinkTarget . clear ( ) ;
2011-09-06 18:01:41 +00:00
}
2007-01-13 00:33:50 +00:00
2014-09-11 13:18:05 +00:00
Document : : OpenResult Part : : doOpenFile ( const QMimeType & mimeA , const QString & fileNameToOpenA , bool * isCompressedFile )
2003-09-15 09:35:55 +00:00
{
2014-09-11 13:18:05 +00:00
QMimeDatabase db ;
2014-08-13 21:51:48 +00:00
Document : : OpenResult openResult = Document : : OpenError ;
2007-07-29 00:55:17 +00:00
bool uncompressOk = true ;
2014-09-11 13:18:05 +00:00
QMimeType mime = mimeA ;
2014-08-13 21:51:48 +00:00
QString fileNameToOpen = fileNameToOpenA ;
2016-07-11 21:52:42 +00:00
KFilterDev : : CompressionType compressionType = compressionTypeFor ( mime . name ( ) ) ;
if ( compressionType ! = KFilterDev : : None ) {
2014-08-13 21:51:48 +00:00
* isCompressedFile = true ;
2016-07-11 21:52:42 +00:00
uncompressOk = handleCompressed ( fileNameToOpen , localFilePath ( ) , compressionType ) ;
2014-09-11 13:18:05 +00:00
mime = db . mimeTypeForFile ( fileNameToOpen ) ;
2014-08-13 21:51:48 +00:00
} else {
* isCompressedFile = false ;
}
2014-05-09 22:53:39 +00:00
if ( m_swapInsteadOfOpening ) {
m_swapInsteadOfOpening = false ;
if ( ! uncompressOk )
2014-09-08 12:58:55 +00:00
return Document : : OpenError ;
2014-05-09 22:53:39 +00:00
2017-09-10 09:51:56 +00:00
if ( mime . inherits ( QStringLiteral ( " application/vnd.kde.okular-archive " ) ) ) {
2014-05-09 22:53:39 +00:00
isDocumentArchive = true ;
2014-09-08 12:58:55 +00:00
if ( ! m_document - > swapBackingFileArchive ( fileNameToOpen , url ( ) ) )
return Document : : OpenError ;
2014-05-09 22:53:39 +00:00
} else {
isDocumentArchive = false ;
2014-09-08 12:58:55 +00:00
if ( ! m_document - > swapBackingFile ( fileNameToOpen , url ( ) ) )
return Document : : OpenError ;
2014-05-09 22:53:39 +00:00
}
2014-09-10 10:15:09 +00:00
2018-02-05 23:30:12 +00:00
m_fileLastModified = QFileInfo ( localFilePath ( ) ) . lastModified ( ) ;
2014-09-10 10:15:09 +00:00
return Document : : OpenSuccess ;
2014-05-09 22:53:39 +00:00
}
2012-05-30 16:33:07 +00:00
isDocumentArchive = false ;
2007-07-29 00:55:17 +00:00
if ( uncompressOk ) {
2015-10-29 12:37:11 +00:00
if ( mime . inherits ( QStringLiteral ( " application/vnd.kde.okular-archive " ) ) ) {
2014-05-09 17:56:16 +00:00
openResult = m_document - > openDocumentArchive ( fileNameToOpen , url ( ) ) ;
2012-05-30 16:33:07 +00:00
isDocumentArchive = true ;
2008-11-16 01:23:31 +00:00
} else {
2014-05-09 17:56:16 +00:00
openResult = m_document - > openDocument ( fileNameToOpen , url ( ) , mime ) ;
}
2017-10-26 16:58:34 +00:00
m_documentOpenWithPassword = false ;
2014-05-09 17:56:16 +00:00
2020-09-09 12:13:09 +00:00
# ifdef WITH_KWALLET
2014-05-09 17:56:16 +00:00
// if the file didn't open correctly it might be encrypted, so ask for a pass
2014-05-10 13:31:59 +00:00
QString walletName , walletFolder , walletKey ;
m_document - > walletDataForFile ( fileNameToOpen , & walletName , & walletFolder , & walletKey ) ;
2014-05-09 17:56:16 +00:00
bool firstInput = true ;
bool triedWallet = false ;
2017-09-05 21:27:18 +00:00
KWallet : : Wallet * wallet = nullptr ;
2014-05-09 17:56:16 +00:00
bool keep = true ;
while ( openResult = = Document : : OpenNeedsPassword ) {
QString password ;
// 1.A. try to retrieve the first password from the kde wallet system
if ( ! triedWallet & & ! walletKey . isNull ( ) ) {
const WId parentwid = widget ( ) - > effectiveWinId ( ) ;
wallet = KWallet : : Wallet : : openWallet ( walletName , parentwid ) ;
if ( wallet ) {
// use the KPdf folder (and create if missing)
2014-05-10 13:31:59 +00:00
if ( ! wallet - > hasFolder ( walletFolder ) )
wallet - > createFolder ( walletFolder ) ;
wallet - > setFolder ( walletFolder ) ;
2014-05-09 17:56:16 +00:00
// look for the pass in that folder
QString retrievedPass ;
if ( ! wallet - > readPassword ( walletKey , retrievedPass ) )
password = retrievedPass ;
}
triedWallet = true ;
}
// 1.B. if not retrieved, ask the password using the kde password dialog
if ( password . isNull ( ) ) {
QString prompt ;
if ( firstInput )
prompt = i18n ( " Please enter the password to read the document: " ) ;
else
prompt = i18n ( " Incorrect password. Try again: " ) ;
firstInput = false ;
// if the user presses cancel, abort opening
KPasswordDialog dlg ( widget ( ) , wallet ? KPasswordDialog : : ShowKeepPassword : KPasswordDialog : : KPasswordDialogFlags ( ) ) ;
2014-08-09 23:08:54 +00:00
dlg . setWindowTitle ( i18n ( " Document Password " ) ) ;
2014-05-09 17:56:16 +00:00
dlg . setPrompt ( prompt ) ;
if ( ! dlg . exec ( ) )
break ;
password = dlg . password ( ) ;
if ( wallet )
keep = dlg . keepPassword ( ) ;
}
// 2. reopen the document using the password
2015-10-29 12:37:11 +00:00
if ( mime . inherits ( QStringLiteral ( " application/vnd.kde.okular-archive " ) ) ) {
2014-05-09 17:56:16 +00:00
openResult = m_document - > openDocumentArchive ( fileNameToOpen , url ( ) , password ) ;
isDocumentArchive = true ;
} else {
openResult = m_document - > openDocument ( fileNameToOpen , url ( ) , mime , password ) ;
}
2017-10-26 16:58:34 +00:00
if ( openResult = = Document : : OpenSuccess ) {
m_documentOpenWithPassword = true ;
// 3. if the password is correct and the user chose to remember it, store it to the wallet
if ( wallet & & /*safety check*/ wallet - > isOpen ( ) & & keep ) {
wallet - > writePassword ( walletKey , password ) ;
}
2014-05-09 17:56:16 +00:00
}
2012-05-30 16:33:07 +00:00
}
2020-09-09 12:13:09 +00:00
# endif
2007-07-29 00:55:17 +00:00
}
2005-01-27 17:31:07 +00:00
2017-11-17 13:19:12 +00:00
if ( openResult = = Document : : OpenSuccess ) {
2018-02-05 23:30:12 +00:00
m_fileLastModified = QFileInfo ( localFilePath ( ) ) . lastModified ( ) ;
2017-11-17 13:19:12 +00:00
}
2014-08-13 21:51:48 +00:00
return openResult ;
}
bool Part : : openFile ( )
{
2014-09-11 13:18:05 +00:00
QList < QMimeType > mimes ;
2014-08-13 21:51:48 +00:00
QString fileNameToOpen = localFilePath ( ) ;
2014-08-14 11:35:43 +00:00
const bool isstdin = url ( ) . isLocalFile ( ) & & url ( ) . fileName ( ) = = QLatin1String ( " - " ) ;
2014-08-13 21:51:48 +00:00
const QFileInfo fileInfo ( fileNameToOpen ) ;
2014-08-14 11:35:43 +00:00
if ( ( ! isstdin ) & & ( ! fileInfo . exists ( ) ) )
2014-08-13 21:51:48 +00:00
return false ;
2014-09-11 13:18:05 +00:00
QMimeDatabase db ;
QMimeType pathMime = db . mimeTypeForFile ( fileNameToOpen ) ;
2014-08-13 21:51:48 +00:00
if ( ! arguments ( ) . mimeType ( ) . isEmpty ( ) ) {
2014-09-11 13:18:05 +00:00
QMimeType argMime = db . mimeTypeForName ( arguments ( ) . mimeType ( ) ) ;
2014-08-13 21:51:48 +00:00
// Select the "childmost" mimetype, if none of them
// inherits the other trust more what pathMime says
// but still do a second try if that one fails
2014-09-11 13:18:05 +00:00
if ( argMime . inherits ( pathMime . name ( ) ) ) {
2014-08-13 21:51:48 +00:00
mimes < < argMime ;
2014-09-11 13:18:05 +00:00
} else if ( pathMime . inherits ( argMime . name ( ) ) ) {
2014-08-13 21:51:48 +00:00
mimes < < pathMime ;
} else {
mimes < < pathMime < < argMime ;
}
2015-10-29 12:37:11 +00:00
if ( mimes [ 0 ] . name ( ) = = QLatin1String ( " text/plain " ) ) {
2014-09-11 13:18:05 +00:00
QMimeType contentMime = db . mimeTypeForFile ( fileNameToOpen , QMimeDatabase : : MatchContent ) ;
2014-08-13 21:51:48 +00:00
mimes . prepend ( contentMime ) ;
}
} else {
mimes < < pathMime ;
}
2014-09-11 13:18:05 +00:00
QMimeType mime ;
2014-08-13 21:51:48 +00:00
Document : : OpenResult openResult = Document : : OpenError ;
bool isCompressedFile = false ;
while ( ! mimes . isEmpty ( ) & & openResult = = Document : : OpenError ) {
mime = mimes . takeFirst ( ) ;
openResult = doOpenFile ( mime , fileNameToOpen , & isCompressedFile ) ;
}
2014-05-09 17:56:16 +00:00
bool canSearch = m_document - > supportsSearching ( ) ;
2014-02-08 10:44:26 +00:00
emit mimeTypeChanged ( mime ) ;
2005-01-27 17:31:07 +00:00
// update one-time actions
2014-05-09 17:56:16 +00:00
const bool ok = openResult = = Document : : OpenSuccess ;
2012-09-04 18:04:01 +00:00
emit enableCloseAction ( ok ) ;
2005-06-24 16:45:25 +00:00
m_find - > setEnabled ( ok & & canSearch ) ;
m_findNext - > setEnabled ( ok & & canSearch ) ;
2009-02-14 17:11:29 +00:00
m_findPrev - > setEnabled ( ok & & canSearch ) ;
2019-04-25 21:10:48 +00:00
if ( m_save )
m_save - > setEnabled ( ok & & ! ( isstdin | | mime . inherits ( QStringLiteral ( " inode/directory " ) ) ) ) ;
if ( m_saveAs )
m_saveAs - > setEnabled ( ok & & ! ( isstdin | | mime . inherits ( QStringLiteral ( " inode/directory " ) ) ) ) ;
2008-03-31 20:51:05 +00:00
emit enablePrintAction ( ok & & m_document - > printingSupport ( ) ! = Okular : : Document : : NoPrinting ) ;
2007-11-26 21:43:54 +00:00
m_printPreview - > setEnabled ( ok & & m_document - > printingSupport ( ) ! = Okular : : Document : : NoPrinting ) ;
2005-02-02 18:18:26 +00:00
m_showProperties - > setEnabled ( ok ) ;
2019-06-28 15:41:15 +00:00
if ( m_openContainingFolder )
m_openContainingFolder - > setEnabled ( ok ) ;
2006-10-03 10:11:16 +00:00
bool hasEmbeddedFiles = ok & & m_document - > embeddedFiles ( ) & & m_document - > embeddedFiles ( ) - > count ( ) > 0 ;
2011-10-12 19:36:01 +00:00
if ( m_showEmbeddedFiles )
m_showEmbeddedFiles - > setEnabled ( hasEmbeddedFiles ) ;
2013-12-12 22:44:38 +00:00
m_topMessage - > setVisible ( hasEmbeddedFiles & & Okular : : Settings : : showOSD ( ) ) ;
2014-09-10 10:01:58 +00:00
m_migrationMessage - > setVisible ( m_document - > isDocdataMigrationNeeded ( ) ) ;
2012-11-02 11:32:44 +00:00
// Warn the user that XFA forms are not supported yet (NOTE: poppler generator only)
2015-10-29 12:37:11 +00:00
if ( ok & & m_document - > metaData ( QStringLiteral ( " HasUnsupportedXfaForm " ) ) . toBool ( ) = = true ) {
2014-05-09 15:19:50 +00:00
m_formsMessage - > setText ( i18n ( " This document has XFA forms, which are currently <b>unsupported</b>. " ) ) ;
2015-10-29 12:37:11 +00:00
m_formsMessage - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " dialog-warning " ) ) ) ;
2014-05-09 15:19:50 +00:00
m_formsMessage - > setMessageType ( KMessageWidget : : Warning ) ;
2012-11-02 11:32:44 +00:00
m_formsMessage - > setVisible ( true ) ;
}
2007-06-05 20:49:00 +00:00
// m_pageView->toggleFormsAction() may be null on dummy mode
2012-11-02 11:32:44 +00:00
else if ( ok & & m_pageView - > toggleFormsAction ( ) & & m_pageView - > toggleFormsAction ( ) - > isEnabled ( ) ) {
2014-05-09 15:19:50 +00:00
m_formsMessage - > setText ( i18n ( " This document has forms. Click on the button to interact with them, or use View -> Show Forms. " ) ) ;
m_formsMessage - > setMessageType ( KMessageWidget : : Information ) ;
2012-11-02 11:32:44 +00:00
m_formsMessage - > setVisible ( true ) ;
} else {
m_formsMessage - > setVisible ( false ) ;
}
2020-09-05 17:57:57 +00:00
if ( ok ) {
const uint numPages = m_document - > pages ( ) ;
bool isDigitallySigned = false ;
for ( uint i = 0 ; i < numPages ; i + + ) {
const QLinkedList < Okular : : FormField * > formFields = m_document - > page ( i ) - > formFields ( ) ;
for ( const Okular : : FormField * f : formFields ) {
if ( f - > type ( ) = = Okular : : FormField : : FormSignature )
isDigitallySigned = true ;
}
}
if ( isDigitallySigned ) {
if ( m_embedMode = = PrintPreviewMode ) {
m_signatureMessage - > setText ( i18n ( " All editing and interactive features for this document are disabled. Please save a copy and reopen to edit this document. " ) ) ;
} else {
2020-09-06 11:19:00 +00:00
const QVector < const Okular : : FormFieldSignature * > signatureFormFields = SignatureGuiUtils : : getSignatureFormFields ( m_document , true , 0 ) ;
bool allSignaturesValid = true ;
for ( const Okular : : FormFieldSignature * signature : signatureFormFields ) {
const Okular : : SignatureInfo & info = signature - > signatureInfo ( ) ;
if ( info . signatureStatus ( ) ! = SignatureInfo : : SignatureValid ) {
allSignaturesValid = false ;
}
}
if ( allSignaturesValid ) {
if ( signatureFormFields . last ( ) - > signatureInfo ( ) . signsTotalDocument ( ) ) {
m_signatureMessage - > setMessageType ( KMessageWidget : : Information ) ;
m_signatureMessage - > setText ( i18n ( " This document is digitally signed. " ) ) ;
} else {
m_signatureMessage - > setMessageType ( KMessageWidget : : Warning ) ;
m_signatureMessage - > setText ( i18n ( " This document is digitally signed. There have been changes since last signed. " ) ) ;
}
} else {
m_signatureMessage - > setMessageType ( KMessageWidget : : Warning ) ;
m_signatureMessage - > setText ( i18n ( " This document is digitally signed. Some of the signatures could not be validated properly. " ) ) ;
}
2020-09-05 17:57:57 +00:00
}
2020-09-06 08:50:29 +00:00
m_signatureMessage - > setVisible ( true ) ;
2019-01-05 22:30:25 +00:00
}
}
2011-10-12 19:36:01 +00:00
if ( m_showPresentation )
m_showPresentation - > setEnabled ( ok ) ;
2006-07-01 22:17:53 +00:00
if ( ok ) {
2011-10-12 19:36:01 +00:00
if ( m_exportAs ) {
m_exportFormats = m_document - > exportFormats ( ) ;
QList < Okular : : ExportFormat > : : ConstIterator it = m_exportFormats . constBegin ( ) ;
QList < Okular : : ExportFormat > : : ConstIterator itEnd = m_exportFormats . constEnd ( ) ;
QMenu * menu = m_exportAs - > menu ( ) ;
for ( ; it ! = itEnd ; + + it ) {
menu - > addAction ( actionForExportFormat ( * it ) ) ;
}
2006-07-01 22:17:53 +00:00
}
2017-10-11 15:45:02 +00:00
# if PURPOSE_FOUND
if ( m_share ) {
m_shareMenu - > model ( ) - > setInputData ( QJsonObject { { QStringLiteral ( " mimeType " ) , mime . name ( ) } , { QStringLiteral ( " urls " ) , QJsonArray { url ( ) . toString ( ) } } } ) ;
m_shareMenu - > model ( ) - > setPluginType ( QStringLiteral ( " Export " ) ) ;
m_shareMenu - > reload ( ) ;
}
# endif
2007-07-29 00:55:17 +00:00
if ( isCompressedFile ) {
m_realUrl = url ( ) ;
}
2008-06-07 21:08:41 +00:00
# ifdef OKULAR_KEEP_FILE_OPEN
if ( keepFileOpen ( ) )
m_keeper - > open ( fileNameToOpen ) ;
# endif
2019-02-13 21:55:02 +00:00
// Tries to find the text passed from terminal after the file is open
if ( ! m_textToFindOnOpen . isEmpty ( ) ) {
m_findBar - > startSearch ( m_textToFindOnOpen ) ;
m_textToFindOnOpen = QString ( ) ;
}
2006-07-01 22:17:53 +00:00
}
2011-10-12 19:36:01 +00:00
if ( m_exportAsText )
m_exportAsText - > setEnabled ( ok & & m_document - > canExportToText ( ) ) ;
if ( m_exportAs )
m_exportAs - > setEnabled ( ok ) ;
2017-10-11 15:45:02 +00:00
# if PURPOSE_FOUND
if ( m_share )
m_share - > setEnabled ( ok ) ;
# endif
2005-01-27 17:31:07 +00:00
// update viewing actions
2005-02-02 18:18:26 +00:00
updateViewActions ( ) ;
2008-11-21 10:50:16 +00:00
2008-03-17 23:02:33 +00:00
m_fileWasRemoved = false ;
2005-01-01 15:44:44 +00:00
2005-01-27 17:31:07 +00:00
if ( ! ok ) {
// if can't open document, update windows so they display blank contents
2009-06-29 20:55:50 +00:00
m_pageView - > viewport ( ) - > update ( ) ;
2006-05-05 21:12:04 +00:00
m_thumbnailList - > update ( ) ;
2015-01-29 19:55:57 +00:00
setUrl ( QUrl ( ) ) ;
2005-01-27 17:31:07 +00:00
return false ;
}
// set the file to the fileWatcher
2008-03-17 23:02:33 +00:00
if ( url ( ) . isLocalFile ( ) )
2014-05-10 22:53:20 +00:00
setFileToWatch ( localFilePath ( ) ) ;
2005-01-27 17:31:07 +00:00
2007-04-15 20:00:43 +00:00
// if the 'OpenTOC' flag is set, open the TOC
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
if ( m_document - > metaData ( QStringLiteral ( " OpenTOC " ) ) . toBool ( ) & & m_tocEnabled & & m_sidebar - > currentItem ( ) ! = m_toc ) {
m_sidebar - > setCurrentItem ( m_toc ) ;
2006-10-28 18:21:55 +00:00
}
2018-04-12 16:40:00 +00:00
// if the 'StartFullScreen' flag is set and we're not in viewer widget mode, or the command line flag was
2007-01-04 00:20:50 +00:00
// specified, start presentation
2018-04-12 16:40:00 +00:00
const bool presentationBecauseOfDocumentMetadata = ( m_embedMode ! = ViewerWidgetMode ) & & m_document - > metaData ( QStringLiteral ( " StartFullScreen " ) ) . toBool ( ) ;
2020-05-11 07:15:50 +00:00
if ( ( presentationBecauseOfDocumentMetadata | | m_cliPresentation ) & & ! m_isReloading ) {
2008-03-13 11:42:15 +00:00
bool goAheadWithPresentationMode = true ;
2007-01-04 00:20:50 +00:00
if ( ! m_cliPresentation ) {
2018-01-06 05:12:06 +00:00
const QString text = i18n (
" This document wants to be shown full screen. \n "
" Leave normal mode and enter presentation mode? " ) ;
const QString caption = i18n ( " Request to Change Viewing Mode " ) ;
const KGuiItem yesItem = KGuiItem ( i18n ( " Enter Presentation Mode " ) , QStringLiteral ( " dialog-ok " ) ) ;
const KGuiItem noItem = KGuiItem ( i18n ( " Deny Request " ) , QStringLiteral ( " dialog-cancel " ) ) ;
2008-03-13 11:42:15 +00:00
const int result = KMessageBox : : questionYesNo ( widget ( ) , text , caption , yesItem , noItem ) ;
if ( result = = KMessageBox : : No )
goAheadWithPresentationMode = false ;
}
2007-01-04 00:20:50 +00:00
m_cliPresentation = false ;
2008-03-13 11:42:15 +00:00
if ( goAheadWithPresentationMode )
QMetaObject : : invokeMethod ( this , " slotShowPresentation " , Qt : : QueuedConnection ) ;
2005-06-13 16:55:57 +00:00
}
2017-09-05 21:27:18 +00:00
m_generatorGuiClient = factory ( ) ? m_document - > guiClient ( ) : nullptr ;
2007-08-28 23:17:00 +00:00
if ( m_generatorGuiClient )
factory ( ) - > addClient ( m_generatorGuiClient ) ;
2013-03-11 21:52:25 +00:00
if ( m_cliPrint ) {
m_cliPrint = false ;
slotPrint ( ) ;
2018-03-03 16:21:15 +00:00
} else if ( m_cliPrintAndExit ) {
slotPrint ( ) ;
}
2005-01-27 17:31:07 +00:00
return true ;
2003-09-15 09:35:55 +00:00
}
2017-09-10 09:51:56 +00:00
bool Part : : openUrl ( const QUrl & url )
2004-09-18 16:41:23 +00:00
{
2014-05-11 10:23:37 +00:00
return openUrl ( url , false /* swapInsteadOfOpening */ ) ;
}
2017-09-10 09:51:56 +00:00
bool Part : : openUrl ( const QUrl & _url , bool swapInsteadOfOpening )
2004-09-18 16:41:23 +00:00
{
2014-05-11 10:23:37 +00:00
/* Store swapInsteadOfOpening, so that closeUrl and openFile will be able
* to read it */
m_swapInsteadOfOpening = swapInsteadOfOpening ;
2018-02-25 10:45:44 +00:00
// The subsequent call to closeUrl clears the arguments.
// We want to save them and restore them later.
const KParts : : OpenUrlArguments args = arguments ( ) ;
2012-05-23 21:43:44 +00:00
// Close current document if any
if ( ! closeUrl ( ) )
return false ;
2018-02-25 10:45:44 +00:00
setArguments ( args ) ;
2015-01-29 19:55:57 +00:00
QUrl url ( _url ) ;
if ( url . hasFragment ( ) ) {
const QString dest = url . fragment ( QUrl : : FullyDecoded ) ;
2009-05-17 18:08:43 +00:00
bool ok = true ;
2020-09-09 11:52:30 +00:00
int page = dest . toInt ( & ok ) ;
if ( ! ok ) {
const QStringList parameters = dest . split ( QChar ( ' & ' ) ) ;
for ( const QString & parameter : parameters ) {
if ( parameter . startsWith ( QStringLiteral ( " page= " ) , Qt : : CaseInsensitive ) ) {
page = dest . midRef ( 5 ) . toInt ( & ok ) ;
}
}
}
2009-05-17 18:08:43 +00:00
if ( ok ) {
Okular : : DocumentViewport vp ( page - 1 ) ;
vp . rePos . enabled = true ;
vp . rePos . normalizedX = 0 ;
vp . rePos . normalizedY = 0 ;
vp . rePos . pos = Okular : : DocumentViewport : : TopLeft ;
m_document - > setNextDocumentViewport ( vp ) ;
} else {
m_document - > setNextDocumentDestination ( dest ) ;
}
2015-01-29 19:55:57 +00:00
url . setFragment ( QString ( ) ) ;
2009-05-17 18:08:43 +00:00
}
2006-08-30 13:02:48 +00:00
// this calls in sequence the 'closeUrl' and 'openFile' methods
2012-05-23 21:43:44 +00:00
bool openOk = KParts : : ReadWritePart : : openUrl ( url ) ;
2005-07-15 18:20:57 +00:00
2005-06-24 16:39:57 +00:00
if ( openOk ) {
2006-10-15 12:26:16 +00:00
m_viewportDirty . pageNumber = - 1 ;
2006-07-30 23:37:50 +00:00
2007-06-05 21:25:41 +00:00
setWindowTitleFromDocument ( ) ;
2010-08-20 16:20:17 +00:00
} else {
2013-03-11 21:52:25 +00:00
resetStartArguments ( ) ;
2020-02-10 23:22:06 +00:00
/* TRANSLATORS: Adding the reason (%2) why the opening failed (if any). */
2020-02-21 16:45:03 +00:00
QString errorMessage = i18n ( " Could not open %1. %2 " , url . toDisplayString ( ) , QStringLiteral ( " \n %1 " ) . arg ( m_document - > openError ( ) ) ) ;
2020-02-10 23:22:06 +00:00
KMessageBox : : error ( widget ( ) , errorMessage ) ;
2010-08-20 16:20:17 +00:00
}
2020-07-10 22:15:05 +00:00
2005-06-24 16:39:57 +00:00
return openOk ;
2004-09-18 16:41:23 +00:00
}
2012-05-23 21:43:44 +00:00
bool Part : : queryClose ( )
{
if ( ! isReadWrite ( ) | | ! isModified ( ) )
return true ;
2007-01-13 00:33:50 +00:00
2017-11-17 13:19:12 +00:00
// 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
if ( m_fileLastModified ! = QFileInfo ( localFilePath ( ) ) . lastModified ( ) ) {
int res ;
if ( m_isReloading ) {
res = KMessageBox : : warningYesNo (
widget ( ) ,
i18n ( " There are unsaved changes, and the file '%1' has been modified by another program. Your changes will be lost, because the file can no longer be saved.<br>Do you want to continue reloading the file? " , url ( ) . fileName ( ) ) ,
i18n ( " File Changed " ) ,
KGuiItem ( i18n ( " Continue Reloading " ) ) , // <- KMessageBox::Yes
KGuiItem ( i18n ( " Abort Reloading " ) ) ) ;
} else {
res = KMessageBox : : warningYesNo (
widget ( ) ,
i18n ( " There are unsaved changes, and the file '%1' has been modified by another program. Your changes will be lost, because the file can no longer be saved.<br>Do you want to continue closing the file? " , url ( ) . fileName ( ) ) ,
i18n ( " File Changed " ) ,
KGuiItem ( i18n ( " Continue Closing " ) ) , // <- KMessageBox::Yes
KGuiItem ( i18n ( " Abort Closing " ) ) ) ;
}
return res = = KMessageBox : : Yes ;
}
2017-11-16 11:03:23 +00:00
const int res = KMessageBox : : warningYesNoCancel ( widget ( ) , i18n ( " Do you want to save your changes to \" %1 \" or discard them? " , url ( ) . fileName ( ) ) , i18n ( " Close Document " ) , KStandardGuiItem : : save ( ) , KStandardGuiItem : : discard ( ) ) ;
2012-05-23 21:43:44 +00:00
switch ( res ) {
2017-11-13 09:10:46 +00:00
case KMessageBox : : Yes : // Save
2014-05-09 20:36:24 +00:00
saveFile ( ) ;
2012-05-23 21:43:44 +00:00
return ! isModified ( ) ; // Only allow closing if file was really saved
case KMessageBox : : No : // Discard
return true ;
default : // Cancel
return false ;
}
}
bool Part : : closeUrl ( bool promptToSave )
2005-02-02 18:18:26 +00:00
{
2012-05-23 21:43:44 +00:00
if ( promptToSave & & ! queryClose ( ) )
return false ;
2014-05-09 22:53:39 +00:00
if ( m_swapInsteadOfOpening ) {
// If we're swapping the backing file, we don't want to close the
// current one when openUrl() calls us internally
return true ; // pretend it worked
}
2017-11-15 08:46:36 +00:00
m_document - > setHistoryClean ( true ) ;
2012-05-23 21:43:44 +00:00
2007-03-28 22:01:38 +00:00
if ( ! m_temporaryLocalFile . isNull ( ) & & m_temporaryLocalFile ! = localFilePath ( ) ) {
2005-07-15 18:20:57 +00:00
QFile : : remove ( m_temporaryLocalFile ) ;
2006-11-18 21:36:56 +00:00
m_temporaryLocalFile . clear ( ) ;
2005-07-15 18:20:57 +00:00
}
2005-11-04 11:59:51 +00:00
slotHidePresentation ( ) ;
2012-09-04 18:04:01 +00:00
emit enableCloseAction ( false ) ;
2005-02-02 18:18:26 +00:00
m_find - > setEnabled ( false ) ;
m_findNext - > setEnabled ( false ) ;
2009-02-14 17:11:29 +00:00
m_findPrev - > setEnabled ( false ) ;
2014-05-09 20:36:24 +00:00
if ( m_save )
m_save - > setEnabled ( false ) ;
2011-10-12 19:36:01 +00:00
if ( m_saveAs )
m_saveAs - > setEnabled ( false ) ;
2005-02-02 18:18:26 +00:00
m_printPreview - > setEnabled ( false ) ;
m_showProperties - > setEnabled ( false ) ;
2011-10-12 19:36:01 +00:00
if ( m_showEmbeddedFiles )
m_showEmbeddedFiles - > setEnabled ( false ) ;
if ( m_exportAs )
m_exportAs - > setEnabled ( false ) ;
if ( m_exportAsText )
m_exportAsText - > setEnabled ( false ) ;
2006-10-25 15:35:53 +00:00
m_exportFormats . clear ( ) ;
2011-10-12 19:36:01 +00:00
if ( m_exportAs ) {
QMenu * menu = m_exportAs - > menu ( ) ;
QList < QAction * > acts = menu - > actions ( ) ;
int num = acts . count ( ) ;
2014-05-09 15:40:14 +00:00
for ( int i = 1 ; i < num ; + + i ) {
2011-10-12 19:36:01 +00:00
menu - > removeAction ( acts . at ( i ) ) ;
delete acts . at ( i ) ;
}
2006-07-01 22:17:53 +00:00
}
2017-10-11 15:45:02 +00:00
# if PURPOSE_FOUND
if ( m_share ) {
m_share - > setEnabled ( false ) ;
m_shareMenu - > clear ( ) ;
}
# endif
2011-10-12 19:36:01 +00:00
if ( m_showPresentation )
m_showPresentation - > setEnabled ( false ) ;
2015-10-29 12:37:11 +00:00
emit setWindowCaption ( QLatin1String ( " " ) ) ;
2005-11-04 11:59:51 +00:00
emit enablePrintAction ( false ) ;
2015-01-29 19:55:57 +00:00
m_realUrl = QUrl ( ) ;
2008-01-01 15:59:18 +00:00
if ( url ( ) . isLocalFile ( ) )
2014-05-10 22:53:20 +00:00
unsetFileToWatch ( ) ;
2008-03-17 23:02:33 +00:00
m_fileWasRemoved = false ;
2007-08-28 23:17:00 +00:00
if ( m_generatorGuiClient )
factory ( ) - > removeClient ( m_generatorGuiClient ) ;
2017-09-05 21:27:18 +00:00
m_generatorGuiClient = nullptr ;
2005-02-02 18:18:26 +00:00
m_document - > closeDocument ( ) ;
2017-11-17 13:19:12 +00:00
m_fileLastModified = QDateTime ( ) ;
2005-11-04 11:59:51 +00:00
updateViewActions ( ) ;
2007-07-29 10:38:48 +00:00
delete m_tempfile ;
2017-09-05 21:27:18 +00:00
m_tempfile = nullptr ;
2008-09-22 22:58:32 +00:00
if ( widget ( ) ) {
m_searchWidget - > clearText ( ) ;
2014-09-10 10:01:58 +00:00
m_migrationMessage - > setVisible ( false ) ;
2008-09-22 22:58:32 +00:00
m_topMessage - > setVisible ( false ) ;
m_formsMessage - > setVisible ( false ) ;
2019-01-05 22:30:25 +00:00
m_signatureMessage - > setVisible ( false ) ;
2008-09-22 22:58:32 +00:00
}
2008-06-07 21:08:41 +00:00
# ifdef OKULAR_KEEP_FILE_OPEN
m_keeper - > close ( ) ;
# endif
2012-05-23 21:43:44 +00:00
bool r = KParts : : ReadWritePart : : closeUrl ( ) ;
2015-01-29 19:55:57 +00:00
setUrl ( QUrl ( ) ) ;
2011-09-09 20:59:59 +00:00
return r ;
2005-02-02 18:18:26 +00:00
}
2012-05-23 21:43:44 +00:00
bool Part : : closeUrl ( )
{
return closeUrl ( true ) ;
}
2011-10-23 10:07:38 +00:00
void Part : : guiActivateEvent ( KParts : : GUIActivateEvent * event )
{
updateViewActions ( ) ;
2012-05-23 21:43:44 +00:00
KParts : : ReadWritePart : : guiActivateEvent ( event ) ;
2015-01-06 23:17:35 +00:00
setWindowTitleFromDocument ( ) ;
Overhaul annotations UX
Create a new new annotation toolbar to replace the current one as discussed in the task T8076.
Fixes:
BUG: 386578
BUG: 374728
BUG: 352310
BUG: 330518
BUG: 341914
BUG: 157289
BUG: 358057
BUG: 412767
BUG: 413595
BUG: 420462
FIXED-IN: 1.11.0
Test Plan
Before testing this revision
Delete or Temporary move aside the following files:
~/.config/okularpartrc
~/.config/okularrc
~/.local/share/kxmlgui5/okular/part.rc
~/.local/share/kxmlgui5/okular/shell.rc
Nomenclature
Actions in the main toolbar:
Quick annotations
Actions in the annotation toolbar:
Annotation actions Highlighter, Underline, Squiggle, Strike out, Typewriter,
Inline note, Popup note, Freehand line, Arrow, Straight line, Rectangle, Ellipse,
Polygon, Stamp
Annotation config actions Line width, Color, Inner color, Opacity, Font, Annotation settings
Other actions Add to Quick Annotations, Pin
Autotests
First run: annotation toolbar is not visible
Selecting Tools > Annotations shows the annotation toolbar (below the main toolbar by default)
Select an annotation > toolbar is shown
Select a quick annotation > toolbar is shown
Hide action (red cross) on the toolbar hides the toolbar
Keys 1-9,0 select the (builtin) Annotation actions (one case tested)
Keys Alt+1-9,0 select the quick annotation actions (one case tested)
No annotation action selected: Quick Annotations is enabled, Add to quick annotations is disabled, Annotation config actions are disabled, Pin is enabled
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled (also in Quick annotations)
The current document is protected: All actions are disabled
Select annotation: the Annotation config actions are enabled and their values set to the ones for the current annotation (taken from okularpartrc)
Click an annotation action when none selected: browse mode is selected
Click the currently selected annotation action: the action is unchecked and the tool disabled (back to browse mode)
Click ESC: the currently selected annotation action is unchecked
If Pin unchecked the selected annotation is unchecked after it has be used once and we are back to Browse mode
The annotation systems works when multiple Okular tabs are open (the selected annotation is per-tab)
Manual tests
(TODO) Check that kconf_update updates the key AnnotationTools to QuickAnnotationTools in ~/.config/okularpartrc
Color icon is a format-text-color (if inline note or typewriter) or format-stroke-color for all other annotations
All actions have tooltips (some change based on the fact that the icon is enabled or not)
If a custom Line Width or Opacity is set through the Annotation Settings dialog, its value appears as a new checked action in the Line width or Opacity menu
If a custom stamp is selected through the Annotation Settings dialog, its name or filename (without path) appears as a new checked action in the Stamp menu
In Configure Okular > Annotations it is only possible to configure the quick annotations. Modifying them here updates the Quick annotations list after clicking Apply
The current document is an image: Highlighter, Underline, Squiggle, Strike out are disabled in Quick annotations
The state of Pin action is remembered across Okular launches
Selecting a quick action selects the corresponding action and loads its config values (color, line width, ...)
Setting the color and fill color works for all annotations (to be tested carefully, can be problematic for typewriter and inline note given the different internal mechanism to store the color in the settings)
Test stamp annotation (handled differently from the rest of the annotations)
Merge Request: https://invent.kde.org/graphics/okular/-/merge_requests/105
2020-06-04 13:01:31 +00:00
2020-07-14 10:13:34 +00:00
if ( event - > activated ( ) ) {
m_pageView - > setupActionsPostGUIActivated ( ) ;
}
2011-10-23 10:07:38 +00:00
}
2007-01-13 00:33:50 +00:00
2005-11-04 11:59:51 +00:00
void Part : : close ( )
{
2009-03-22 18:38:38 +00:00
if ( m_embedMode = = NativeShellMode ) {
2007-01-13 00:33:50 +00:00
closeUrl ( ) ;
2015-10-29 12:37:11 +00:00
} else
KMessageBox : : information ( widget ( ) , i18n ( " This link points to a close document action that does not work when using the embedded viewer. " ) , QString ( ) , QStringLiteral ( " warnNoCloseIfNotInOkular " ) ) ;
2005-11-04 11:59:51 +00:00
}
void Part : : cannotQuit ( )
{
2015-10-29 12:37:11 +00:00
KMessageBox : : information ( widget ( ) , i18n ( " This link points to a quit application action that does not work when using the embedded viewer. " ) , QString ( ) , QStringLiteral ( " warnNoQuitIfNotInOkular " ) ) ;
2005-11-04 11:59:51 +00:00
}
2005-03-12 15:39:04 +00:00
void Part : : slotShowLeftPanel ( )
2004-12-01 22:18:27 +00:00
{
2005-03-12 15:39:04 +00:00
bool showLeft = m_showLeftPanel - > isChecked ( ) ;
2006-09-21 08:45:36 +00:00
Okular : : Settings : : setShowLeftPanel ( showLeft ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2005-03-13 13:14:44 +00:00
// show/hide left panel
2007-08-06 17:24:10 +00:00
m_sidebar - > setSidebarVisibility ( showLeft ) ;
2005-11-04 11:59:51 +00:00
}
2010-10-29 21:47:17 +00:00
void Part : : slotShowBottomBar ( )
{
const bool showBottom = m_showBottomBar - > isChecked ( ) ;
Okular : : Settings : : setShowBottomBar ( showBottom ) ;
2014-10-01 05:27:09 +00:00
Okular : : Settings : : self ( ) - > save ( ) ;
2010-10-29 21:47:17 +00:00
// show/hide bottom bar
m_bottomBar - > setVisible ( showBottom ) ;
}
2007-01-13 00:33:50 +00:00
2008-03-17 23:02:33 +00:00
void Part : : slotFileDirty ( const QString & path )
2004-12-01 22:18:27 +00:00
{
2007-01-13 00:33:50 +00:00
// The beauty of this is that each start cancels the previous one.
// This means that timeout() is only fired when there have
2018-11-14 19:12:15 +00:00
// no changes to the file for the last 750 millisecs.
2007-01-13 00:33:50 +00:00
// This ensures that we don't update on every other byte that gets
// written to the file.
2008-03-17 23:02:33 +00:00
if ( path = = localFilePath ( ) ) {
2010-07-05 22:33:16 +00:00
// Only start watching the file in case if it wasn't removed
if ( QFile : : exists ( localFilePath ( ) ) )
m_dirtyHandler - > start ( 750 ) ;
2010-07-05 22:48:09 +00:00
else
m_fileWasRemoved = true ;
2008-03-17 23:02:33 +00:00
} else {
2011-07-05 02:16:57 +00:00
const QFileInfo fi ( localFilePath ( ) ) ;
2008-03-17 23:02:33 +00:00
if ( fi . absolutePath ( ) = = path ) {
// Our parent has been dirtified
if ( ! QFile : : exists ( localFilePath ( ) ) ) {
m_fileWasRemoved = true ;
} else if ( m_fileWasRemoved & & QFile : : exists ( localFilePath ( ) ) ) {
// we need to watch the new file
2014-05-10 22:53:20 +00:00
unsetFileToWatch ( ) ;
setFileToWatch ( localFilePath ( ) ) ;
2008-03-17 23:02:33 +00:00
m_dirtyHandler - > start ( 750 ) ;
}
2019-03-12 12:21:07 +00:00
} else if ( fi . isSymLink ( ) & & fi . symLinkTarget ( ) = = path ) {
if ( QFile : : exists ( fi . symLinkTarget ( ) ) )
2011-07-05 02:16:57 +00:00
m_dirtyHandler - > start ( 750 ) ;
else
m_fileWasRemoved = true ;
}
2008-03-17 23:02:33 +00:00
}
2004-12-01 22:18:27 +00:00
}
2014-05-11 08:53:56 +00:00
// Attempt to reload the document, one or more times, optionally from a different URL
2017-09-10 09:51:56 +00:00
bool Part : : slotAttemptReload ( bool oneShot , const QUrl & newUrl )
2004-12-01 22:18:27 +00:00
{
2017-08-30 23:07:52 +00:00
// Skip reload when another reload is already in progress
if ( m_isReloading ) {
2017-09-10 09:51:56 +00:00
return false ;
2017-08-30 23:07:52 +00:00
}
QScopedValueRollback < bool > rollback ( m_isReloading , true ) ;
2013-01-18 17:02:07 +00:00
bool tocReloadPrepared = false ;
2014-11-08 04:33:23 +00:00
2005-06-24 16:39:57 +00:00
// do the following the first time the file is reloaded
2005-07-15 18:20:57 +00:00
if ( m_viewportDirty . pageNumber = = - 1 ) {
2012-11-30 22:24:19 +00:00
// store the url of the current document
2014-05-11 08:53:56 +00:00
m_oldUrl = newUrl . isEmpty ( ) ? url ( ) : newUrl ;
2012-11-30 22:24:19 +00:00
2005-06-24 16:39:57 +00:00
// store the current viewport
2006-10-15 12:26:16 +00:00
m_viewportDirty = m_document - > viewport ( ) ;
2007-04-20 23:22:56 +00:00
// store the current toolbox pane
2015-09-15 23:18:17 +00:00
m_dirtyToolboxItem = m_sidebar - > currentItem ( ) ;
2007-11-01 17:52:47 +00:00
m_wasSidebarVisible = m_sidebar - > isSidebarVisible ( ) ;
2007-04-20 23:22:56 +00:00
2006-10-15 12:26:16 +00:00
// store if presentation view was open
2017-09-05 21:27:18 +00:00
m_wasPresentationOpen = ( ( PresentationWidget * ) m_presentationWidget ! = nullptr ) ;
2014-11-08 04:33:23 +00:00
2013-01-15 00:17:14 +00:00
// preserves the toc state after reload
2013-01-18 17:02:07 +00:00
m_toc - > prepareForReload ( ) ;
tocReloadPrepared = true ;
2005-06-24 16:39:57 +00:00
2011-06-25 22:14:04 +00:00
// store the page rotation
m_dirtyPageRotation = m_document - > rotation ( ) ;
2005-06-24 16:39:57 +00:00
// inform the user about the operation in progress
2012-12-01 00:16:59 +00:00
// TODO: Remove this line and integrate reload info in queryClose
2005-06-24 16:39:57 +00:00
m_pageView - > displayMessage ( i18n ( " Reloading the document... " ) ) ;
}
// close and (try to) reopen the document
2012-05-23 21:43:44 +00:00
if ( ! closeUrl ( ) ) {
2013-06-02 15:21:27 +00:00
m_viewportDirty . pageNumber = - 1 ;
2014-11-08 04:33:23 +00:00
if ( tocReloadPrepared ) {
2013-01-18 17:02:07 +00:00
m_toc - > rollbackReload ( ) ;
}
2014-05-10 16:00:30 +00:00
return false ;
2013-01-18 17:02:07 +00:00
}
2014-11-08 04:33:23 +00:00
2013-01-18 17:02:07 +00:00
if ( tocReloadPrepared )
m_toc - > finishReload ( ) ;
2012-05-23 21:43:44 +00:00
2012-12-01 00:16:59 +00:00
// inform the user about the operation in progress
m_pageView - > displayMessage ( i18n ( " Reloading the document... " ) ) ;
2014-05-10 16:00:30 +00:00
bool reloadSucceeded = false ;
2012-11-30 22:24:19 +00:00
if ( KParts : : ReadWritePart : : openUrl ( m_oldUrl ) ) {
2006-12-28 16:58:56 +00:00
// on successful opening, restore the previous viewport
2007-01-13 00:33:50 +00:00
if ( m_viewportDirty . pageNumber > = ( int ) m_document - > pages ( ) )
2005-07-15 18:20:57 +00:00
m_viewportDirty . pageNumber = ( int ) m_document - > pages ( ) - 1 ;
m_document - > setViewport ( m_viewportDirty ) ;
2015-01-29 19:55:57 +00:00
m_oldUrl = QUrl ( ) ;
2005-07-15 18:20:57 +00:00
m_viewportDirty . pageNumber = - 1 ;
2011-06-25 22:14:04 +00:00
m_document - > setRotation ( m_dirtyPageRotation ) ;
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
if ( m_sidebar - > currentItem ( ) ! = m_dirtyToolboxItem ) {
2015-09-15 23:18:17 +00:00
m_sidebar - > setCurrentItem ( m_dirtyToolboxItem ) ;
2007-04-20 23:22:56 +00:00
}
2007-11-01 17:52:47 +00:00
if ( m_sidebar - > isSidebarVisible ( ) ! = m_wasSidebarVisible ) {
2010-09-04 00:14:45 +00:00
m_sidebar - > setSidebarVisibility ( m_wasSidebarVisible ) ;
2007-11-01 17:52:47 +00:00
}
2006-10-15 12:26:16 +00:00
if ( m_wasPresentationOpen )
slotShowPresentation ( ) ;
2007-11-26 21:43:54 +00:00
emit enablePrintAction ( true & & m_document - > printingSupport ( ) ! = Okular : : Document : : NoPrinting ) ;
2014-05-10 16:00:30 +00:00
reloadSucceeded = true ;
2014-05-11 08:53:56 +00:00
} else if ( ! oneShot ) {
2019-01-05 22:30:25 +00:00
// start watching the file again (since we dropped it on close)
2014-05-10 22:53:20 +00:00
setFileToWatch ( localFilePath ( ) ) ;
2006-05-13 11:33:36 +00:00
m_dirtyHandler - > start ( 750 ) ;
2005-06-24 16:39:57 +00:00
}
2014-05-10 16:00:30 +00:00
return reloadSucceeded ;
2004-12-01 22:18:27 +00:00
}
2005-02-02 18:18:26 +00:00
void Part : : updateViewActions ( )
2003-09-14 21:49:26 +00:00
{
2005-02-02 18:18:26 +00:00
bool opened = m_document - > pages ( ) > 0 ;
if ( opened ) {
2004-11-09 17:20:19 +00:00
m_gotoPage - > setEnabled ( m_document - > pages ( ) > 1 ) ;
2014-11-08 04:33:23 +00:00
2010-09-03 21:30:30 +00:00
// Check if you are at the beginning or not
if ( m_document - > currentPage ( ) ! = 0 ) {
m_beginningOfDocument - > setEnabled ( true ) ;
m_prevPage - > setEnabled ( true ) ;
2014-11-08 04:33:23 +00:00
} else {
2010-09-03 21:30:30 +00:00
if ( m_pageView - > verticalScrollBar ( ) - > value ( ) ! = 0 ) {
// The page isn't at the very beginning
m_beginningOfDocument - > setEnabled ( true ) ;
} else {
// The page is 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
m_prevPage - > setEnabled ( false ) ;
}
2014-11-08 04:33:23 +00:00
2010-09-03 21:30:30 +00:00
if ( m_document - > pages ( ) = = m_document - > currentPage ( ) + 1 ) {
// If you are at the end, 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
m_endOfDocument - > setEnabled ( false ) ;
2014-11-08 04:33:23 +00:00
} else {
2010-09-03 21:30:30 +00:00
// Otherwise you can move to the endif
m_endOfDocument - > setEnabled ( true ) ;
}
2014-11-08 04:33:23 +00:00
} else {
2010-09-03 21:30:30 +00:00
// If you are not at the end, enable go to next page
m_nextPage - > setEnabled ( true ) ;
m_endOfDocument - > setEnabled ( true ) ;
}
2020-07-10 22:15:05 +00:00
2007-06-17 09:45:59 +00:00
if ( m_historyBack )
m_historyBack - > setEnabled ( ! m_document - > historyAtBegin ( ) ) ;
if ( m_historyNext )
m_historyNext - > setEnabled ( ! m_document - > historyAtEnd ( ) ) ;
2007-05-06 11:23:26 +00:00
m_reload - > setEnabled ( true ) ;
2011-10-12 19:36:01 +00:00
if ( m_copy )
m_copy - > setEnabled ( true ) ;
if ( m_selectAll )
m_selectAll - > setEnabled ( true ) ;
Add action in Edit menu to select the text on current page
BUG: 358868
Test Plan: Click on "Select All Text on Current Page" entry in Edit menu to select the entire page. The selected text can then be copied via Edit menu item "Copy"
Reviewers: aacid, #vdg, ngraham
Reviewed By: #vdg, ngraham
Subscribers: yurchor, michaelweghorn, kde-doc-english, davidhurka, abetts, loh.tar, alexde, ngraham, okular-devel
Tags: #okular, #documentation
Differential Revision: https://phabricator.kde.org/D18744
2019-04-21 23:06:54 +00:00
if ( m_selectCurrentPage )
m_selectCurrentPage - > setEnabled ( true ) ;
2004-11-09 17:20:19 +00:00
} else {
m_gotoPage - > setEnabled ( false ) ;
2010-09-03 21:30:30 +00:00
m_beginningOfDocument - > setEnabled ( false ) ;
m_endOfDocument - > setEnabled ( false ) ;
2004-11-09 17:20:19 +00:00
m_prevPage - > setEnabled ( false ) ;
m_nextPage - > setEnabled ( false ) ;
2007-06-17 09:45:59 +00:00
if ( m_historyBack )
m_historyBack - > setEnabled ( false ) ;
if ( m_historyNext )
m_historyNext - > setEnabled ( false ) ;
2007-05-06 11:23:26 +00:00
m_reload - > setEnabled ( false ) ;
2011-10-12 19:36:01 +00:00
if ( m_copy )
m_copy - > setEnabled ( false ) ;
if ( m_selectAll )
m_selectAll - > setEnabled ( false ) ;
Add action in Edit menu to select the text on current page
BUG: 358868
Test Plan: Click on "Select All Text on Current Page" entry in Edit menu to select the entire page. The selected text can then be copied via Edit menu item "Copy"
Reviewers: aacid, #vdg, ngraham
Reviewed By: #vdg, ngraham
Subscribers: yurchor, michaelweghorn, kde-doc-english, davidhurka, abetts, loh.tar, alexde, ngraham, okular-devel
Tags: #okular, #documentation
Differential Revision: https://phabricator.kde.org/D18744
2019-04-21 23:06:54 +00:00
if ( m_selectCurrentPage )
m_selectCurrentPage - > setEnabled ( false ) ;
2004-11-09 17:20:19 +00:00
}
2020-07-10 22:15:05 +00:00
2011-10-23 09:17:04 +00:00
if ( factory ( ) ) {
2015-10-29 12:37:11 +00:00
QWidget * menu = factory ( ) - > container ( QStringLiteral ( " menu_okular_part_viewer " ) , this ) ;
2011-10-23 10:07:38 +00:00
if ( menu )
menu - > setEnabled ( opened ) ;
2015-10-29 12:37:11 +00:00
menu = factory ( ) - > container ( QStringLiteral ( " view_orientation " ) , this ) ;
2011-10-23 10:07:38 +00:00
if ( menu )
menu - > setEnabled ( opened ) ;
2011-10-23 09:17:04 +00:00
}
2011-10-31 21:41:50 +00:00
emit viewerMenuStateChange ( opened ) ;
2011-10-23 09:17:04 +00:00
2007-05-01 14:43:30 +00:00
updateBookmarksActions ( ) ;
}
void Part : : updateBookmarksActions ( )
{
bool opened = m_document - > pages ( ) > 0 ;
if ( opened ) {
m_addBookmark - > setEnabled ( true ) ;
2012-03-26 18:01:01 +00:00
if ( m_document - > bookmarkManager ( ) - > isBookmarked ( m_document - > viewport ( ) ) ) {
2007-05-01 14:43:30 +00:00
m_addBookmark - > setText ( i18n ( " Remove Bookmark " ) ) ;
2015-10-29 12:37:11 +00:00
m_addBookmark - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " edit-delete-bookmark " ) ) ) ;
2011-10-25 20:21:22 +00:00
m_renameBookmark - > setEnabled ( true ) ;
2007-05-01 14:43:30 +00:00
} else {
m_addBookmark - > setText ( m_addBookmarkText ) ;
2007-05-01 16:38:35 +00:00
m_addBookmark - > setIcon ( m_addBookmarkIcon ) ;
2011-10-25 20:21:22 +00:00
m_renameBookmark - > setEnabled ( false ) ;
2007-05-01 14:43:30 +00:00
}
} else {
m_addBookmark - > setEnabled ( false ) ;
m_addBookmark - > setText ( m_addBookmarkText ) ;
2007-05-01 16:38:35 +00:00
m_addBookmark - > setIcon ( m_addBookmarkIcon ) ;
2011-10-25 20:21:22 +00:00
m_renameBookmark - > setEnabled ( false ) ;
2007-05-01 14:43:30 +00:00
}
2003-09-14 21:49:26 +00:00
}
2003-09-14 20:46:38 +00:00
2004-09-23 21:49:00 +00:00
void Part : : enableTOC ( bool enable )
{
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
if ( ! enable ) {
m_tocEnabled = false ;
return ;
}
m_sidebar - > addItem ( m_toc , QIcon : : fromTheme ( QApplication : : isLeftToRight ( ) ? QStringLiteral ( " format-justify-left " ) : QStringLiteral ( " format-justify-right " ) ) , i18n ( " Contents " ) ) ;
m_tocEnabled = true ;
2013-09-30 21:17:35 +00:00
// If present, show the TOC when a document is opened
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
if ( m_sidebar - > currentItem ( ) ! = m_toc ) {
m_sidebar - > setCurrentItem ( m_toc ) ;
2013-09-27 13:31:44 +00:00
}
2004-09-23 21:49:00 +00:00
}
2008-02-05 17:36:04 +00:00
void Part : : slotRebuildBookmarkMenu ( )
{
rebuildBookmarkMenu ( ) ;
}
2007-01-13 00:33:50 +00:00
2015-05-27 13:56:56 +00:00
void Part : : enableLayers ( bool enable )
{
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
if ( ! enable ) {
return ;
}
m_sidebar - > addItem ( m_layers , QIcon : : fromTheme ( QStringLiteral ( " format-list-unordered " ) ) , i18n ( " Layers " ) ) ;
2015-05-27 13:56:56 +00:00
}
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
void Part : : enableSidebarSignaturesItem ( bool enable )
2019-01-05 22:30:25 +00:00
{
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
if ( ! enable ) {
return ;
}
m_sidebar - > addItem ( m_signaturePanel , QIcon : : fromTheme ( QStringLiteral ( " application-pkcs7-signature " ) ) , i18n ( " Signatures " ) ) ;
2019-01-05 22:30:25 +00:00
}
2007-03-17 22:58:41 +00:00
void Part : : slotShowFindBar ( )
{
m_findBar - > show ( ) ;
m_findBar - > focusAndSetCursor ( ) ;
2014-02-08 10:44:26 +00:00
m_closeFindBar - > setEnabled ( true ) ;
2007-03-17 22:58:41 +00:00
}
void Part : : slotHideFindBar ( )
{
2009-05-08 23:19:37 +00:00
if ( m_findBar - > maybeHide ( ) ) {
m_pageView - > setFocus ( ) ;
2014-02-08 10:44:26 +00:00
m_closeFindBar - > setEnabled ( false ) ;
2009-05-08 23:19:37 +00:00
}
2007-03-17 22:58:41 +00:00
}
2004-09-18 16:41:23 +00:00
// BEGIN go to page dialog
2016-07-15 18:08:34 +00:00
class GotoPageDialog : public QDialog
2003-09-14 20:46:38 +00:00
{
2016-10-29 14:32:24 +00:00
Q_OBJECT
2007-01-13 00:33:50 +00:00
public :
2016-07-15 18:08:34 +00:00
GotoPageDialog ( QWidget * p , int current , int max )
: QDialog ( p )
2020-07-10 22:15:05 +00:00
{
2016-07-15 18:08:34 +00:00
setWindowTitle ( i18n ( " Go to Page " ) ) ;
buttonBox = new QDialogButtonBox ( QDialogButtonBox : : Ok | QDialogButtonBox : : Cancel , this ) ;
connect ( buttonBox , & QDialogButtonBox : : accepted , this , & QDialog : : accept ) ;
connect ( buttonBox , & QDialogButtonBox : : rejected , this , & QDialog : : reject ) ;
2007-01-13 00:33:50 +00:00
QVBoxLayout * topLayout = new QVBoxLayout ( this ) ;
topLayout - > setContentsMargins ( 6 , 6 , 6 , 6 ) ;
QHBoxLayout * midLayout = new QHBoxLayout ( ) ;
2016-07-15 18:08:34 +00:00
spinbox = new QSpinBox ( this ) ;
2007-01-13 00:33:50 +00:00
spinbox - > setRange ( 1 , max ) ;
2016-07-15 18:08:34 +00:00
spinbox - > setValue ( current ) ;
spinbox - > setFocus ( ) ;
2020-07-10 22:15:05 +00:00
2015-10-29 12:37:11 +00:00
slider = new QSlider ( Qt : : Horizontal , this ) ;
2016-07-15 18:08:34 +00:00
slider - > setRange ( 1 , max ) ;
slider - > setValue ( current ) ;
slider - > setSingleStep ( 1 ) ;
slider - > setTickPosition ( QSlider : : TicksBelow ) ;
slider - > setTickInterval ( max / 10 ) ;
2007-01-13 00:33:50 +00:00
2016-07-15 18:08:34 +00:00
connect ( slider , & QSlider : : valueChanged , spinbox , & QSpinBox : : setValue ) ;
connect ( spinbox , static_cast < void ( QSpinBox : : * ) ( int ) > ( & QSpinBox : : valueChanged ) , slider , & QSlider : : setValue ) ;
2020-07-10 22:15:05 +00:00
2016-07-15 18:08:34 +00:00
QLabel * label = new QLabel ( i18n ( " &Page: " ) , this ) ;
label - > setBuddy ( spinbox ) ;
2007-01-13 00:33:50 +00:00
topLayout - > addWidget ( label ) ;
2016-07-15 18:08:34 +00:00
topLayout - > addLayout ( midLayout ) ;
midLayout - > addWidget ( slider ) ;
midLayout - > addWidget ( spinbox ) ;
2020-07-10 22:15:05 +00:00
2016-07-15 18:08:34 +00:00
// A little bit extra space
2007-01-13 00:33:50 +00:00
topLayout - > addStretch ( 10 ) ;
topLayout - > addWidget ( buttonBox ) ;
2016-07-15 18:08:34 +00:00
spinbox - > setFocus ( ) ;
2020-07-10 22:15:05 +00:00
}
2014-05-10 08:26:29 +00:00
int getPage ( ) const
2020-07-10 22:15:05 +00:00
{
2016-07-15 18:08:34 +00:00
return spinbox - > value ( ) ;
2020-07-10 22:15:05 +00:00
}
2007-01-13 00:33:50 +00:00
protected :
2016-07-15 18:08:34 +00:00
QSpinBox * spinbox ;
QSlider * slider ;
QDialogButtonBox * buttonBox ;
2004-09-09 13:25:40 +00:00
} ;
2004-09-18 16:41:23 +00:00
// END go to page dialog
2004-09-09 13:25:40 +00:00
void Part : : slotGoToPage ( )
{
2006-09-21 08:45:36 +00:00
GotoPageDialog pageDialog ( m_pageView , m_document - > currentPage ( ) + 1 , m_document - > pages ( ) ) ;
2004-11-09 17:20:19 +00:00
if ( pageDialog . exec ( ) = = QDialog : : Accepted )
2019-11-15 16:08:25 +00:00
m_document - > setViewportPage ( pageDialog . getPage ( ) - 1 , nullptr , true ) ;
2002-08-30 09:14:01 +00:00
}
2004-09-09 13:25:40 +00:00
void Part : : slotPreviousPage ( )
2003-09-14 20:23:01 +00:00
{
2006-05-14 16:28:53 +00:00
if ( m_document - > isOpened ( ) & & ! ( m_document - > currentPage ( ) < 1 ) )
2019-11-15 16:08:25 +00:00
m_document - > setViewportPage ( m_document - > currentPage ( ) - 1 , nullptr , true ) ;
2003-09-14 20:23:01 +00:00
}
2004-09-09 13:25:40 +00:00
void Part : : slotNextPage ( )
2003-09-14 20:23:01 +00:00
{
2005-11-04 11:59:51 +00:00
if ( m_document - > isOpened ( ) & & m_document - > currentPage ( ) < ( m_document - > pages ( ) - 1 ) )
2019-11-15 16:08:25 +00:00
m_document - > setViewportPage ( m_document - > currentPage ( ) + 1 , nullptr , true ) ;
2004-09-09 13:25:40 +00:00
}
2004-09-11 15:59:32 +00:00
void Part : : slotGotoFirst ( )
2004-09-09 13:25:40 +00:00
{
2010-09-03 21:30:30 +00:00
if ( m_document - > isOpened ( ) ) {
2019-11-15 16:08:25 +00:00
m_document - > setViewportPage ( 0 , nullptr , true ) ;
2010-09-03 21:30:30 +00:00
m_beginningOfDocument - > setEnabled ( false ) ;
}
2003-09-14 20:23:01 +00:00
}
2004-09-11 15:59:32 +00:00
void Part : : slotGotoLast ( )
2003-09-14 14:54:16 +00:00
{
2005-11-04 11:59:51 +00:00
if ( m_document - > isOpened ( ) ) {
2010-09-03 21:30:30 +00:00
DocumentViewport endPage ( m_document - > pages ( ) - 1 ) ;
endPage . rePos . enabled = true ;
endPage . rePos . normalizedX = 0 ;
endPage . rePos . normalizedY = 1 ;
endPage . rePos . pos = Okular : : DocumentViewport : : TopLeft ;
2019-11-15 16:08:25 +00:00
m_document - > setViewport ( endPage , nullptr , true ) ;
2010-09-03 21:30:30 +00:00
m_endOfDocument - > setEnabled ( false ) ;
}
2003-09-14 14:54:16 +00:00
}
2005-01-27 17:31:07 +00:00
void Part : : slotHistoryBack ( )
{
m_document - > setPrevViewport ( ) ;
}
void Part : : slotHistoryNext ( )
{
m_document - > setNextViewport ( ) ;
}
2007-05-01 14:43:30 +00:00
void Part : : slotAddBookmark ( )
{
2012-03-26 18:01:01 +00:00
DocumentViewport vp = m_document - > viewport ( ) ;
if ( m_document - > bookmarkManager ( ) - > isBookmarked ( vp ) ) {
m_document - > bookmarkManager ( ) - > removeBookmark ( vp ) ;
2007-05-01 14:43:30 +00:00
} else {
2012-03-26 18:01:01 +00:00
m_document - > bookmarkManager ( ) - > addBookmark ( vp ) ;
2007-05-01 14:43:30 +00:00
}
}
2012-03-26 18:01:01 +00:00
void Part : : slotRenameBookmark ( const DocumentViewport & viewport )
2011-10-25 20:21:22 +00:00
{
2012-03-26 18:01:01 +00:00
Q_ASSERT ( m_document - > bookmarkManager ( ) - > isBookmarked ( viewport ) ) ;
if ( m_document - > bookmarkManager ( ) - > isBookmarked ( viewport ) ) {
KBookmark bookmark = m_document - > bookmarkManager ( ) - > bookmark ( viewport ) ;
2014-09-28 10:44:33 +00:00
const QString newName = QInputDialog : : getText ( widget ( ) , i18n ( " Rename Bookmark " ) , i18n ( " Enter the new name of the bookmark: " ) , QLineEdit : : Normal , bookmark . fullText ( ) ) ;
2011-10-25 20:21:22 +00:00
if ( ! newName . isEmpty ( ) ) {
m_document - > bookmarkManager ( ) - > renameBookmark ( & bookmark , newName ) ;
}
}
}
2007-05-01 14:43:30 +00:00
2011-10-25 22:19:58 +00:00
void Part : : slotRenameBookmarkFromMenu ( )
{
QAction * action = dynamic_cast < QAction * > ( sender ( ) ) ;
Q_ASSERT ( action ) ;
if ( action ) {
2012-03-26 18:01:01 +00:00
DocumentViewport vp ( action - > data ( ) . toString ( ) ) ;
slotRenameBookmark ( vp ) ;
2011-10-25 22:19:58 +00:00
}
}
2017-09-16 19:55:55 +00:00
void Part : : slotRemoveBookmarkFromMenu ( )
{
QAction * action = dynamic_cast < QAction * > ( sender ( ) ) ;
Q_ASSERT ( action ) ;
if ( action ) {
DocumentViewport vp ( action - > data ( ) . toString ( ) ) ;
slotRemoveBookmark ( vp ) ;
}
}
void Part : : slotRemoveBookmark ( const DocumentViewport & viewport )
{
Q_ASSERT ( m_document - > bookmarkManager ( ) - > isBookmarked ( viewport ) ) ;
if ( m_document - > bookmarkManager ( ) - > isBookmarked ( viewport ) ) {
m_document - > bookmarkManager ( ) - > removeBookmark ( viewport ) ;
}
}
2012-03-26 18:01:01 +00:00
void Part : : slotRenameCurrentViewportBookmark ( )
2011-10-25 22:19:58 +00:00
{
2012-03-26 18:01:01 +00:00
slotRenameBookmark ( m_document - > viewport ( ) ) ;
2011-10-25 22:19:58 +00:00
}
2016-10-29 10:23:14 +00:00
bool Part : : aboutToShowContextMenu ( QMenu * /*menu*/ , QAction * action , QMenu * contextMenu )
2011-10-25 22:19:58 +00:00
{
KBookmarkAction * ba = dynamic_cast < KBookmarkAction * > ( action ) ;
2017-09-05 21:27:18 +00:00
if ( ba ! = nullptr ) {
2011-10-25 22:19:58 +00:00
QAction * separatorAction = contextMenu - > addSeparator ( ) ;
2015-10-29 12:37:11 +00:00
separatorAction - > setObjectName ( QStringLiteral ( " OkularPrivateRenameBookmarkActions " ) ) ;
2019-04-25 21:10:48 +00:00
QAction * renameAction = contextMenu - > addAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-rename " ) ) , i18n ( " Rename this Bookmark " ) , this , & Part : : slotRenameBookmarkFromMenu ) ;
2012-03-26 18:01:01 +00:00
renameAction - > setData ( ba - > property ( " htmlRef " ) . toString ( ) ) ;
2015-10-29 12:37:11 +00:00
renameAction - > setObjectName ( QStringLiteral ( " OkularPrivateRenameBookmarkActions " ) ) ;
2019-04-25 21:10:48 +00:00
QAction * deleteAction = contextMenu - > addAction ( QIcon : : fromTheme ( QStringLiteral ( " list-remove " ) ) , i18n ( " Remove this Bookmark " ) , this , & Part : : slotRemoveBookmarkFromMenu ) ;
2017-09-16 19:55:55 +00:00
deleteAction - > setData ( ba - > property ( " htmlRef " ) . toString ( ) ) ;
deleteAction - > setObjectName ( QStringLiteral ( " OkularPrivateRenameBookmarkActions " ) ) ;
2011-10-25 22:19:58 +00:00
}
2016-10-29 10:23:14 +00:00
return ba ;
2011-10-25 22:19:58 +00:00
}
2007-05-01 14:43:30 +00:00
2006-06-24 10:56:06 +00:00
void Part : : slotPreviousBookmark ( )
{
2012-03-26 18:01:01 +00:00
const KBookmark bookmark = m_document - > bookmarkManager ( ) - > previousBookmark ( m_document - > viewport ( ) ) ;
2006-06-24 10:56:06 +00:00
2012-03-26 18:01:01 +00:00
if ( ! bookmark . isNull ( ) ) {
2014-08-09 23:08:54 +00:00
DocumentViewport vp ( bookmark . url ( ) . fragment ( QUrl : : FullyDecoded ) ) ;
2019-11-15 16:08:25 +00:00
m_document - > setViewport ( vp , nullptr , true ) ;
2006-06-24 10:56:06 +00:00
}
}
void Part : : slotNextBookmark ( )
{
2012-03-26 18:01:01 +00:00
const KBookmark bookmark = m_document - > bookmarkManager ( ) - > nextBookmark ( m_document - > viewport ( ) ) ;
2006-06-24 10:56:06 +00:00
2012-03-26 18:01:01 +00:00
if ( ! bookmark . isNull ( ) ) {
2014-08-09 23:08:54 +00:00
DocumentViewport vp ( bookmark . url ( ) . fragment ( QUrl : : FullyDecoded ) ) ;
2019-11-15 16:08:25 +00:00
m_document - > setViewport ( vp , nullptr , true ) ;
2006-06-24 10:56:06 +00:00
}
}
2004-09-09 13:25:40 +00:00
void Part : : slotFind ( )
2003-09-14 14:54:16 +00:00
{
2007-03-17 22:58:41 +00:00
// when in presentation mode, there's already a search bar, taking care of
// the 'find' requests
2017-09-05 21:27:18 +00:00
if ( ( PresentationWidget * ) m_presentationWidget ! = nullptr ) {
2007-04-20 19:45:33 +00:00
m_presentationWidget - > slotFind ( ) ;
} else {
slotShowFindBar ( ) ;
}
2003-09-14 21:53:40 +00:00
}
2004-09-09 13:25:40 +00:00
void Part : : slotFindNext ( )
2003-09-14 21:53:40 +00:00
{
2007-03-17 22:58:41 +00:00
if ( m_findBar - > isHidden ( ) )
slotShowFindBar ( ) ;
else
m_findBar - > findNext ( ) ;
2003-09-14 14:22:37 +00:00
}
2009-02-14 17:11:29 +00:00
void Part : : slotFindPrev ( )
{
if ( m_findBar - > isHidden ( ) )
slotShowFindBar ( ) ;
else
m_findBar - > findPrev ( ) ;
}
2012-05-23 21:43:44 +00:00
bool Part : : saveFile ( )
{
2014-05-09 20:36:24 +00:00
if ( ! isModified ( ) )
return true ;
else
return saveAs ( url ( ) ) ;
2012-05-23 21:43:44 +00:00
}
2009-02-14 17:11:29 +00:00
2014-05-09 15:04:48 +00:00
bool Part : : slotSaveFileAs ( bool showOkularArchiveAsDefaultFormat )
2004-08-28 17:59:17 +00:00
{
2009-03-22 18:38:38 +00:00
if ( m_embedMode = = PrintPreviewMode )
2014-05-09 15:04:48 +00:00
return false ;
2007-06-05 20:49:00 +00:00
2014-05-09 15:04:48 +00:00
// Determine the document's mimetype
2017-09-10 09:51:56 +00:00
QMimeDatabase db ;
QMimeType originalMimeType ;
2014-09-08 12:58:55 +00:00
const QString typeName = m_document - > documentInfo ( ) . get ( DocumentInfo : : MimeType ) ;
if ( ! typeName . isEmpty ( ) )
2017-09-10 09:51:56 +00:00
originalMimeType = db . mimeTypeForName ( typeName ) ;
2012-06-13 13:33:49 +00:00
2014-09-11 12:31:46 +00:00
// What data would we lose if we saved natively?
bool wontSaveForms , wontSaveAnnotations ;
checkNativeSaveDataLoss ( & wontSaveForms , & wontSaveAnnotations ) ;
2012-06-13 13:33:49 +00:00
2017-11-13 17:12:34 +00:00
const QMimeType okularArchiveMimeType = db . mimeTypeForName ( QStringLiteral ( " application/vnd.kde.okular-archive " ) ) ;
2017-09-10 09:51:56 +00:00
// Prepare "Save As" dialog
const QString originalMimeTypeFilter = i18nc ( " File type name and pattern " , " %1 (%2) " , originalMimeType . comment ( ) , originalMimeType . globPatterns ( ) . join ( QLatin1Char ( ' ' ) ) ) ;
2017-11-13 17:12:34 +00:00
const QString okularArchiveMimeTypeFilter = i18nc ( " File type name and pattern " , " %1 (%2) " , okularArchiveMimeType . comment ( ) , okularArchiveMimeType . globPatterns ( ) . join ( QLatin1Char ( ' ' ) ) ) ;
2017-09-10 09:51:56 +00:00
2014-05-09 15:04:48 +00:00
// What format choice should we show as default?
2017-09-10 09:51:56 +00:00
QString selectedFilter = ( isDocumentArchive | | showOkularArchiveAsDefaultFormat | | wontSaveForms | | wontSaveAnnotations ) ? okularArchiveMimeTypeFilter : originalMimeTypeFilter ;
2012-06-13 13:33:49 +00:00
2017-09-10 09:51:56 +00:00
QString filter = originalMimeTypeFilter + QStringLiteral ( " ;; " ) + okularArchiveMimeTypeFilter ;
2014-05-09 15:04:48 +00:00
2017-09-10 09:51:56 +00:00
const QUrl saveUrl = QFileDialog : : getSaveFileUrl ( widget ( ) , i18n ( " Save As " ) , url ( ) , filter , & selectedFilter ) ;
2012-06-13 13:33:49 +00:00
2008-03-11 23:40:59 +00:00
if ( ! saveUrl . isValid ( ) | | saveUrl . isEmpty ( ) )
2014-05-09 15:04:48 +00:00
return false ;
2017-09-10 09:51:56 +00:00
// Has the user chosen to save in .okular archive format?
const bool saveAsOkularArchive = ( selectedFilter = = okularArchiveMimeTypeFilter ) ;
2008-03-11 23:40:59 +00:00
2017-09-10 09:51:56 +00:00
return saveAs ( saveUrl , saveAsOkularArchive ? SaveAsOkularArchive : NoSaveAsFlags ) ;
2014-05-09 15:04:48 +00:00
}
2008-03-11 23:40:59 +00:00
2017-09-10 09:51:56 +00:00
bool Part : : saveAs ( const QUrl & saveUrl )
2014-05-09 15:04:48 +00:00
{
// Save in the same format (.okular vs native) as the current file
2014-09-08 14:59:14 +00:00
return saveAs ( saveUrl , isDocumentArchive ? SaveAsOkularArchive : NoSaveAsFlags ) ;
2012-05-23 21:43:44 +00:00
}
2018-10-23 22:06:09 +00:00
static QUrl resolveSymlinksIfFileExists ( const QUrl & saveUrl )
{
if ( saveUrl . isLocalFile ( ) ) {
const QFileInfo fi ( saveUrl . toLocalFile ( ) ) ;
return fi . exists ( ) ? QUrl : : fromLocalFile ( fi . canonicalFilePath ( ) ) : saveUrl ;
} else {
return saveUrl ;
}
}
2017-09-10 09:51:56 +00:00
bool Part : : saveAs ( const QUrl & saveUrl , SaveAsFlags flags )
2012-05-23 21:43:44 +00:00
{
2017-11-17 13:19:12 +00:00
// 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
if ( m_fileLastModified ! = QFileInfo ( localFilePath ( ) ) . lastModified ( ) ) {
2018-08-31 09:23:45 +00:00
KMessageBox : : sorry ( widget ( ) , i18n ( " The file '%1' has been modified by another program, which means it can no longer be saved. " , url ( ) . fileName ( ) ) , i18n ( " File Changed " ) ) ;
2017-11-17 13:19:12 +00:00
return false ;
}
2017-10-26 16:58:34 +00:00
bool hasUserAcceptedReload = false ;
if ( m_documentOpenWithPassword ) {
const int res = KMessageBox : : warningYesNo (
widget ( ) ,
2017-11-13 09:37:35 +00:00
i18n ( " The current document is protected with a password.<br />In order to save, the file needs to be reloaded. You will be asked for the password again and your undo/redo history will be lost.<br />Do you want to continue? " ) ,
2017-10-26 16:58:34 +00:00
i18n ( " Save - Warning " ) ) ;
2020-07-10 22:15:05 +00:00
2017-10-26 16:58:34 +00:00
switch ( res ) {
case KMessageBox : : Yes :
hasUserAcceptedReload = true ;
// do nothing
break ;
case KMessageBox : : No : // User said no to continue, so return true even if save didn't happen otherwise we will get an error
return true ;
}
}
2017-10-26 17:11:44 +00:00
bool setModifiedAfterSave = false ;
2014-09-17 22:30:39 +00:00
QTemporaryFile tf ;
2009-09-13 21:11:37 +00:00
QString fileName ;
if ( ! tf . open ( ) ) {
KMessageBox : : information ( widget ( ) , i18n ( " Could not open the temporary file for saving. " ) ) ;
2012-05-23 21:43:44 +00:00
return false ;
2009-09-13 21:11:37 +00:00
}
fileName = tf . fileName ( ) ;
tf . close ( ) ;
2008-03-11 23:40:59 +00:00
2018-10-21 22:27:54 +00:00
// Figure out the real save url, for symlinks we don't want to copy over the symlink but over the target file
2018-10-23 22:06:09 +00:00
const QUrl realSaveUrl = resolveSymlinksIfFileExists ( saveUrl ) ;
2018-10-21 22:27:54 +00:00
2017-09-10 09:51:56 +00:00
QScopedPointer < QTemporaryFile > tempFile ;
2017-11-06 08:59:01 +00:00
KIO : : Job * copyJob = nullptr ; // this will be filled with the job that writes to saveUrl
2012-05-30 16:33:07 +00:00
2014-05-09 15:04:48 +00:00
// Does the user want a .okular archive?
2014-09-08 14:59:14 +00:00
if ( flags & SaveAsOkularArchive ) {
2017-10-30 10:11:08 +00:00
if ( ! hasUserAcceptedReload & & ! m_document - > canSwapBackingFile ( ) ) {
2017-11-15 09:08:20 +00:00
const int res = KMessageBox : : warningYesNo ( widget ( ) , i18n ( " After saving, the current document format requires the file to be reloaded. Your undo/redo history will be lost.<br />Do you want to continue? " ) , i18n ( " Save - Warning " ) ) ;
2020-07-10 22:15:05 +00:00
2017-10-26 16:58:34 +00:00
switch ( res ) {
case KMessageBox : : Yes :
// do nothing
break ;
case KMessageBox : : No : // User said no to continue, so return true even if save didn't happen otherwise we will get an error
return true ;
}
}
2014-05-09 15:04:48 +00:00
if ( ! m_document - > saveDocumentArchive ( fileName ) ) {
2009-10-19 23:00:52 +00:00
KMessageBox : : information ( widget ( ) , i18n ( " File could not be saved in '%1'. Try to save it to another location. " , fileName ) ) ;
2014-05-09 15:04:48 +00:00
return false ;
2009-10-19 23:00:52 +00:00
}
2014-05-09 15:04:48 +00:00
2018-10-21 22:27:54 +00:00
copyJob = KIO : : file_copy ( QUrl : : fromLocalFile ( fileName ) , realSaveUrl , - 1 , KIO : : Overwrite ) ;
2014-05-09 15:04:48 +00:00
} else {
2014-09-11 12:31:46 +00:00
bool wontSaveForms , wontSaveAnnotations ;
checkNativeSaveDataLoss ( & wontSaveForms , & wontSaveAnnotations ) ;
2012-05-23 21:43:44 +00:00
2014-05-09 15:04:48 +00:00
// If something can't be saved in this format, ask for confirmation
QStringList listOfwontSaves ;
if ( wontSaveForms )
listOfwontSaves < < i18n ( " Filled form contents " ) ;
if ( wontSaveAnnotations )
listOfwontSaves < < i18n ( " User annotations " ) ;
2017-10-30 10:11:08 +00:00
if ( ! listOfwontSaves . isEmpty ( ) ) {
2017-11-15 13:10:36 +00:00
if ( saveUrl = = url ( ) ) {
// Save
const QString warningMessage = i18n ( " You are about to save changes, but the current file format does not support saving the following elements. Please use the <i>Okular document archive</i> format to preserve them. " ) ;
const int result = KMessageBox : : warningYesNoList ( widget ( ) ,
warningMessage ,
listOfwontSaves ,
i18n ( " Warning " ) ,
2019-04-25 21:10:48 +00:00
KGuiItem ( i18n ( " Save as Okular document archive... " ) , QStringLiteral ( " document-save-as " ) ) , // <- KMessageBox::Yes
2017-11-15 13:10:36 +00:00
KStandardGuiItem : : cancel ( ) ) ;
2020-07-10 22:15:05 +00:00
2017-11-15 13:10:36 +00:00
switch ( result ) {
case KMessageBox : : Yes : // -> Save as Okular document archive
return slotSaveFileAs ( true /* showOkularArchiveAsDefaultFormat */ ) ;
default :
return false ;
}
} else {
// Save as
const QString warningMessage = m_document - > canSwapBackingFile ( ) ? i18n (
" You are about to save changes, but the current file format does not support saving the following elements. Please use the <i>Okular document "
" archive</i> format to preserve them. Click <i>Continue</i> to save the document and discard these elements. " )
: i18n (
" You are about to save changes, but the current file format does not support saving the following elements. Please use the <i>Okular document "
" archive</i> format to preserve them. Click <i>Continue</i> to save, but you will lose these elements as well as the undo/redo history. " ) ;
const QString continueMessage = m_document - > canSwapBackingFile ( ) ? i18n ( " Continue " ) : i18n ( " Continue losing changes " ) ;
const int result = KMessageBox : : warningYesNoCancelList ( widget ( ) ,
warningMessage ,
listOfwontSaves ,
i18n ( " Warning " ) ,
2019-04-25 21:10:48 +00:00
KGuiItem ( i18n ( " Save as Okular document archive... " ) , QStringLiteral ( " document-save-as " ) ) , // <- KMessageBox::Yes
KGuiItem ( continueMessage , QStringLiteral ( " arrow-right " ) ) ) ; // <- KMessageBox::NO
2020-07-10 22:15:05 +00:00
2017-11-15 13:10:36 +00:00
switch ( result ) {
case KMessageBox : : Yes : // -> Save as Okular document archive
return slotSaveFileAs ( true /* showOkularArchiveAsDefaultFormat */ ) ;
case KMessageBox : : No : // -> Continue
setModifiedAfterSave = m_document - > canSwapBackingFile ( ) ;
break ;
case KMessageBox : : Cancel :
return false ;
}
2014-05-09 15:04:48 +00:00
}
}
2008-03-11 23:40:59 +00:00
2014-05-09 15:04:48 +00:00
if ( m_document - > canSaveChanges ( ) ) {
// If the generator supports saving changes, save them
QString errorText ;
if ( ! m_document - > saveChanges ( fileName , & errorText ) ) {
if ( errorText . isEmpty ( ) )
KMessageBox : : information ( widget ( ) , i18n ( " File could not be saved in '%1'. Try to save it to another location. " , fileName ) ) ;
else
KMessageBox : : information ( widget ( ) , i18n ( " File could not be saved in '%1'. %2 " , fileName , errorText ) ) ;
2008-03-11 23:40:59 +00:00
2014-05-09 15:04:48 +00:00
return false ;
}
2018-10-21 22:27:54 +00:00
copyJob = KIO : : file_copy ( QUrl : : fromLocalFile ( fileName ) , realSaveUrl , - 1 , KIO : : Overwrite ) ;
2009-10-19 23:00:52 +00:00
} else {
2014-05-10 14:34:53 +00:00
// If the generators doesn't support saving changes, we will
// just copy the original file.
if ( isDocumentArchive ) {
// Special case: if the user is extracting the contents of a
// .okular archive back to the native format, we can't just copy
// the open file (which is a .okular). So let's ask to core to
// extract and give us the real file
if ( ! m_document - > extractArchivedFile ( fileName ) ) {
KMessageBox : : information ( widget ( ) , i18n ( " File could not be saved in '%1'. Try to save it to another location. " , fileName ) ) ;
return false ;
}
2018-10-21 22:27:54 +00:00
copyJob = KIO : : file_copy ( QUrl : : fromLocalFile ( fileName ) , realSaveUrl , - 1 , KIO : : Overwrite ) ;
2014-05-10 14:34:53 +00:00
} else {
// Otherwise just copy the open file.
// make use of the already downloaded (in case of remote URLs) file,
// no point in downloading that again
2017-09-10 09:51:56 +00:00
QUrl srcUrl = QUrl : : fromLocalFile ( localFilePath ( ) ) ;
2014-05-10 14:34:53 +00:00
// duh, our local file disappeared...
if ( ! QFile : : exists ( localFilePath ( ) ) ) {
if ( url ( ) . isLocalFile ( ) ) {
2008-06-07 21:08:41 +00:00
# ifdef OKULAR_KEEP_FILE_OPEN
2014-05-10 14:34:53 +00:00
// local file: try to get it back from the open handle on it
tempFile . reset ( m_keeper - > copyToTemporary ( ) ) ;
if ( tempFile )
srcUrl = KUrl : : fromPath ( tempFile - > fileName ( ) ) ;
2008-06-21 10:54:27 +00:00
# else
2014-05-10 14:34:53 +00:00
const QString msg = i18n ( " Okular cannot copy %1 to the specified location. \n \n The document does not exist anymore. " , localFilePath ( ) ) ;
KMessageBox : : sorry ( widget ( ) , msg ) ;
return false ;
2008-06-07 21:08:41 +00:00
# endif
2014-05-10 14:34:53 +00:00
} else {
// we still have the original remote URL of the document,
// so copy the document from there
srcUrl = url ( ) ;
}
}
if ( srcUrl ! = saveUrl ) {
2018-10-21 22:27:54 +00:00
copyJob = KIO : : file_copy ( srcUrl , realSaveUrl , - 1 , KIO : : Overwrite ) ;
2014-05-09 15:04:48 +00:00
} else {
2014-05-10 14:34:53 +00:00
// Don't do a real copy in this case, just update the timestamps
2018-10-21 22:27:54 +00:00
copyJob = KIO : : setModificationTime ( realSaveUrl , QDateTime : : currentDateTime ( ) ) ;
2014-05-09 15:04:48 +00:00
}
}
2009-10-19 23:00:52 +00:00
}
2008-03-11 23:40:59 +00:00
}
2009-09-13 21:11:37 +00:00
2014-05-11 08:53:56 +00:00
// Stop watching for changes while we write the new file (useful when
// overwriting)
if ( url ( ) . isLocalFile ( ) )
unsetFileToWatch ( ) ;
2016-07-11 21:37:13 +00:00
KJobWidgets : : setWindow ( copyJob , widget ( ) ) ;
if ( ! copyJob - > exec ( ) ) {
2017-09-10 09:51:56 +00:00
KMessageBox : : information ( widget ( ) , i18n ( " File could not be saved in '%1'. Error: '%2'. Try to save it to another location. " , saveUrl . toDisplayString ( ) , copyJob - > errorString ( ) ) ) ;
2014-05-11 08:53:56 +00:00
// Restore watcher
if ( url ( ) . isLocalFile ( ) )
setFileToWatch ( localFilePath ( ) ) ;
2012-05-23 21:43:44 +00:00
return false ;
}
2017-11-14 13:52:02 +00:00
m_document - > setHistoryClean ( true ) ;
2008-03-11 23:40:59 +00:00
2014-09-10 10:01:58 +00:00
if ( m_document - > isDocdataMigrationNeeded ( ) )
m_document - > docdataMigrationDone ( ) ;
2008-03-11 23:40:59 +00:00
2014-05-10 16:00:30 +00:00
bool reloadedCorrectly = true ;
2016-07-11 21:16:42 +00:00
2018-11-14 19:12:15 +00:00
// Make the generator use the new file instead of the old one
2017-10-26 16:58:34 +00:00
if ( m_document - > canSwapBackingFile ( ) & & ! m_documentOpenWithPassword ) {
2018-08-13 08:44:01 +00:00
QWidget * currentSidebarItem = m_sidebar - > currentItem ( ) ;
2017-10-25 13:05:31 +00:00
// this calls openFile internally, which in turn actually calls
// m_document->swapBackingFile() instead of the regular loadDocument
2017-10-26 17:11:44 +00:00
if ( openUrl ( saveUrl , true /* swapInsteadOfOpening */ ) ) {
if ( setModifiedAfterSave ) {
2017-11-14 13:52:02 +00:00
m_document - > setHistoryClean ( false ) ;
2008-06-07 21:08:41 +00:00
}
2017-10-26 17:11:44 +00:00
} else {
2017-10-25 13:05:31 +00:00
reloadedCorrectly = false ;
2017-10-26 17:11:44 +00:00
}
2018-08-13 08:44:01 +00:00
if ( m_sidebar - > currentItem ( ) ! = currentSidebarItem )
m_sidebar - > setCurrentItem ( currentSidebarItem ) ;
2017-10-25 13:05:31 +00:00
} else {
// If the generator doesn't support swapping file, then just reload
// the document from the new location
if ( ! slotAttemptReload ( true , saveUrl ) )
reloadedCorrectly = false ;
2014-05-09 22:53:39 +00:00
}
2014-05-11 08:53:56 +00:00
2014-05-10 16:00:30 +00:00
// In case of file swapping errors, close the document to avoid inconsistencies
if ( ! reloadedCorrectly ) {
2017-09-10 09:51:56 +00:00
qWarning ( ) < < " The document hasn't been reloaded/swapped correctly " ;
2014-05-10 16:00:30 +00:00
closeUrl ( ) ;
}
2014-05-11 08:53:56 +00:00
// Restore watcher
if ( url ( ) . isLocalFile ( ) )
setFileToWatch ( localFilePath ( ) ) ;
2018-04-23 20:52:28 +00:00
// Set correct permission taking into account the umask value
# ifndef Q_OS_WIN
const QString saveFilePath = saveUrl . toLocalFile ( ) ;
if ( QFile : : exists ( saveFilePath ) ) {
const mode_t mask = umask ( 0 ) ;
umask ( mask ) ;
const mode_t fileMode = 0666 & ~ mask ;
2018-04-24 17:38:08 +00:00
chmod ( QFile : : encodeName ( saveFilePath ) . constData ( ) , fileMode ) ;
2018-04-23 20:52:28 +00:00
}
# endif
2014-05-09 15:04:48 +00:00
return true ;
}
2007-01-13 00:33:50 +00:00
2014-09-11 12:31:46 +00:00
// If the user wants to save in the original file's format, some features might
// not be available. Find out what cannot be saved in this format
void Part : : checkNativeSaveDataLoss ( bool * out_wontSaveForms , bool * out_wontSaveAnnotations ) const
{
bool wontSaveForms = false ;
bool wontSaveAnnotations = false ;
if ( ! m_document - > canSaveChanges ( Document : : SaveFormsCapability ) ) {
/* Set wontSaveForms only if there are forms */
const int pagecount = m_document - > pages ( ) ;
for ( int pageno = 0 ; pageno < pagecount ; + + pageno ) {
const Okular : : Page * page = m_document - > page ( pageno ) ;
if ( ! page - > formFields ( ) . empty ( ) ) {
wontSaveForms = true ;
break ;
2008-06-07 21:08:41 +00:00
}
}
2014-09-11 12:31:46 +00:00
}
2008-06-07 21:08:41 +00:00
2014-09-11 12:31:46 +00:00
if ( ! m_document - > canSaveChanges ( Document : : SaveAnnotationsCapability ) ) {
/* Set wontSaveAnnotations only if there are local annotations */
const int pagecount = m_document - > pages ( ) ;
2008-06-07 21:08:41 +00:00
2014-09-11 12:31:46 +00:00
for ( int pageno = 0 ; pageno < pagecount ; + + pageno ) {
2019-12-12 22:48:27 +00:00
const QLinkedList < Okular : : Annotation * > annotations = m_document - > page ( pageno ) - > annotations ( ) ;
for ( const Okular : : Annotation * ann : annotations ) {
2014-09-11 12:31:46 +00:00
if ( ! ( ann - > flags ( ) & Okular : : Annotation : : External ) ) {
wontSaveAnnotations = true ;
break ;
}
}
if ( wontSaveAnnotations )
break ;
}
2004-11-05 01:52:48 +00:00
}
2004-04-15 18:36:43 +00:00
2014-09-11 12:31:46 +00:00
* out_wontSaveForms = wontSaveForms ;
* out_wontSaveAnnotations = wontSaveAnnotations ;
}
2007-01-13 00:33:50 +00:00
2005-04-16 00:25:26 +00:00
void Part : : slotGetNewStuff ( )
{
2009-12-26 16:23:36 +00:00
#if 0
2007-11-09 16:16:05 +00:00
KNS : : Engine engine ( widget ( ) ) ;
2007-07-19 22:27:45 +00:00
engine . init ( " okular.knsrc " ) ;
2005-04-16 00:25:26 +00:00
// show the modal dialog over pageview and execute it
2007-07-19 22:27:45 +00:00
KNS : : Entry : : List entries = engine . downloadDialogModal ( m_pageView ) ;
Q_UNUSED ( entries )
2009-12-26 16:23:36 +00:00
# endif
2005-04-16 00:25:26 +00:00
}
2004-10-27 14:15:27 +00:00
void Part : : slotPreferences ( )
2002-08-30 09:14:01 +00:00
{
2013-05-28 19:10:50 +00:00
// Create dialog
2011-10-12 19:36:01 +00:00
PreferencesDialog * dialog = new PreferencesDialog ( m_pageView , Okular : : Settings : : self ( ) , m_embedMode ) ;
2013-05-28 19:10:50 +00:00
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
// Show it
2004-10-27 14:15:27 +00:00
dialog - > show ( ) ;
}
2018-06-26 11:05:25 +00:00
void Part : : slotToggleChangeColors ( )
{
m_pageView - > slotToggleChangeColors ( ) ;
}
void Part : : slotSetChangeColors ( bool active )
{
m_pageView - > slotSetChangeColors ( active ) ;
}
2007-01-13 00:33:50 +00:00
2013-05-28 21:55:10 +00:00
void Part : : slotAnnotationPreferences ( )
{
// Create dialog
PreferencesDialog * dialog = new PreferencesDialog ( m_pageView , Okular : : Settings : : self ( ) , m_embedMode ) ;
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
// Show it
dialog - > switchToAnnotationsPage ( ) ;
dialog - > show ( ) ;
}
2004-10-27 14:15:27 +00:00
void Part : : slotNewConfig ( )
{
2008-04-13 13:15:15 +00:00
// Apply settings here. A good policy is to check whether the setting has
2004-10-29 13:33:51 +00:00
// changed before applying changes.
2005-03-12 15:39:04 +00:00
// Watch File
2011-09-10 17:15:52 +00:00
setWatchFileModeEnabled ( Okular : : Settings : : watchFile ( ) ) ;
2005-03-12 15:39:04 +00:00
2004-11-05 18:14:20 +00:00
// Main View (pageView)
2006-10-28 22:58:05 +00:00
m_pageView - > reparseConfig ( ) ;
2004-11-06 01:48:52 +00:00
2004-11-09 17:20:19 +00:00
// update document settings
m_document - > reparseConfig ( ) ;
2006-12-22 20:42:36 +00:00
// update TOC settings
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
if ( m_tocEnabled )
2006-12-22 20:42:36 +00:00
m_toc - > reparseConfig ( ) ;
2006-10-28 22:58:05 +00:00
// update ThumbnailList contents
2006-09-21 08:45:36 +00:00
if ( Okular : : Settings : : showLeftPanel ( ) & & ! m_thumbnailList - > isHidden ( ) )
2004-11-07 11:20:27 +00:00
m_thumbnailList - > updateWidgets ( ) ;
2009-11-19 17:26:41 +00:00
// update Reviews settings
Improve the sidebar's navigation and UX
Okular's sidebar vertical view chooser toolbar suffers from a few issues:
* It's a nonstandard UI not used for category choosers in other pieces of KDE software,
and not used in other FOSS document readers
* What is shown and what is hidden is simultaneously too configurable while still not
offering the desirable UI common to other programs (i.e. no visible category chooser,
but a sidebar capable of displaying thumbnails, table of contents, search results, etc.)
* With labels on it takes up quite a bit of horizontal space, while with labels off, the
categories are less than clear
* UX is kind of clunky with nonstandard behaviors (e.g. clicking on the current category
to hide that category's view while keeping the view chooser visible, showing mostly
disabled items)
* It's made with custom painting code, which reduces maintainability and introduces bugs
(e.g. https://bugs.kde.org/show_bug.cgi?id=408190)
This patch removes the vertical category chooser entirely and replaces it with a tabbed
view on the top of the sidebar itself. The tabs are icons-only and have large icons. A
button is added on the left side of the default toolbar to quickly hide or show the
sidebar. In order to make room for the new button, the Previous and Next buttons on the
toolbar are removed, as previous/next buttons are already present on the Page Bar on the
bottom of the window so there's no need to duplicate this functionality. This improves
the UX, fixes a variety of bugs, and deletes a lot of custom code of dubious long-term
maintainability.
![vokoscreenNG-2020-04-16_13-29-24](https://invent.kde.org/graphics/okular/uploads/a1f96a315b69282df51de9993b1befaf/vokoscreenNG-2020-04-16_13-29-24.webm)
BUG: 213508
BUG: 334441
BUG: 344599
BUG: 408190
CCBUG: 335189
FIXED-IN: 1.11.0
CHANGELOG: The sidebar can now be easily shown or hidden with a toolbar button, and the category chooser no longer takes up so much space
2020-05-27 13:37:42 +00:00
m_reviewsWidget - > reparseConfig ( ) ;
2011-08-09 15:59:49 +00:00
setWindowTitleFromDocument ( ) ;
2015-08-22 20:15:32 +00:00
if ( m_presentationDrawingActions ) {
m_presentationDrawingActions - > reparseConfig ( ) ;
if ( factory ( ) ) {
factory ( ) - > refreshActionProperties ( ) ;
}
}
2004-10-09 08:10:56 +00:00
}
2002-08-30 09:14:01 +00:00
2004-10-09 08:10:56 +00:00
void Part : : slotPrintPreview ( )
2002-09-02 21:56:00 +00:00
{
2004-11-09 17:20:19 +00:00
if ( m_document - > pages ( ) = = 0 )
return ;
2002-09-02 21:56:00 +00:00
2007-10-18 20:25:33 +00:00
QPrinter printer ;
2016-08-13 20:30:22 +00:00
QString tempFilePattern ;
2004-09-18 16:41:23 +00:00
2016-08-13 20:30:22 +00:00
if ( m_document - > printingSupport ( ) = = Okular : : Document : : PostscriptPrinting ) {
tempFilePattern = ( QDir : : tempPath ( ) + QLatin1String ( " /okular_XXXXXX.ps " ) ) ;
} else if ( m_document - > printingSupport ( ) = = Okular : : Document : : NativePrinting ) {
tempFilePattern = ( QDir : : tempPath ( ) + QLatin1String ( " /okular_XXXXXX.pdf " ) ) ;
2007-11-26 21:43:54 +00:00
} else {
2016-08-13 20:30:22 +00:00
return ;
}
// Generate a temp filename for Print to File, then release the file so generator can write to it
QTemporaryFile tf ( tempFilePattern ) ;
tf . setAutoRemove ( true ) ;
tf . open ( ) ;
printer . setOutputFileName ( tf . fileName ( ) ) ;
tf . close ( ) ;
setupPrint ( printer ) ;
doPrint ( printer ) ;
if ( QFile : : exists ( printer . outputFileName ( ) ) ) {
Okular : : FilePrinterPreview previewdlg ( printer . outputFileName ( ) , widget ( ) ) ;
previewdlg . exec ( ) ;
2006-11-01 22:24:57 +00:00
}
2002-09-02 21:56:00 +00:00
}
2020-02-20 17:45:46 +00:00
void Part : : slotShowTOCMenu ( const Okular : : DocumentViewport & vp , const QPoint point , const QString & title )
2017-03-23 00:22:08 +00:00
{
2018-08-26 11:56:37 +00:00
showMenu ( m_document - > page ( vp . pageNumber ) , point , title , vp , true ) ;
2017-03-23 00:22:08 +00:00
}
2007-01-13 00:33:50 +00:00
2020-02-20 17:45:46 +00:00
void Part : : slotShowMenu ( const Okular : : Page * page , const QPoint point )
2017-03-23 00:22:08 +00:00
{
showMenu ( page , point ) ;
}
2020-02-20 17:45:46 +00:00
void Part : : showMenu ( const Okular : : Page * page , const QPoint point , const QString & bookmarkTitle , const Okular : : DocumentViewport & vp , bool showTOCActions )
2004-12-04 23:23:18 +00:00
{
2009-03-22 18:38:38 +00:00
if ( m_embedMode = = PrintPreviewMode )
return ;
2007-06-05 20:49:00 +00:00
2007-01-13 00:33:50 +00:00
bool reallyShow = false ;
2013-12-29 18:09:50 +00:00
const bool currentPage = page & & page - > number ( ) = = m_document - > viewport ( ) . pageNumber ;
2007-01-13 00:33:50 +00:00
if ( ! m_actionsSearched ) {
// the quest for options_show_menubar
KActionCollection * ac ;
QAction * act ;
if ( factory ( ) ) {
2011-10-25 22:19:58 +00:00
const QList < KXMLGUIClient * > clients ( factory ( ) - > clients ( ) ) ;
2007-01-13 00:33:50 +00:00
for ( int i = 0 ; ( ! m_showMenuBarAction | | ! m_showFullScreenAction ) & & i < clients . size ( ) ; + + i ) {
ac = clients . at ( i ) - > actionCollection ( ) ;
// show_menubar
2015-10-29 12:37:11 +00:00
act = ac - > action ( QStringLiteral ( " options_show_menubar " ) ) ;
2007-01-13 00:33:50 +00:00
if ( act & & qobject_cast < KToggleAction * > ( act ) )
m_showMenuBarAction = qobject_cast < KToggleAction * > ( act ) ;
// fullscreen
2015-10-29 12:37:11 +00:00
act = ac - > action ( QStringLiteral ( " fullscreen " ) ) ;
2007-01-13 00:33:50 +00:00
if ( act & & qobject_cast < KToggleFullScreenAction * > ( act ) )
m_showFullScreenAction = qobject_cast < KToggleFullScreenAction * > ( act ) ;
}
2006-03-24 22:57:41 +00:00
}
2007-01-13 00:33:50 +00:00
m_actionsSearched = true ;
}
2014-08-13 10:45:40 +00:00
QMenu * popup = new QMenu ( widget ( ) ) ;
2018-08-26 11:56:37 +00:00
if ( showTOCActions ) {
popup - > addAction ( i18n ( " Expand whole section " ) , m_toc . data ( ) , & TOC : : expandRecursively ) ;
popup - > addAction ( i18n ( " Collapse whole section " ) , m_toc . data ( ) , & TOC : : collapseRecursively ) ;
popup - > addAction ( i18n ( " Expand all " ) , m_toc . data ( ) , & TOC : : expandAll ) ;
popup - > addAction ( i18n ( " Collapse all " ) , m_toc . data ( ) , & TOC : : collapseAll ) ;
reallyShow = true ;
}
2017-09-05 21:27:18 +00:00
QAction * addBookmark = nullptr ;
QAction * removeBookmark = nullptr ;
QAction * fitPageWidth = nullptr ;
2007-01-13 00:33:50 +00:00
if ( page ) {
2016-12-28 16:03:28 +00:00
popup - > addAction ( new OKMenuTitle ( popup , i18n ( " Page %1 " , page - > number ( ) + 1 ) ) ) ;
2013-12-29 18:09:50 +00:00
if ( ( ! currentPage & & m_document - > bookmarkManager ( ) - > isBookmarked ( page - > number ( ) ) ) | | ( currentPage & & m_document - > bookmarkManager ( ) - > isBookmarked ( m_document - > viewport ( ) ) ) )
2015-10-29 12:37:11 +00:00
removeBookmark = popup - > addAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-delete-bookmark " ) ) , i18n ( " Remove Bookmark " ) ) ;
2007-01-13 14:45:51 +00:00
else
2015-10-29 12:37:11 +00:00
addBookmark = popup - > addAction ( QIcon : : fromTheme ( QStringLiteral ( " bookmark-new " ) ) , i18n ( " Add Bookmark " ) ) ;
2007-01-13 00:33:50 +00:00
if ( m_pageView - > canFitPageWidth ( ) )
2015-10-29 12:37:11 +00:00
fitPageWidth = popup - > addAction ( QIcon : : fromTheme ( QStringLiteral ( " zoom-fit-best " ) ) , i18n ( " Fit Width " ) ) ;
2007-01-13 00:33:50 +00:00
popup - > addAction ( m_prevBookmark ) ;
popup - > addAction ( m_nextBookmark ) ;
reallyShow = true ;
}
2016-07-21 21:05:54 +00:00
2007-01-13 00:33:50 +00:00
if ( ( m_showMenuBarAction & & ! m_showMenuBarAction - > isChecked ( ) ) | | ( m_showFullScreenAction & & m_showFullScreenAction - > isChecked ( ) ) ) {
2016-12-28 16:03:28 +00:00
popup - > addAction ( new OKMenuTitle ( popup , i18n ( " Tools " ) ) ) ;
2007-01-13 00:33:50 +00:00
if ( m_showMenuBarAction & & ! m_showMenuBarAction - > isChecked ( ) )
popup - > addAction ( m_showMenuBarAction ) ;
if ( m_showFullScreenAction & & m_showFullScreenAction - > isChecked ( ) )
popup - > addAction ( m_showFullScreenAction ) ;
reallyShow = true ;
}
if ( reallyShow ) {
QAction * res = popup - > exec ( point ) ;
if ( res ) {
2013-12-29 18:09:50 +00:00
if ( res = = addBookmark ) {
2017-03-23 00:22:08 +00:00
if ( currentPage & & bookmarkTitle . isEmpty ( ) )
2013-12-29 18:09:50 +00:00
m_document - > bookmarkManager ( ) - > addBookmark ( m_document - > viewport ( ) ) ;
2017-03-23 00:22:08 +00:00
else if ( ! bookmarkTitle . isEmpty ( ) )
m_document - > bookmarkManager ( ) - > addBookmark ( m_document - > currentDocument ( ) , vp , bookmarkTitle ) ;
2013-12-29 18:09:50 +00:00
else
m_document - > bookmarkManager ( ) - > addBookmark ( page - > number ( ) ) ;
} else if ( res = = removeBookmark ) {
if ( currentPage )
m_document - > bookmarkManager ( ) - > removeBookmark ( m_document - > viewport ( ) ) ;
else
m_document - > bookmarkManager ( ) - > removeBookmark ( page - > number ( ) ) ;
} else if ( res = = fitPageWidth ) {
m_pageView - > fitPageWidth ( page - > number ( ) ) ;
}
2007-01-13 00:33:50 +00:00
}
}
delete popup ;
2004-12-04 23:23:18 +00:00
}
2004-12-05 22:47:32 +00:00
void Part : : slotShowProperties ( )
{
2007-01-13 00:33:50 +00:00
PropertiesDialog * d = new PropertiesDialog ( widget ( ) , m_document ) ;
2017-11-07 18:28:13 +00:00
connect ( d , & QDialog : : finished , d , & QObject : : deleteLater ) ;
d - > open ( ) ;
2004-12-05 22:47:32 +00:00
}
2006-05-28 16:54:54 +00:00
void Part : : slotShowEmbeddedFiles ( )
{
2007-01-13 00:33:50 +00:00
EmbeddedFilesDialog * d = new EmbeddedFilesDialog ( widget ( ) , m_document ) ;
2017-11-07 18:28:13 +00:00
connect ( d , & QDialog : : finished , d , & QObject : : deleteLater ) ;
d - > open ( ) ;
2006-05-28 16:54:54 +00:00
}
2004-12-17 17:14:46 +00:00
void Part : : slotShowPresentation ( )
{
2005-06-13 16:55:57 +00:00
if ( ! m_presentationWidget ) {
2015-08-22 20:15:32 +00:00
m_presentationWidget = new PresentationWidget ( widget ( ) , m_document , m_presentationDrawingActions , actionCollection ( ) ) ;
2006-06-25 16:34:11 +00:00
}
2004-12-17 17:14:46 +00:00
}
2005-04-07 09:53:15 +00:00
void Part : : slotHidePresentation ( )
{
if ( m_presentationWidget )
delete ( PresentationWidget * ) m_presentationWidget ;
}
2007-08-26 14:40:29 +00:00
void Part : : slotTogglePresentation ( )
{
if ( m_document - > isOpened ( ) ) {
if ( ! m_presentationWidget )
2015-08-22 20:15:32 +00:00
m_presentationWidget = new PresentationWidget ( widget ( ) , m_document , m_presentationDrawingActions , actionCollection ( ) ) ;
2007-08-26 14:40:29 +00:00
else
delete ( PresentationWidget * ) m_presentationWidget ;
}
}
2008-09-22 22:18:07 +00:00
void Part : : reload ( )
{
if ( m_document - > isOpened ( ) ) {
slotReload ( ) ;
}
}
2013-03-11 21:52:25 +00:00
void Part : : enableStartWithPrint ( )
{
m_cliPrint = true ;
}
2008-09-22 22:18:07 +00:00
2018-03-03 16:21:15 +00:00
void Part : : enableExitAfterPrint ( )
{
m_cliPrintAndExit = true ;
}
2020-09-24 13:31:49 +00:00
static const char * kKPlugin = " KPlugin " ;
2007-03-07 18:15:00 +00:00
void Part : : slotAboutBackend ( )
{
2015-12-08 16:22:33 +00:00
const KPluginMetaData data = m_document - > generatorInfo ( ) ;
if ( ! data . isValid ( ) )
return ;
2014-08-10 12:42:51 +00:00
2020-09-24 13:31:49 +00:00
// Here we do a bit of magic because KPluginMetaData doesn't have setters
// so we get the json info from it, modify it and use that for the KAboutPluginDialog
// in case the internals of KPluginMetaData change it won't be too bad, at most we're
// missing the icon or the generator extra description
QJsonObject rawData = data . rawData ( ) ;
const QIcon icon = QIcon : : fromTheme ( data . iconName ( ) ) ;
2016-07-24 16:35:44 +00:00
// fall back to mime type icon
if ( icon . isNull ( ) ) {
2015-12-08 16:22:33 +00:00
const Okular : : DocumentInfo documentInfo = m_document - > documentInfo ( QSet < DocumentInfo : : Key > ( ) < < DocumentInfo : : MimeType ) ;
const QString mimeTypeName = documentInfo . get ( DocumentInfo : : MimeType ) ;
2016-07-24 16:35:44 +00:00
if ( ! mimeTypeName . isEmpty ( ) ) {
2015-12-08 16:22:33 +00:00
QMimeDatabase db ;
QMimeType type = db . mimeTypeForName ( mimeTypeName ) ;
2016-07-24 16:35:44 +00:00
if ( type . isValid ( ) ) {
2020-09-24 13:31:49 +00:00
QJsonObject kplugin = rawData [ kKPlugin ] . toObject ( ) ;
kplugin [ QStringLiteral ( " Icon " ) ] = type . iconName ( ) ;
rawData [ kKPlugin ] = kplugin ;
2016-07-24 16:35:44 +00:00
}
2015-12-08 16:22:33 +00:00
}
}
2016-07-24 16:35:44 +00:00
2018-12-18 23:41:37 +00:00
const QString extraDescription = m_document - > metaData ( QStringLiteral ( " GeneratorExtraDescription " ) ) . toString ( ) ;
2020-09-24 13:31:49 +00:00
if ( ! extraDescription . isEmpty ( ) ) {
const QString descriptionAndLang = QStringLiteral ( " Description[%1] " ) . arg ( QLocale ( ) . name ( ) ) ;
QJsonObject kplugin = rawData [ kKPlugin ] . toObject ( ) ;
kplugin [ descriptionAndLang ] = QStringLiteral ( " %1 \n \n %2 " ) . arg ( data . description ( ) , extraDescription ) ;
rawData [ kKPlugin ] = kplugin ;
2016-07-24 16:35:44 +00:00
}
2020-09-24 13:31:49 +00:00
KAboutPluginDialog dlg ( KPluginMetaData ( rawData , data . fileName ( ) ) , widget ( ) ) ;
2015-12-08 16:22:33 +00:00
dlg . exec ( ) ;
2007-03-07 18:15:00 +00:00
}
2006-07-01 22:17:53 +00:00
void Part : : slotExportAs ( QAction * act )
{
QList < QAction * > acts = m_exportAs - > menu ( ) ? m_exportAs - > menu ( ) - > actions ( ) : QList < QAction * > ( ) ;
int id = acts . indexOf ( act ) ;
if ( ( id < 0 ) | | ( id > = acts . count ( ) ) )
return ;
2016-07-11 21:16:42 +00:00
QMimeDatabase mimeDatabase ;
QMimeType mimeType ;
2008-11-16 01:23:31 +00:00
switch ( id ) {
case 0 :
2016-07-11 21:16:42 +00:00
mimeType = mimeDatabase . mimeTypeForName ( QStringLiteral ( " text/plain " ) ) ;
2008-11-16 01:23:31 +00:00
break ;
default :
2018-01-22 23:37:44 +00:00
mimeType = m_exportFormats . at ( id - 1 ) . mimeType ( ) ;
2008-11-16 01:23:31 +00:00
break ;
}
2016-07-11 21:16:42 +00:00
QString filter = i18nc ( " File type name and pattern " , " %1 (%2) " , mimeType . comment ( ) , mimeType . globPatterns ( ) . join ( QLatin1Char ( ' ' ) ) ) ;
QString fileName = QFileDialog : : getSaveFileName ( widget ( ) , QString ( ) , QString ( ) , filter ) ;
2006-07-01 22:17:53 +00:00
if ( ! fileName . isEmpty ( ) ) {
2008-11-16 01:23:31 +00:00
bool saved = false ;
switch ( id ) {
case 0 :
saved = m_document - > exportToText ( fileName ) ;
break ;
default :
2014-05-09 15:40:14 +00:00
saved = m_document - > exportTo ( fileName , m_exportFormats . at ( id - 1 ) ) ;
2008-11-16 01:23:31 +00:00
break ;
}
2006-07-01 22:17:53 +00:00
if ( ! saved )
KMessageBox : : information ( widget ( ) , i18n ( " File could not be saved in '%1'. Try to save it to another location. " , fileName ) ) ;
}
}
2007-05-06 11:23:26 +00:00
void Part : : slotReload ( )
{
// stop the dirty handler timer, otherwise we may conflict with the
// auto-refresh system
m_dirtyHandler - > stop ( ) ;
2014-05-11 08:53:56 +00:00
slotAttemptReload ( ) ;
2007-05-06 11:23:26 +00:00
}
2004-10-09 08:10:56 +00:00
void Part : : slotPrint ( )
2004-01-02 17:46:06 +00:00
{
2004-11-09 17:20:19 +00:00
if ( m_document - > pages ( ) = = 0 )
return ;
2004-11-03 21:37:21 +00:00
2014-10-06 18:02:48 +00:00
# ifdef Q_OS_WIN
2011-08-22 20:56:56 +00:00
QPrinter printer ( QPrinter : : HighResolution ) ;
2011-08-23 19:47:37 +00:00
# else
QPrinter printer ;
# endif
2017-09-05 21:27:18 +00:00
QPrintDialog * printDialog = nullptr ;
QWidget * printConfigWidget = nullptr ;
2004-11-03 21:37:21 +00:00
2007-11-26 21:43:54 +00:00
// Must do certain QPrinter setup before creating QPrintDialog
setupPrint ( printer ) ;
2007-10-15 23:01:27 +00:00
2007-11-26 21:43:54 +00:00
// Create the Print Dialog with extra config widgets if required
if ( m_document - > canConfigurePrinter ( ) ) {
printConfigWidget = m_document - > printConfigurationWidget ( ) ;
Add option to ignore print margins for non-PDF generators
Summary:
This adds a combobox in the print dialog of the non-PDF
generators to allow selecting whether or not to take
print margins into account.
For the PDF case and rasterized printing, new print otions have
been implemented in commit 2e97d587508dff08aaf86ff149c8ed6b7658950d
already, which adds an additional option to do no scaling at all.
For consistency reasons, the same terms also used for the PDF
case are used in the combobox (i.e. the two of the three that
apply).
This adds a new abstract class 'PrintOptionsWidget' with a
'ignorePrintMargins()' method to indicate whether print margins
should be ignored or not, and a default implementation.
The existing widget for the PDF generator now derives from this
class.
In order to avoid an ABI breakage, the return value of
'Document::printConfigurationWidget' is left as a 'QWidget *'
and a dynamic_cast is done on use.
FilePrinter is adapted to take into account the value set by
'QPrinter::setFullPage()' and the margin options
are now passed accordingly (either the values set in the dialog or '0').
A big thanks to Albert Astals Cid <aacid@kde.org> for showing how
to extend the initial implementation to cover more generators.
Test Plan:
1) Open a PostScript file in Okular (using a document size that matches
a paper size available on the printer used later makes it easier
to see things behave as expected)
2) open print dialog, go to "Print options" and notice that there is a new
"Scale mode" combobox whose value is set to "Fit to printable area"
by default.
3) don't change any options, print to a printer that has hardware margins
Expected result: the document is scaled to the printable area (e.g.
scaled down so that the printer's hardware margins remain empty) as it
has been without this change.
4) Set the value of the "Print Options" -> "Scale mode" combobox to
"Fit to full page" and print again
Expected result: The document is scaled to the full page size, i.e. ignoring
the printer's hardware margins.
5) Try steps 1-4 with other document formats supported by Okular and
observe that they behave the same (except for the PDF case, where
there's a combobox with three options that has been implemented
independent of this change).
Reviewers: #okular, ngraham
Reviewed By: ngraham
Subscribers: fvogt, rkflx, arthurpeters, ltoscano, okular-devel, aacid, ngraham
Tags: #okular
Differential Revision: https://phabricator.kde.org/D10974
2019-04-03 13:58:21 +00:00
} else {
printConfigWidget = new DefaultPrintOptionsWidget ( ) ;
}
2016-07-15 19:05:38 +00:00
printDialog = new QPrintDialog ( & printer , widget ( ) ) ;
printDialog - > setWindowTitle ( i18nc ( " @title:window " , " Print " ) ) ;
QList < QWidget * > options ;
if ( printConfigWidget ) {
options < < printConfigWidget ;
2007-11-26 21:43:54 +00:00
}
Add option to ignore print margins for non-PDF generators
Summary:
This adds a combobox in the print dialog of the non-PDF
generators to allow selecting whether or not to take
print margins into account.
For the PDF case and rasterized printing, new print otions have
been implemented in commit 2e97d587508dff08aaf86ff149c8ed6b7658950d
already, which adds an additional option to do no scaling at all.
For consistency reasons, the same terms also used for the PDF
case are used in the combobox (i.e. the two of the three that
apply).
This adds a new abstract class 'PrintOptionsWidget' with a
'ignorePrintMargins()' method to indicate whether print margins
should be ignored or not, and a default implementation.
The existing widget for the PDF generator now derives from this
class.
In order to avoid an ABI breakage, the return value of
'Document::printConfigurationWidget' is left as a 'QWidget *'
and a dynamic_cast is done on use.
FilePrinter is adapted to take into account the value set by
'QPrinter::setFullPage()' and the margin options
are now passed accordingly (either the values set in the dialog or '0').
A big thanks to Albert Astals Cid <aacid@kde.org> for showing how
to extend the initial implementation to cover more generators.
Test Plan:
1) Open a PostScript file in Okular (using a document size that matches
a paper size available on the printer used later makes it easier
to see things behave as expected)
2) open print dialog, go to "Print options" and notice that there is a new
"Scale mode" combobox whose value is set to "Fit to printable area"
by default.
3) don't change any options, print to a printer that has hardware margins
Expected result: the document is scaled to the printable area (e.g.
scaled down so that the printer's hardware margins remain empty) as it
has been without this change.
4) Set the value of the "Print Options" -> "Scale mode" combobox to
"Fit to full page" and print again
Expected result: The document is scaled to the full page size, i.e. ignoring
the printer's hardware margins.
5) Try steps 1-4 with other document formats supported by Okular and
observe that they behave the same (except for the PDF case, where
there's a combobox with three options that has been implemented
independent of this change).
Reviewers: #okular, ngraham
Reviewed By: ngraham
Subscribers: fvogt, rkflx, arthurpeters, ltoscano, okular-devel, aacid, ngraham
Tags: #okular
Differential Revision: https://phabricator.kde.org/D10974
2019-04-03 13:58:21 +00:00
printDialog - > setOptionTabs ( options ) ;
2007-11-26 21:43:54 +00:00
if ( printDialog ) {
// Set the available Print Range
printDialog - > setMinMax ( 1 , m_document - > pages ( ) ) ;
printDialog - > setFromTo ( 1 , m_document - > pages ( ) ) ;
// If the user has bookmarked pages for printing, then enable Selection
if ( ! m_document - > bookmarkedPageRange ( ) . isEmpty ( ) ) {
printDialog - > addEnabledOption ( QAbstractPrintDialog : : PrintSelection ) ;
}
2004-11-03 21:37:21 +00:00
2007-11-26 21:43:54 +00:00
// If the Document type doesn't support print to both PS & PDF then disable the Print Dialog option
if ( printDialog - > isOptionEnabled ( QAbstractPrintDialog : : PrintToFile ) & & ! m_document - > supportsPrintToFile ( ) ) {
printDialog - > setEnabledOptions ( printDialog - > enabledOptions ( ) ^ QAbstractPrintDialog : : PrintToFile ) ;
}
2010-06-04 08:25:25 +00:00
// Enable the Current Page option in the dialog.
if ( m_document - > pages ( ) > 1 & & currentPage ( ) > 0 ) {
printDialog - > setOption ( QAbstractPrintDialog : : PrintCurrentPage ) ;
}
2018-03-03 16:21:15 +00:00
bool success = true ;
2007-11-26 21:43:54 +00:00
if ( printDialog - > exec ( ) ) {
Add option to ignore print margins for non-PDF generators
Summary:
This adds a combobox in the print dialog of the non-PDF
generators to allow selecting whether or not to take
print margins into account.
For the PDF case and rasterized printing, new print otions have
been implemented in commit 2e97d587508dff08aaf86ff149c8ed6b7658950d
already, which adds an additional option to do no scaling at all.
For consistency reasons, the same terms also used for the PDF
case are used in the combobox (i.e. the two of the three that
apply).
This adds a new abstract class 'PrintOptionsWidget' with a
'ignorePrintMargins()' method to indicate whether print margins
should be ignored or not, and a default implementation.
The existing widget for the PDF generator now derives from this
class.
In order to avoid an ABI breakage, the return value of
'Document::printConfigurationWidget' is left as a 'QWidget *'
and a dynamic_cast is done on use.
FilePrinter is adapted to take into account the value set by
'QPrinter::setFullPage()' and the margin options
are now passed accordingly (either the values set in the dialog or '0').
A big thanks to Albert Astals Cid <aacid@kde.org> for showing how
to extend the initial implementation to cover more generators.
Test Plan:
1) Open a PostScript file in Okular (using a document size that matches
a paper size available on the printer used later makes it easier
to see things behave as expected)
2) open print dialog, go to "Print options" and notice that there is a new
"Scale mode" combobox whose value is set to "Fit to printable area"
by default.
3) don't change any options, print to a printer that has hardware margins
Expected result: the document is scaled to the printable area (e.g.
scaled down so that the printer's hardware margins remain empty) as it
has been without this change.
4) Set the value of the "Print Options" -> "Scale mode" combobox to
"Fit to full page" and print again
Expected result: The document is scaled to the full page size, i.e. ignoring
the printer's hardware margins.
5) Try steps 1-4 with other document formats supported by Okular and
observe that they behave the same (except for the PDF case, where
there's a combobox with three options that has been implemented
independent of this change).
Reviewers: #okular, ngraham
Reviewed By: ngraham
Subscribers: fvogt, rkflx, arthurpeters, ltoscano, okular-devel, aacid, ngraham
Tags: #okular
Differential Revision: https://phabricator.kde.org/D10974
2019-04-03 13:58:21 +00:00
// set option for margins if widget is of corresponding type that holds this information
PrintOptionsWidget * optionWidget = dynamic_cast < PrintOptionsWidget * > ( printConfigWidget ) ;
if ( optionWidget ! = nullptr )
printer . setFullPage ( optionWidget - > ignorePrintMargins ( ) ) ;
else {
// printConfigurationWidget() method should always return an object of type Okular::PrintOptionsWidget,
// (signature does not (yet) require it for ABI stability reasons), so emit a warning if the object is of another type
qWarning ( ) < < " printConfigurationWidget() method did not return an Okular::PrintOptionsWidget. This is strongly discouraged! " ;
}
2018-03-03 16:21:15 +00:00
success = doPrint ( printer ) ;
Add option to ignore print margins for non-PDF generators
Summary:
This adds a combobox in the print dialog of the non-PDF
generators to allow selecting whether or not to take
print margins into account.
For the PDF case and rasterized printing, new print otions have
been implemented in commit 2e97d587508dff08aaf86ff149c8ed6b7658950d
already, which adds an additional option to do no scaling at all.
For consistency reasons, the same terms also used for the PDF
case are used in the combobox (i.e. the two of the three that
apply).
This adds a new abstract class 'PrintOptionsWidget' with a
'ignorePrintMargins()' method to indicate whether print margins
should be ignored or not, and a default implementation.
The existing widget for the PDF generator now derives from this
class.
In order to avoid an ABI breakage, the return value of
'Document::printConfigurationWidget' is left as a 'QWidget *'
and a dynamic_cast is done on use.
FilePrinter is adapted to take into account the value set by
'QPrinter::setFullPage()' and the margin options
are now passed accordingly (either the values set in the dialog or '0').
A big thanks to Albert Astals Cid <aacid@kde.org> for showing how
to extend the initial implementation to cover more generators.
Test Plan:
1) Open a PostScript file in Okular (using a document size that matches
a paper size available on the printer used later makes it easier
to see things behave as expected)
2) open print dialog, go to "Print options" and notice that there is a new
"Scale mode" combobox whose value is set to "Fit to printable area"
by default.
3) don't change any options, print to a printer that has hardware margins
Expected result: the document is scaled to the printable area (e.g.
scaled down so that the printer's hardware margins remain empty) as it
has been without this change.
4) Set the value of the "Print Options" -> "Scale mode" combobox to
"Fit to full page" and print again
Expected result: The document is scaled to the full page size, i.e. ignoring
the printer's hardware margins.
5) Try steps 1-4 with other document formats supported by Okular and
observe that they behave the same (except for the PDF case, where
there's a combobox with three options that has been implemented
independent of this change).
Reviewers: #okular, ngraham
Reviewed By: ngraham
Subscribers: fvogt, rkflx, arthurpeters, ltoscano, okular-devel, aacid, ngraham
Tags: #okular
Differential Revision: https://phabricator.kde.org/D10974
2019-04-03 13:58:21 +00:00
}
2008-07-13 09:51:04 +00:00
delete printDialog ;
2018-03-03 16:21:15 +00:00
if ( m_cliPrintAndExit )
exit ( success ? EXIT_SUCCESS : EXIT_FAILURE ) ;
2007-11-26 21:43:54 +00:00
}
}
void Part : : setupPrint ( QPrinter & printer )
{
2011-06-05 22:40:22 +00:00
printer . setOrientation ( m_document - > orientation ( ) ) ;
2004-11-03 21:37:21 +00:00
2007-03-04 23:19:43 +00:00
// title
2015-10-29 12:37:11 +00:00
QString title = m_document - > metaData ( QStringLiteral ( " DocumentTitle " ) ) . toString ( ) ;
2007-03-04 23:19:43 +00:00
if ( title . isEmpty ( ) ) {
title = m_document - > currentDocument ( ) . fileName ( ) ;
}
if ( ! title . isEmpty ( ) ) {
printer . setDocName ( title ) ;
}
2004-01-02 17:46:06 +00:00
}
2018-03-03 16:21:15 +00:00
bool Part : : doPrint ( QPrinter & printer )
2004-01-02 17:46:06 +00:00
{
2007-01-02 22:37:55 +00:00
if ( ! m_document - > isAllowed ( Okular : : AllowPrint ) ) {
2004-11-03 21:37:21 +00:00
KMessageBox : : error ( widget ( ) , i18n ( " Printing this document is not allowed. " ) ) ;
2018-03-03 16:21:15 +00:00
return false ;
2004-11-03 21:37:21 +00:00
}
2004-11-09 17:20:19 +00:00
if ( ! m_document - > print ( printer ) ) {
2010-04-14 23:07:27 +00:00
const QString error = m_document - > printError ( ) ;
if ( error . isEmpty ( ) ) {
KMessageBox : : error ( widget ( ) , i18n ( " Could not print the document. Unknown error. Please report to bugs.kde.org " ) ) ;
} else {
2010-04-16 21:21:40 +00:00
KMessageBox : : error ( widget ( ) , i18n ( " Could not print the document. Detailed error is \" %1 \" . Please report to bugs.kde.org " , error ) ) ;
2010-04-14 23:07:27 +00:00
}
2018-03-03 16:21:15 +00:00
return false ;
2004-11-03 21:37:21 +00:00
}
2018-03-03 16:21:15 +00:00
return true ;
2004-01-02 17:46:06 +00:00
}
2007-03-27 00:00:41 +00:00
void Part : : psTransformEnded ( int exit , QProcess : : ExitStatus status )
2005-07-15 18:20:57 +00:00
{
2007-03-27 00:00:41 +00:00
Q_UNUSED ( exit )
if ( status ! = QProcess : : NormalExit )
return ;
2020-09-13 09:20:09 +00:00
QProcess * senderobj = sender ( ) ? qobject_cast < QProcess * > ( sender ( ) ) : nullptr ;
2007-03-27 00:00:41 +00:00
if ( senderobj ) {
senderobj - > close ( ) ;
senderobj - > deleteLater ( ) ;
}
2007-03-28 22:01:38 +00:00
setLocalFilePath ( m_temporaryLocalFile ) ;
2014-08-10 18:36:41 +00:00
openUrl ( QUrl : : fromLocalFile ( m_temporaryLocalFile ) ) ;
2007-03-28 22:01:38 +00:00
m_temporaryLocalFile . clear ( ) ;
2005-07-15 18:20:57 +00:00
}
2014-05-10 08:26:29 +00:00
void Part : : displayInfoMessage ( const QString & message , KMessageWidget : : MessageType messageType , int duration )
{
if ( ! Okular : : Settings : : showOSD ( ) ) {
if ( messageType = = KMessageWidget : : Error ) {
KMessageBox : : error ( widget ( ) , message ) ;
}
return ;
}
// hide messageWindow if string is empty
if ( message . isEmpty ( ) )
m_infoMessage - > animatedHide ( ) ;
2018-11-14 19:12:15 +00:00
// display message (duration is length dependent)
2014-05-10 08:26:29 +00:00
if ( duration < 0 ) {
duration = 500 + 100 * message . length ( ) ;
}
m_infoTimer - > start ( duration ) ;
m_infoMessage - > setText ( message ) ;
m_infoMessage - > setMessageType ( messageType ) ;
2014-05-10 21:52:36 +00:00
m_infoMessage - > setVisible ( true ) ;
2014-05-10 08:26:29 +00:00
}
void Part : : errorMessage ( const QString & message , int duration )
{
displayInfoMessage ( message , KMessageWidget : : Error , duration ) ;
}
void Part : : warningMessage ( const QString & message , int duration )
{
displayInfoMessage ( message , KMessageWidget : : Warning , duration ) ;
}
void Part : : noticeMessage ( const QString & message , int duration )
{
2018-11-14 19:12:15 +00:00
// less important message -> simpler display widget in the PageView
2014-05-10 08:26:29 +00:00
m_pageView - > displayMessage ( message , QString ( ) , PageViewMessage : : Info , duration ) ;
}
2015-03-16 23:20:11 +00:00
void Part : : moveSplitter ( int sideWidgetSize )
{
m_sidebar - > moveSplitter ( sideWidgetSize ) ;
}
2007-06-05 20:49:00 +00:00
void Part : : unsetDummyMode ( )
{
2009-03-22 18:38:38 +00:00
if ( m_embedMode = = PrintPreviewMode )
return ;
2007-06-05 20:49:00 +00:00
2007-08-06 17:24:10 +00:00
m_sidebar - > setSidebarVisibility ( Okular : : Settings : : showLeftPanel ( ) ) ;
2007-06-05 20:49:00 +00:00
2007-06-17 09:45:59 +00:00
// add back and next in history
2011-07-31 19:22:04 +00:00
m_historyBack = KStandardAction : : documentBack ( this , SLOT ( slotHistoryBack ( ) ) , actionCollection ( ) ) ;
2007-06-17 09:45:59 +00:00
m_historyBack - > setWhatsThis ( i18n ( " Go to the place you were before " ) ) ;
2015-10-29 12:37:11 +00:00
connect ( m_pageView . data ( ) , & PageView : : mouseBackButtonClick , m_historyBack , & QAction : : trigger ) ;
2007-06-17 09:45:59 +00:00
2011-07-31 19:22:04 +00:00
m_historyNext = KStandardAction : : documentForward ( this , SLOT ( slotHistoryNext ( ) ) , actionCollection ( ) ) ;
2007-06-17 09:45:59 +00:00
m_historyNext - > setWhatsThis ( i18n ( " Go to the place you were after " ) ) ;
2015-10-29 12:37:11 +00:00
connect ( m_pageView . data ( ) , & PageView : : mouseForwardButtonClick , m_historyNext , & QAction : : trigger ) ;
2007-06-17 09:45:59 +00:00
2007-06-05 20:49:00 +00:00
m_pageView - > setupActions ( actionCollection ( ) ) ;
// attach the actions of the children widgets too
2014-05-09 15:19:50 +00:00
m_formsMessage - > addAction ( m_pageView - > toggleFormsAction ( ) ) ;
2011-11-01 21:13:20 +00:00
2019-01-05 22:30:25 +00:00
m_signatureMessage - > addAction ( m_showSignaturePanel ) ;
2011-11-01 21:13:20 +00:00
// ensure history actions are in the correct state
updateViewActions ( ) ;
2007-06-05 20:49:00 +00:00
}
2016-07-11 21:52:42 +00:00
bool Part : : handleCompressed ( QString & destpath , const QString & path , KFilterDev : : CompressionType compressionType )
2007-01-12 23:54:26 +00:00
{
2017-09-05 21:27:18 +00:00
m_tempfile = nullptr ;
2007-01-12 23:54:26 +00:00
// we are working with a compressed file, decompressing
// temporary file for decompressing
2014-09-17 22:30:39 +00:00
QTemporaryFile * newtempfile = new QTemporaryFile ( ) ;
2007-10-01 17:06:42 +00:00
newtempfile - > setAutoRemove ( true ) ;
2007-01-12 23:54:26 +00:00
2007-10-01 17:06:42 +00:00
if ( ! newtempfile - > open ( ) ) {
2007-03-30 17:46:50 +00:00
KMessageBox : : error ( widget ( ) ,
2007-01-12 23:54:26 +00:00
i18n ( " <qt><strong>File Error!</strong> Could not create temporary file "
2007-01-13 00:33:50 +00:00
" <nobr><strong>%1</strong></nobr>.</qt> " ,
2016-07-11 20:12:55 +00:00
newtempfile - > errorString ( ) ) ) ;
2007-10-01 17:06:42 +00:00
delete newtempfile ;
2007-01-13 00:33:50 +00:00
return false ;
2007-01-12 23:54:26 +00:00
}
// decompression filer
2016-07-11 21:52:42 +00:00
KCompressionDevice dev ( path , compressionType ) ;
2019-01-04 22:58:15 +00:00
2016-07-11 21:52:42 +00:00
if ( ! dev . open ( QIODevice : : ReadOnly ) ) {
2007-03-30 17:46:50 +00:00
KMessageBox : : detailedError ( widget ( ) ,
2007-01-12 23:54:26 +00:00
i18n ( " <qt><strong>File Error!</strong> Could not open the file "
" <nobr><strong>%1</strong></nobr> for uncompression. "
" The file will not be loaded.</qt> " ,
2020-07-10 22:15:05 +00:00
path ) ,
2007-01-12 23:54:26 +00:00
i18n ( " <qt>This error typically occurs if you do "
2007-01-13 00:33:50 +00:00
" not have enough permissions to read the file. "
2007-01-12 23:54:26 +00:00
" You can check ownership and permissions if you "
2008-04-11 22:09:50 +00:00
" right-click on the file in the Dolphin "
2019-01-04 22:58:15 +00:00
" file manager, then choose the 'Properties' option, "
" and select 'Permissions' tab in the opened window.</qt> " ) ) ;
2007-01-12 23:54:26 +00:00
2007-10-01 17:06:42 +00:00
delete newtempfile ;
2007-01-13 00:33:50 +00:00
return false ;
2007-01-12 23:54:26 +00:00
}
2010-08-21 15:48:02 +00:00
char buf [ 65536 ] ;
2007-01-12 23:54:26 +00:00
int read = 0 , wrtn = 0 ;
2016-07-11 21:52:42 +00:00
while ( ( read = dev . read ( buf , sizeof ( buf ) ) ) > 0 ) {
2010-08-21 15:48:02 +00:00
wrtn = newtempfile - > write ( buf , read ) ;
2007-01-12 23:54:26 +00:00
if ( read ! = wrtn )
break ;
}
2007-10-01 17:06:42 +00:00
if ( ( read ! = 0 ) | | ( newtempfile - > size ( ) = = 0 ) ) {
2007-03-30 17:46:50 +00:00
KMessageBox : : detailedError ( widget ( ) ,
2007-01-12 23:54:26 +00:00
i18n ( " <qt><strong>File Error!</strong> Could not uncompress "
" the file <nobr><strong>%1</strong></nobr>. "
" The file will not be loaded.</qt> " ,
path ) ,
i18n ( " <qt>This error typically occurs if the file is corrupt. "
" If you want to be sure, try to decompress the file manually "
" using command-line tools.</qt> " ) ) ;
2007-10-01 17:06:42 +00:00
delete newtempfile ;
2007-01-12 23:54:26 +00:00
return false ;
}
2007-10-01 17:06:42 +00:00
m_tempfile = newtempfile ;
2007-07-29 00:55:17 +00:00
destpath = m_tempfile - > fileName ( ) ;
2007-01-12 23:54:26 +00:00
return true ;
}
2007-01-13 17:28:54 +00:00
void Part : : rebuildBookmarkMenu ( bool unplugActions )
{
if ( unplugActions ) {
2015-10-29 12:37:11 +00:00
unplugActionList ( QStringLiteral ( " bookmarks_currentdocument " ) ) ;
2007-01-13 17:28:54 +00:00
qDeleteAll ( m_bookmarkActions ) ;
m_bookmarkActions . clear ( ) ;
}
2015-01-29 19:55:57 +00:00
QUrl u = m_document - > currentDocument ( ) ;
2007-01-13 17:28:54 +00:00
if ( u . isValid ( ) ) {
m_bookmarkActions = m_document - > bookmarkManager ( ) - > actionsForUrl ( u ) ;
}
2007-01-28 16:37:13 +00:00
bool havebookmarks = true ;
2007-01-13 17:28:54 +00:00
if ( m_bookmarkActions . isEmpty ( ) ) {
2007-01-28 16:37:13 +00:00
havebookmarks = false ;
2017-09-05 21:27:18 +00:00
QAction * a = new QAction ( nullptr ) ;
2007-01-13 17:28:54 +00:00
a - > setText ( i18n ( " No Bookmarks " ) ) ;
a - > setEnabled ( false ) ;
m_bookmarkActions . append ( a ) ;
}
2015-10-29 12:37:11 +00:00
plugActionList ( QStringLiteral ( " bookmarks_currentdocument " ) , m_bookmarkActions ) ;
2014-11-08 04:33:23 +00:00
2011-10-25 22:19:58 +00:00
if ( factory ( ) ) {
const QList < KXMLGUIClient * > clients ( factory ( ) - > clients ( ) ) ;
bool containerFound = false ;
for ( int i = 0 ; ! containerFound & & i < clients . size ( ) ; + + i ) {
2016-10-29 10:23:14 +00:00
QMenu * container = dynamic_cast < QMenu * > ( factory ( ) - > container ( QStringLiteral ( " bookmarks " ) , clients [ i ] ) ) ;
2011-10-25 22:19:58 +00:00
if ( container & & container - > actions ( ) . contains ( m_bookmarkActions . first ( ) ) ) {
2016-10-29 10:23:14 +00:00
container - > installEventFilter ( this ) ;
2011-10-25 22:19:58 +00:00
containerFound = true ;
}
}
}
2007-01-28 16:37:13 +00:00
m_prevBookmark - > setEnabled ( havebookmarks ) ;
m_nextBookmark - > setEnabled ( havebookmarks ) ;
2007-01-13 17:28:54 +00:00
}
2016-10-29 10:23:14 +00:00
bool Part : : eventFilter ( QObject * watched , QEvent * event )
{
switch ( event - > type ( ) ) {
case QEvent : : ContextMenu : {
QContextMenuEvent * e = static_cast < QContextMenuEvent * > ( event ) ;
QMenu * menu = static_cast < QMenu * > ( watched ) ;
QScopedPointer < QMenu > ctxMenu ( new QMenu ) ;
QPoint pos ;
bool ret = false ;
if ( e - > reason ( ) = = QContextMenuEvent : : Mouse ) {
pos = e - > pos ( ) ;
ret = aboutToShowContextMenu ( menu , menu - > actionAt ( e - > pos ( ) ) , ctxMenu . data ( ) ) ;
} else if ( menu - > activeAction ( ) ) {
pos = menu - > actionGeometry ( menu - > activeAction ( ) ) . center ( ) ;
ret = aboutToShowContextMenu ( menu , menu - > activeAction ( ) , ctxMenu . data ( ) ) ;
}
ctxMenu - > exec ( menu - > mapToGlobal ( pos ) ) ;
if ( ret ) {
event - > accept ( ) ;
}
return ret ;
}
default :
break ;
}
2020-02-20 17:45:46 +00:00
return KParts : : ReadWritePart : : eventFilter ( watched , event ) ;
2016-10-29 10:23:14 +00:00
}
2007-03-07 18:15:00 +00:00
void Part : : updateAboutBackendAction ( )
{
2015-12-08 16:22:33 +00:00
const KPluginMetaData data = m_document - > generatorInfo ( ) ;
m_aboutBackend - > setEnabled ( data . isValid ( ) ) ;
2007-03-07 18:15:00 +00:00
}
2013-03-11 21:52:25 +00:00
void Part : : resetStartArguments ( )
{
m_cliPrint = false ;
2018-03-03 16:21:15 +00:00
m_cliPrintAndExit = false ;
2013-03-11 21:52:25 +00:00
}
2017-10-11 15:45:02 +00:00
# if PURPOSE_FOUND
void Part : : slotShareActionFinished ( const QJsonObject & output , int error , const QString & message )
{
if ( error ) {
KMessageBox : : error ( widget ( ) , i18n ( " There was a problem sharing the document: %1 " , message ) , i18n ( " Share " ) ) ;
} else {
2019-04-25 21:10:48 +00:00
const QString url = output [ QStringLiteral ( " url " ) ] . toString ( ) ;
2017-10-11 15:45:02 +00:00
if ( url . isEmpty ( ) ) {
m_pageView - > displayMessage ( i18n ( " Document shared successfully " ) ) ;
} else {
KMessageBox : : information ( widget ( ) , i18n ( " You can find the shared document at: <a href= \" %1 \" >%1</a> " , url ) , i18n ( " Share " ) , QString ( ) , KMessageBox : : Notify | KMessageBox : : AllowLink ) ;
}
}
}
# endif
2012-05-23 21:43:44 +00:00
void Part : : setReadWrite ( bool readwrite )
{
m_document - > setAnnotationEditingEnabled ( readwrite ) ;
ReadWritePart : : setReadWrite ( readwrite ) ;
}
2019-02-13 21:55:02 +00:00
void Part : : enableStartWithFind ( const QString & text )
{
m_textToFindOnOpen = QString ( text ) ;
}
2019-06-28 15:41:15 +00:00
void Part : : slotOpenContainingFolder ( )
{
KIO : : highlightInFileManager ( { QUrl ( localFilePath ( ) ) } ) ;
}
2009-10-26 20:59:24 +00:00
} // namespace Okular
2007-01-12 23:54:26 +00:00
2014-08-10 20:01:13 +00:00
# include "part.moc"
2008-03-17 23:02:33 +00:00
/* kate: replace-tabs on; indent-width 4; */