2004-09-08 12:41:14 +00:00
/***************************************************************************
2005-02-20 16:04:40 +00:00
* Copyright ( C ) 2004 - 2005 by Enrico Ros < eros . kde @ email . it > *
2008-08-01 20:26:22 +00:00
* Copyright ( C ) 2004 - 2008 by Albert Astals Cid < aacid @ kde . org > *
2004-09-08 12:41:14 +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 "document.h"
2007-09-14 15:17:36 +00:00
# include "document_p.h"
2013-04-05 22:39:35 +00:00
# include "documentcommands_p.h"
2007-04-19 18:30:20 +00:00
2012-07-02 06:22:51 +00:00
# include <limits.h>
2007-10-31 19:44:35 +00:00
# ifdef Q_OS_WIN
# define _WIN32_WINNT 0x0500
# include <windows.h>
2010-12-18 01:07:33 +00:00
# elif defined(Q_OS_FREEBSD)
# include <sys/types.h>
# include <sys/sysctl.h>
# include <vm/vm_param.h>
2007-10-31 19:44:35 +00:00
# endif
2004-10-06 00:05:49 +00:00
// qt/kde/system includes
2006-09-21 08:45:36 +00:00
# include <QtCore/QtAlgorithms>
2007-05-21 19:51:30 +00:00
# include <QtCore/QDir>
2006-09-21 08:45:36 +00:00
# include <QtCore/QFile>
# include <QtCore/QFileInfo>
# include <QtCore/QMap>
# include <QtCore/QTextStream>
# include <QtCore/QTimer>
2014-08-07 23:35:27 +00:00
# include <QtWidgets/QApplication>
# include <QtWidgets/QLabel>
# include <QtPrintSupport/QPrinter>
# include <QtPrintSupport/QPrintDialog>
2013-04-05 22:22:48 +00:00
# include <QUndoCommand>
2006-09-21 08:45:36 +00:00
2007-03-11 22:35:14 +00:00
# include <kaboutdata.h>
2014-08-07 23:35:27 +00:00
# include <k4aboutdata.h>
2007-01-29 14:28:58 +00:00
# include <kauthorized.h>
2007-03-11 22:35:14 +00:00
# include <kcomponentdata.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 <kconfigdialog.h>
2004-09-12 23:19:18 +00:00
# include <kdebug.h>
2006-09-21 08:45:36 +00:00
# include <klibloader.h>
# include <klocale.h>
2008-10-19 19:40:17 +00:00
# include <kmacroexpander.h>
2004-09-16 21:04:49 +00:00
# include <kmessagebox.h>
2006-05-22 14:02:24 +00:00
# include <kmimetypetrader.h>
2008-10-19 19:40:17 +00:00
# include <kprocess.h>
2004-12-10 16:04:45 +00:00
# include <krun.h>
2008-10-19 19:40:17 +00:00
# include <kshell.h>
2005-01-03 00:28:46 +00:00
# include <kstandarddirs.h>
2007-01-12 22:49:14 +00:00
# include <ktemporaryfile.h>
2006-09-21 08:45:36 +00:00
# include <ktoolinvocation.h>
2008-11-15 14:15:31 +00:00
# include <kzip.h>
2004-09-08 12:41:14 +00:00
// local includes
2007-04-20 11:26:05 +00:00
# include "action.h"
2007-07-17 18:10:25 +00:00
# include "annotations.h"
# include "annotations_p.h"
2007-02-05 00:49:40 +00:00
# include "audioplayer.h"
2007-07-10 18:24:18 +00:00
# include "audioplayer_p.h"
2006-12-27 16:04:49 +00:00
# include "bookmarkmanager.h"
2007-07-10 22:52:25 +00:00
# include "chooseenginedialog_p.h"
2007-07-31 10:19:48 +00:00
# include "debug_p.h"
2007-04-20 17:26:04 +00:00
# include "generator_p.h"
2007-01-03 14:30:48 +00:00
# include "interfaces/configinterface.h"
# include "interfaces/guiinterface.h"
# include "interfaces/printinterface.h"
2008-03-11 23:40:59 +00:00
# include "interfaces/saveinterface.h"
2005-01-02 14:55:14 +00:00
# include "observer.h"
2011-10-17 19:56:45 +00:00
# include "misc.h"
2004-09-08 12:41:14 +00:00
# include "page.h"
2007-04-14 19:58:17 +00:00
# include "page_p.h"
2007-03-24 10:47:22 +00:00
# include "pagecontroller_p.h"
2008-04-13 22:31:59 +00:00
# include "scripter.h"
2012-10-15 22:27:42 +00:00
# include "settings_core.h"
2007-01-02 17:45:32 +00:00
# include "sourcereference.h"
2008-09-22 13:41:28 +00:00
# include "sourcereference_p.h"
2008-10-19 18:01:16 +00:00
# include "texteditors_p.h"
2012-11-08 20:29:09 +00:00
# include "tile.h"
2012-08-17 18:23:58 +00:00
# include "tilesmanager_p.h"
2008-11-15 14:15:31 +00:00
# include "utils_p.h"
2008-04-27 11:05:59 +00:00
# include "view.h"
# include "view_p.h"
2013-06-03 20:46:41 +00:00
# include "form.h"
2014-01-13 00:15:55 +00:00
# include "utils.h"
2004-09-09 13:25:40 +00:00
2008-11-15 14:15:31 +00:00
# include <memory>
2007-01-29 14:28:58 +00:00
# include <config-okular.h>
2006-09-21 08:45:36 +00:00
using namespace Okular ;
2005-01-20 17:33:05 +00:00
struct AllocatedPixmap
2004-12-21 12:38:52 +00:00
{
2005-01-20 17:33:05 +00:00
// owner of the page
2013-02-24 21:58:53 +00:00
DocumentObserver * observer ;
2005-01-20 17:33:05 +00:00
int page ;
2007-07-15 16:10:48 +00:00
qulonglong memory ;
2004-12-21 12:38:52 +00:00
// public constructor: initialize data
2013-02-24 21:58:53 +00:00
AllocatedPixmap ( DocumentObserver * o , int p , qulonglong m ) : observer ( o ) , page ( p ) , memory ( m ) { }
2004-09-08 12:41:14 +00:00
} ;
2008-11-15 14:15:31 +00:00
struct ArchiveData
{
ArchiveData ( )
{
}
KTemporaryFile document ;
2014-05-10 09:35:33 +00:00
KTemporaryFile metadataFile ;
2008-11-15 14:15:31 +00:00
} ;
2005-02-01 18:26:56 +00:00
struct RunningSearch
{
2005-02-02 18:18:26 +00:00
// store search properties
int continueOnPage ;
2005-07-15 18:20:57 +00:00
RegularAreaRect continueOnMatch ;
2007-08-13 22:25:27 +00:00
QSet < int > highlightedPages ;
2005-02-02 18:18:26 +00:00
// fields related to previous searches (used for 'continueSearch')
QString cachedString ;
2006-09-21 08:45:36 +00:00
Document : : SearchType cachedType ;
2006-11-23 16:54:28 +00:00
Qt : : CaseSensitivity cachedCaseSensitivity ;
2007-09-07 13:13:50 +00:00
bool cachedViewportMove : 1 ;
2009-08-10 22:28:54 +00:00
bool isCurrentlySearching : 1 ;
2005-02-02 18:18:26 +00:00
QColor cachedColor ;
2014-05-10 09:33:21 +00:00
int pagesDone ;
2005-02-01 18:26:56 +00:00
} ;
2004-09-08 12:41:14 +00:00
# define foreachObserver( cmd ) {\
2013-02-24 21:58:53 +00:00
QSet < DocumentObserver * > : : const_iterator it = d - > m_observers . constBegin ( ) , end = d - > m_observers . constEnd ( ) ; \
2005-01-20 17:33:05 +00:00
for ( ; it ! = end ; + + it ) { ( * it ) - > cmd ; } }
2004-09-08 12:41:14 +00:00
2007-07-12 20:04:56 +00:00
# define foreachObserverD( cmd ) {\
2013-02-24 21:58:53 +00:00
QSet < DocumentObserver * > : : const_iterator it = m_observers . constBegin ( ) , end = m_observers . constEnd ( ) ; \
2007-07-12 20:04:56 +00:00
for ( ; it ! = end ; + + it ) { ( * it ) - > cmd ; } }
2007-07-23 17:12:20 +00:00
# define OKULAR_HISTORY_MAXSTEPS 100
# define OKULAR_HISTORY_SAVEDSTEPS 10
2007-01-02 19:05:49 +00:00
/***** Document ******/
2005-01-26 10:42:07 +00:00
2007-04-14 19:44:07 +00:00
QString DocumentPrivate : : pagesSizeString ( ) const
2007-01-02 19:05:49 +00:00
{
if ( m_generator )
2005-01-15 01:08:35 +00:00
{
2007-01-02 19:05:49 +00:00
if ( m_generator - > pagesSizeMetric ( ) ! = Generator : : None )
- 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-02 19:05:49 +00:00
QSizeF size = m_parent - > allPagesSize ( ) ;
if ( size . isValid ( ) ) return localizedSize ( size ) ;
else return QString ( ) ;
- 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-02 19:05:49 +00:00
else return QString ( ) ;
2005-01-15 01:08:35 +00:00
}
2007-01-02 19:05:49 +00:00
else return QString ( ) ;
}
2005-01-03 00:45:47 +00:00
2012-12-31 10:14:54 +00:00
QString DocumentPrivate : : namePaperSize ( double inchesWidth , double inchesHeight ) const
{
// Account for small deviations in paper sizes
static const double marginFactor = 0.03 ;
static const double lowerBoundFactor = 1.0 - marginFactor ;
static const double upperBoundFactor = 1.0 + marginFactor ;
const QPrinter : : Orientation orientation = inchesWidth > inchesHeight ? QPrinter : : Landscape : QPrinter : : Portrait ;
// enforce portrait mode for further tests
2013-04-05 22:22:48 +00:00
if ( inchesWidth > inchesHeight )
2012-12-31 10:14:54 +00:00
qSwap ( inchesWidth , inchesHeight ) ;
// Use QPrinter to find which of the predefined paper sizes
// matches best the given paper width and height
QPrinter dummyPrinter ;
QPrinter : : PaperSize paperSize = QPrinter : : Custom ;
for ( int i = 0 ; i < ( int ) QPrinter : : NPaperSize ; + + i )
{
const QPrinter : : PaperSize ps = ( QPrinter : : PaperSize ) i ;
dummyPrinter . setPaperSize ( ps ) ;
const QSizeF definedPaperSize = dummyPrinter . paperSize ( QPrinter : : Inch ) ;
if ( inchesWidth > definedPaperSize . width ( ) * lowerBoundFactor & & inchesWidth < definedPaperSize . width ( ) * upperBoundFactor
& & inchesHeight > definedPaperSize . height ( ) * lowerBoundFactor & & inchesHeight < definedPaperSize . height ( ) * upperBoundFactor )
{
paperSize = ps ;
break ;
}
}
// Handle all paper sizes defined in QPrinter,
// return string depending if paper's orientation is landscape or portrait
switch ( paperSize ) {
case QPrinter : : A0 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A0 " ) : i18nc ( " paper size " , " portrait DIN/ISO A0 " ) ;
case QPrinter : : A1 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A1 " ) : i18nc ( " paper size " , " portrait DIN/ISO A1 " ) ;
case QPrinter : : A2 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A2 " ) : i18nc ( " paper size " , " portrait DIN/ISO A2 " ) ;
case QPrinter : : A3 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A3 " ) : i18nc ( " paper size " , " portrait DIN/ISO A3 " ) ;
case QPrinter : : A4 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A4 " ) : i18nc ( " paper size " , " portrait DIN/ISO A4 " ) ;
case QPrinter : : A5 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A5 " ) : i18nc ( " paper size " , " portrait DIN/ISO A5 " ) ;
case QPrinter : : A6 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A6 " ) : i18nc ( " paper size " , " portrait DIN/ISO A6 " ) ;
case QPrinter : : A7 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A7 " ) : i18nc ( " paper size " , " portrait DIN/ISO A7 " ) ;
case QPrinter : : A8 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A8 " ) : i18nc ( " paper size " , " portrait DIN/ISO A8 " ) ;
case QPrinter : : A9 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO A9 " ) : i18nc ( " paper size " , " portrait DIN/ISO A9 " ) ;
case QPrinter : : B0 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B0 " ) : i18nc ( " paper size " , " portrait DIN/ISO B0 " ) ;
case QPrinter : : B1 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B1 " ) : i18nc ( " paper size " , " portrait DIN/ISO B1 " ) ;
case QPrinter : : B2 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B2 " ) : i18nc ( " paper size " , " portrait DIN/ISO B2 " ) ;
case QPrinter : : B3 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B3 " ) : i18nc ( " paper size " , " portrait DIN/ISO B3 " ) ;
case QPrinter : : B4 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B4 " ) : i18nc ( " paper size " , " portrait DIN/ISO B4 " ) ;
case QPrinter : : B5 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B5 " ) : i18nc ( " paper size " , " portrait DIN/ISO B5 " ) ;
case QPrinter : : B6 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B6 " ) : i18nc ( " paper size " , " portrait DIN/ISO B6 " ) ;
case QPrinter : : B7 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B7 " ) : i18nc ( " paper size " , " portrait DIN/ISO B7 " ) ;
case QPrinter : : B8 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B8 " ) : i18nc ( " paper size " , " portrait DIN/ISO B8 " ) ;
case QPrinter : : B9 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B9 " ) : i18nc ( " paper size " , " portrait DIN/ISO B9 " ) ;
case QPrinter : : B10 :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DIN/ISO B10 " ) : i18nc ( " paper size " , " portrait DIN/ISO B10 " ) ;
case QPrinter : : Letter :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape letter " ) : i18nc ( " paper size " , " portrait letter " ) ;
case QPrinter : : Legal :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape legal " ) : i18nc ( " paper size " , " portrait legal " ) ;
case QPrinter : : Executive :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape executive " ) : i18nc ( " paper size " , " portrait executive " ) ;
case QPrinter : : C5E :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape C5E " ) : i18nc ( " paper size " , " portrait C5E " ) ;
case QPrinter : : Comm10E :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape Comm10E " ) : i18nc ( " paper size " , " portrait Comm10E " ) ;
case QPrinter : : DLE :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape DLE " ) : i18nc ( " paper size " , " portrait DLE " ) ;
case QPrinter : : Folio :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " landscape folio " ) : i18nc ( " paper size " , " portrait folio " ) ;
case QPrinter : : Tabloid :
case QPrinter : : Ledger :
/// Ledger and Tabloid are the same, just rotated by 90 degrees
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " ledger " ) : i18nc ( " paper size " , " tabloid " ) ;
case QPrinter : : Custom :
return orientation = = QPrinter : : Landscape ? i18nc ( " paper size " , " unknown landscape paper size " ) : i18nc ( " paper size " , " unknown portrait paper size " ) ;
}
kWarning ( ) < < " PaperSize " < < paperSize < < " has not been covered " ;
return QString ( ) ;
}
2007-04-14 19:44:07 +00:00
QString DocumentPrivate : : localizedSize ( const QSizeF & size ) const
2007-01-02 19:05:49 +00:00
{
double inchesWidth = 0 , inchesHeight = 0 ;
switch ( m_generator - > pagesSizeMetric ( ) )
2005-06-24 16:39:57 +00:00
{
2007-01-02 19:05:49 +00:00
case Generator : : Points :
inchesWidth = size . width ( ) / 72.0 ;
inchesHeight = size . height ( ) / 72.0 ;
break ;
2005-01-03 15:51:05 +00:00
2014-01-13 00:15:55 +00:00
case Generator : : Pixels :
{
const QSizeF dpi = m_generator - > dpi ( ) ;
inchesWidth = size . width ( ) / dpi . width ( ) ;
inchesHeight = size . height ( ) / dpi . height ( ) ;
}
break ;
2007-01-02 19:05:49 +00:00
case Generator : : None :
break ;
2005-01-21 20:05:36 +00:00
}
2007-01-02 19:05:49 +00:00
if ( KGlobal : : locale ( ) - > measureSystem ( ) = = KLocale : : Imperial )
2005-01-21 20:05:36 +00:00
{
2012-12-31 10:14:54 +00:00
return i18nc ( " %1 is width, %2 is height, %3 is paper size name " , " %1 x %2 in (%3) " , inchesWidth, inchesHeight, namePaperSize(inchesWidth, inchesHeight)) ;
2005-01-21 20:05:36 +00:00
}
2007-01-02 19:05:49 +00:00
else
2005-02-04 22:35:44 +00:00
{
2012-12-31 10:14:54 +00:00
return i18nc ( " %1 is width, %2 is height, %3 is paper size name " , " %1 x %2 mm (%3) " , QString::number(inchesWidth * 25.4, 'd', 0), QString::number(inchesHeight * 25.4, 'd', 0), namePaperSize(inchesWidth, inchesHeight)) ;
2005-02-04 22:35:44 +00:00
}
2004-09-08 12:41:14 +00:00
}
2012-07-01 23:19:32 +00:00
qulonglong DocumentPrivate : : calculateMemoryToFree ( )
- 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-02 19:05:49 +00:00
// [MEM] choose memory parameters based on configuration profile
2008-04-27 18:08:14 +00:00
qulonglong clipValue = 0 ;
qulonglong memoryToFree = 0 ;
2012-06-24 18:35:37 +00:00
2012-10-15 22:27:42 +00:00
switch ( SettingsCore : : memoryLevel ( ) )
2007-01-02 16:40:22 +00:00
{
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumMemoryLevel : : Low :
2007-01-02 19:05:49 +00:00
memoryToFree = m_allocatedPixmapsTotalMemory ;
break ;
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumMemoryLevel : : Normal :
2008-04-27 18:08:14 +00:00
{
qulonglong thirdTotalMemory = getTotalMemory ( ) / 3 ;
qulonglong freeMemory = getFreeMemory ( ) ;
if ( m_allocatedPixmapsTotalMemory > thirdTotalMemory ) memoryToFree = m_allocatedPixmapsTotalMemory - thirdTotalMemory ;
if ( m_allocatedPixmapsTotalMemory > freeMemory ) clipValue = ( m_allocatedPixmapsTotalMemory - freeMemory ) / 2 ;
}
break ;
2007-01-02 19:05:49 +00:00
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumMemoryLevel : : Aggressive :
2008-04-27 18:08:14 +00:00
{
qulonglong freeMemory = getFreeMemory ( ) ;
if ( m_allocatedPixmapsTotalMemory > freeMemory ) clipValue = ( m_allocatedPixmapsTotalMemory - freeMemory ) / 2 ;
}
break ;
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumMemoryLevel : : Greedy :
2012-03-08 23:12:20 +00:00
{
2012-06-24 21:53:01 +00:00
qulonglong freeSwap ;
2012-06-24 18:35:37 +00:00
qulonglong freeMemory = getFreeMemory ( & freeSwap ) ;
const qulonglong memoryLimit = qMin ( qMax ( freeMemory , getTotalMemory ( ) / 2 ) , freeMemory + freeSwap ) ;
2012-03-08 23:12:20 +00:00
if ( m_allocatedPixmapsTotalMemory > memoryLimit ) clipValue = ( m_allocatedPixmapsTotalMemory - memoryLimit ) / 2 ;
}
break ;
2007-01-02 16:40:22 +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-02 19:05:49 +00:00
if ( clipValue > memoryToFree )
memoryToFree = clipValue ;
2012-07-01 23:19:32 +00:00
return memoryToFree ;
}
void DocumentPrivate : : cleanupPixmapMemory ( )
{
cleanupPixmapMemory ( calculateMemoryToFree ( ) ) ;
}
void DocumentPrivate : : cleanupPixmapMemory ( qulonglong memoryToFree )
{
2014-02-19 22:40:43 +00:00
if ( memoryToFree < 1 )
return ;
2012-11-08 18:21:09 +00:00
2014-02-19 22:40:43 +00:00
const int currentViewportPage = ( * m_viewportIterator ) . pageNumber ;
2012-11-08 13:58:08 +00:00
2014-02-19 22:40:43 +00:00
// Create a QMap of visible rects, indexed by page number
QMap < int , VisiblePageRect * > visibleRects ;
QVector < Okular : : VisiblePageRect * > : : const_iterator vIt = m_pageRects . constBegin ( ) , vEnd = m_pageRects . constEnd ( ) ;
for ( ; vIt ! = vEnd ; + + vIt )
visibleRects . insert ( ( * vIt ) - > pageNumber , ( * vIt ) ) ;
2012-07-01 23:05:02 +00:00
2014-02-19 22:40:43 +00:00
// Free memory starting from pages that are farthest from the current one
int pagesFreed = 0 ;
while ( memoryToFree > 0 )
{
AllocatedPixmap * p = searchLowestPriorityPixmap ( true , true ) ;
if ( ! p ) // No pixmap to remove
break ;
2012-07-01 23:05:02 +00:00
2014-02-19 22:40:43 +00:00
kDebug ( ) . nospace ( ) < < " Evicting cache pixmap observer= " < < p - > observer < < " page= " < < p - > page ;
// m_allocatedPixmapsTotalMemory can't underflow because we always add or remove
// the memory used by the AllocatedPixmap so at most it can reach zero
m_allocatedPixmapsTotalMemory - = p - > memory ;
// Make sure memoryToFree does not underflow
if ( p - > memory > memoryToFree )
memoryToFree = 0 ;
else
memoryToFree - = p - > memory ;
pagesFreed + + ;
// delete pixmap
m_pagesVector . at ( p - > page ) - > deletePixmap ( p - > observer ) ;
// delete allocation descriptor
delete p ;
}
2012-08-13 04:09:05 +00:00
2014-02-19 22:40:43 +00:00
// If we're still on low memory, try to free individual tiles
2012-11-08 13:58:08 +00:00
2014-02-19 22:40:43 +00:00
// Store pages that weren't completely removed
QLinkedList < AllocatedPixmap * > pixmapsToKeep ;
while ( memoryToFree > 0 )
{
int clean_hits = 0 ;
foreach ( DocumentObserver * observer , m_observers )
2012-08-13 04:09:05 +00:00
{
2014-02-19 22:40:43 +00:00
AllocatedPixmap * p = searchLowestPriorityPixmap ( false , true , observer ) ;
2012-11-08 13:58:08 +00:00
if ( ! p ) // No pixmap to remove
2014-02-19 22:40:43 +00:00
continue ;
2012-08-13 04:09:05 +00:00
2014-02-19 22:40:43 +00:00
clean_hits + + ;
TilesManager * tilesManager = m_pagesVector . at ( p - > page ) - > d - > tilesManager ( observer ) ;
2012-08-20 01:43:59 +00:00
if ( tilesManager & & tilesManager - > totalMemory ( ) > 0 )
2012-08-13 04:09:05 +00:00
{
2012-11-08 18:21:09 +00:00
qulonglong memoryDiff = p - > memory ;
NormalizedRect visibleRect ;
2012-11-08 13:58:08 +00:00
if ( visibleRects . contains ( p - > page ) )
2012-11-08 18:21:09 +00:00
visibleRect = visibleRects [ p - > page ] - > rect ;
2012-11-08 13:58:08 +00:00
2012-11-08 18:21:09 +00:00
// Free non visible tiles
tilesManager - > cleanupPixmapMemory ( memoryToFree , visibleRect , currentViewportPage ) ;
2012-11-08 13:58:08 +00:00
2012-08-13 04:09:05 +00:00
p - > memory = tilesManager - > totalMemory ( ) ;
2012-11-08 13:58:08 +00:00
memoryDiff - = p - > memory ;
2012-11-08 18:21:09 +00:00
memoryToFree = ( memoryDiff < memoryToFree ) ? ( memoryToFree - memoryDiff ) : 0 ;
2012-11-08 13:58:08 +00:00
m_allocatedPixmapsTotalMemory - = memoryDiff ;
if ( p - > memory > 0 )
pixmapsToKeep . append ( p ) ;
else
delete p ;
2012-08-13 04:09:05 +00:00
}
2012-11-08 13:58:08 +00:00
else
pixmapsToKeep . append ( p ) ;
2012-08-13 04:09:05 +00:00
}
2012-11-08 13:58:08 +00:00
2014-02-19 22:40:43 +00:00
if ( clean_hits = = 0 ) break ;
2012-07-01 23:05:02 +00:00
}
2014-02-19 22:40:43 +00:00
m_allocatedPixmaps + = pixmapsToKeep ;
//p--rintf("freeMemory A:[%d -%d = %d] \n", m_allocatedPixmaps.count() + pagesFreed, pagesFreed, m_allocatedPixmaps.count() );
2012-07-01 23:05:02 +00:00
}
2012-08-13 04:09:05 +00:00
2012-07-01 23:05:02 +00:00
/* Returns the next pixmap to evict from cache, or NULL if no suitable pixmap
2012-11-08 13:58:08 +00:00
* if found . If unloadableOnly is set , only unloadable pixmaps are returned . If
* thenRemoveIt is set , the pixmap is removed from m_allocatedPixmaps before
* returning it
*/
2013-02-24 21:58:53 +00:00
AllocatedPixmap * DocumentPrivate : : searchLowestPriorityPixmap ( bool unloadableOnly , bool thenRemoveIt , DocumentObserver * observer )
2012-07-01 23:05:02 +00:00
{
QLinkedList < AllocatedPixmap * > : : iterator pIt = m_allocatedPixmaps . begin ( ) ;
QLinkedList < AllocatedPixmap * > : : iterator pEnd = m_allocatedPixmaps . end ( ) ;
QLinkedList < AllocatedPixmap * > : : iterator farthestPixmap = pEnd ;
const int currentViewportPage = ( * m_viewportIterator ) . pageNumber ;
/* Find the pixmap that is farthest from the current viewport */
int maxDistance = - 1 ;
while ( pIt ! = pEnd )
{
const AllocatedPixmap * p = * pIt ;
2012-11-08 19:46:47 +00:00
// Filter by observer
2013-02-24 21:58:53 +00:00
if ( observer = = 0 | | p - > observer = = observer )
2012-07-01 23:05:02 +00:00
{
2012-11-08 19:46:47 +00:00
const int distance = qAbs ( p - > page - currentViewportPage ) ;
2013-02-24 21:58:53 +00:00
if ( maxDistance < distance & & ( ! unloadableOnly | | p - > observer - > canUnloadPixmap ( p - > page ) ) )
2012-11-08 19:46:47 +00:00
{
maxDistance = distance ;
farthestPixmap = pIt ;
}
2007-01-02 19:05:49 +00:00
}
2012-07-01 23:05:02 +00:00
+ + pIt ;
2007-01-02 16:40:22 +00:00
}
2012-07-01 23:05:02 +00:00
/* No pixmap to remove */
if ( farthestPixmap = = pEnd )
return 0 ;
AllocatedPixmap * selectedPixmap = * farthestPixmap ;
if ( thenRemoveIt )
m_allocatedPixmaps . erase ( farthestPixmap ) ;
return selectedPixmap ;
- 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-07-15 16:10:48 +00:00
qulonglong DocumentPrivate : : getTotalMemory ( )
2004-09-08 12:41:14 +00:00
{
2007-07-15 16:10:48 +00:00
static qulonglong cachedValue = 0 ;
2007-01-02 19:05:49 +00:00
if ( cachedValue )
return cachedValue ;
2005-01-03 00:28:46 +00:00
2007-07-15 16:51:23 +00:00
# if defined(Q_OS_LINUX)
2007-01-02 19:05:49 +00:00
// if /proc/meminfo doesn't exist, return 128MB
QFile memFile ( " /proc/meminfo " ) ;
if ( ! memFile . open ( QIODevice : : ReadOnly ) )
return ( cachedValue = 134217728 ) ;
2004-12-24 10:24:10 +00:00
2007-01-02 19:05:49 +00:00
QTextStream readStream ( & memFile ) ;
2012-06-19 21:38:54 +00:00
while ( true )
2005-08-31 18:13:59 +00:00
{
2007-01-02 19:05:49 +00:00
QString entry = readStream . readLine ( ) ;
2007-03-10 05:38:23 +00:00
if ( entry . isNull ( ) ) break ;
2007-01-02 19:05:49 +00:00
if ( entry . startsWith ( " MemTotal: " ) )
2008-10-04 19:31:36 +00:00
return ( cachedValue = ( Q_UINT64_C ( 1024 ) * entry . section ( ' ' , - 2 , - 2 ) . toULongLong ( ) ) ) ;
2005-08-31 18:13:59 +00:00
}
2010-12-18 01:07:33 +00:00
# elif defined(Q_OS_FREEBSD)
qulonglong physmem ;
int mib [ ] = { CTL_HW , HW_PHYSMEM } ;
size_t len = sizeof ( physmem ) ;
if ( sysctl ( mib , 2 , & physmem , & len , NULL , 0 ) = = 0 )
return ( cachedValue = physmem ) ;
2007-07-15 16:43:24 +00:00
# elif defined(Q_OS_WIN)
MEMORYSTATUSEX stat ;
2009-02-08 02:36:04 +00:00
stat . dwLength = sizeof ( stat ) ;
2007-07-15 16:43:24 +00:00
GlobalMemoryStatusEx ( & stat ) ;
2007-09-15 14:05:08 +00:00
return ( cachedValue = stat . ullTotalPhys ) ;
2007-01-02 19:05:49 +00:00
# endif
return ( cachedValue = 134217728 ) ;
}
2005-01-18 16:43:36 +00:00
2012-06-24 18:35:37 +00:00
qulonglong DocumentPrivate : : getFreeMemory ( qulonglong * freeSwap )
2007-01-02 19:05:49 +00:00
{
2012-03-08 23:26:51 +00:00
static QTime lastUpdate = QTime : : currentTime ( ) . addSecs ( - 3 ) ;
2007-07-15 16:10:48 +00:00
static qulonglong cachedValue = 0 ;
2012-06-24 18:35:37 +00:00
static qulonglong cachedFreeSwap = 0 ;
2005-01-03 00:24:59 +00:00
2010-03-19 19:52:38 +00:00
if ( qAbs ( lastUpdate . secsTo ( QTime : : currentTime ( ) ) ) < = 2 )
2012-06-24 18:35:37 +00:00
{
2012-06-24 21:53:01 +00:00
if ( freeSwap )
* freeSwap = cachedFreeSwap ;
2007-01-02 19:05:49 +00:00
return cachedValue ;
2012-06-24 18:35:37 +00:00
}
/* Initialize the returned free swap value to 0. It is overwritten if the
* actual value is available */
2012-06-24 21:53:01 +00:00
if ( freeSwap )
* freeSwap = 0 ;
2004-12-10 16:04:45 +00:00
2007-07-15 16:51:23 +00:00
# if defined(Q_OS_LINUX)
2007-01-02 19:05:49 +00:00
// if /proc/meminfo doesn't exist, return MEMORY FULL
QFile memFile ( " /proc/meminfo " ) ;
if ( ! memFile . open ( QIODevice : : ReadOnly ) )
return 0 ;
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
// read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers'
// and 'Cached' fields. consider swapped memory as used memory.
2007-07-15 16:10:48 +00:00
qulonglong memoryFree = 0 ;
2007-01-02 19:05:49 +00:00
QString entry ;
QTextStream readStream ( & memFile ) ;
2012-06-19 22:33:43 +00:00
static const int nElems = 5 ;
QString names [ nElems ] = { " MemFree: " , " Buffers: " , " Cached: " , " SwapFree: " , " SwapTotal: " } ;
qulonglong values [ nElems ] = { 0 , 0 , 0 , 0 , 0 } ;
bool foundValues [ nElems ] = { false , false , false , false , false } ;
2007-01-02 19:05:49 +00:00
while ( true )
{
entry = readStream . readLine ( ) ;
2007-03-10 05:38:23 +00:00
if ( entry . isNull ( ) ) break ;
2012-06-19 22:33:43 +00:00
for ( int i = 0 ; i < nElems ; + + i )
{
if ( entry . startsWith ( names [ i ] ) )
{
values [ i ] = entry . section ( ' ' , - 2 , - 2 ) . toULongLong ( & foundValues [ i ] ) ;
}
}
2007-01-02 19:05:49 +00:00
}
memFile . close ( ) ;
2012-06-19 22:33:43 +00:00
bool found = true ;
for ( int i = 0 ; found & & i < nElems ; + + i )
found = found & & foundValues [ i ] ;
if ( found )
{
2012-06-24 18:35:37 +00:00
/* MemFree + Buffers + Cached - SwapUsed =
* = MemFree + Buffers + Cached - ( SwapTotal - SwapFree ) =
* = MemFree + Buffers + Cached + SwapFree - SwapTotal */
2012-06-19 22:33:43 +00:00
memoryFree = values [ 0 ] + values [ 1 ] + values [ 2 ] + values [ 3 ] ;
if ( values [ 4 ] > memoryFree )
memoryFree = 0 ;
else
memoryFree - = values [ 4 ] ;
}
2012-06-24 18:08:18 +00:00
else
{
return 0 ;
}
2006-06-24 10:03:12 +00:00
2007-01-02 19:05:49 +00:00
lastUpdate = QTime : : currentTime ( ) ;
2005-07-15 18:20:57 +00:00
2012-06-24 21:53:01 +00:00
if ( freeSwap )
* freeSwap = ( cachedFreeSwap = ( Q_UINT64_C ( 1024 ) * values [ 3 ] ) ) ;
2008-10-04 19:31:36 +00:00
return ( cachedValue = ( Q_UINT64_C ( 1024 ) * memoryFree ) ) ;
2010-12-18 01:07:33 +00:00
# elif defined(Q_OS_FREEBSD)
qulonglong cache , inact , free , psize ;
size_t cachelen , inactlen , freelen , psizelen ;
cachelen = sizeof ( cache ) ;
inactlen = sizeof ( inact ) ;
freelen = sizeof ( free ) ;
psizelen = sizeof ( psize ) ;
// sum up inactive, cached and free memory
if ( sysctlbyname ( " vm.stats.vm.v_cache_count " , & cache , & cachelen , NULL , 0 ) = = 0 & &
sysctlbyname ( " vm.stats.vm.v_inactive_count " , & inact , & inactlen , NULL , 0 ) = = 0 & &
sysctlbyname ( " vm.stats.vm.v_free_count " , & free , & freelen , NULL , 0 ) = = 0 & &
sysctlbyname ( " vm.stats.vm.v_page_size " , & psize , & psizelen , NULL , 0 ) = = 0 )
{
lastUpdate = QTime : : currentTime ( ) ;
return ( cachedValue = ( cache + inact + free ) * psize ) ;
}
else
{
return 0 ;
}
2007-07-15 16:43:24 +00:00
# elif defined(Q_OS_WIN)
2007-07-15 16:47:55 +00:00
MEMORYSTATUSEX stat ;
2009-02-08 02:36:04 +00:00
stat . dwLength = sizeof ( stat ) ;
2007-07-15 16:47:55 +00:00
GlobalMemoryStatusEx ( & stat ) ;
2007-07-15 16:43:24 +00:00
2007-12-11 13:52:55 +00:00
lastUpdate = QTime : : currentTime ( ) ;
2012-06-24 21:53:01 +00:00
if ( freeSwap )
* freeSwap = ( cachedFreeSwap = stat . ullAvailPageFile ) ;
2007-08-14 13:03:38 +00:00
return ( cachedValue = stat . ullAvailPhys ) ;
2007-01-02 19:05:49 +00:00
# else
// tell the memory is full.. will act as in LOW profile
return 0 ;
# endif
2004-09-08 12:41:14 +00:00
}
2007-04-14 19:44:07 +00:00
void DocumentPrivate : : loadDocumentInfo ( )
2007-01-02 19:05:49 +00:00
// note: load data and stores it internally (document or pages). observers
// are still uninitialized at this point so don't access them
2004-09-08 12:41:14 +00:00
{
2007-07-31 10:19:48 +00:00
//kDebug(OkularDebug).nospace() << "Using '" << d->m_xmlFileName << "' as document info file.";
2007-01-12 22:49:14 +00:00
if ( m_xmlFileName . isEmpty ( ) )
return ;
2014-05-10 09:35:33 +00:00
QFile infoFile ( m_xmlFileName ) ;
loadDocumentInfo ( infoFile ) ;
2008-11-15 00:34:03 +00:00
}
2014-05-10 09:35:33 +00:00
void DocumentPrivate : : loadDocumentInfo ( QFile & infoFile )
2008-11-15 00:34:03 +00:00
{
2007-01-02 19:05:49 +00:00
if ( ! infoFile . exists ( ) | | ! infoFile . open ( QIODevice : : ReadOnly ) )
return ;
2004-12-17 17:14:46 +00:00
2007-01-02 19:05:49 +00:00
// Load DOM from XML file
QDomDocument doc ( " documentInfo " ) ;
if ( ! doc . setContent ( & infoFile ) )
2005-02-12 17:42:54 +00:00
{
2007-07-31 10:19:48 +00:00
kDebug ( OkularDebug ) < < " Can't load XML pair! Check for broken xml. " ;
2007-01-02 19:05:49 +00:00
infoFile . close ( ) ;
return ;
2005-02-12 17:42:54 +00:00
}
2007-01-02 19:05:49 +00:00
infoFile . close ( ) ;
2004-12-17 17:14:46 +00:00
2007-01-02 19:05:49 +00:00
QDomElement root = doc . documentElement ( ) ;
if ( root . tagName ( ) ! = " documentInfo " )
return ;
2007-09-03 17:53:45 +00:00
KUrl documentUrl ( root . attribute ( " url " ) ) ;
2007-01-02 19:05:49 +00:00
// Parse the DOM tree
QDomNode topLevelNode = root . firstChild ( ) ;
while ( topLevelNode . isElement ( ) )
2004-12-21 12:38:52 +00:00
{
2007-01-02 19:05:49 +00:00
QString catName = topLevelNode . toElement ( ) . tagName ( ) ;
2004-12-24 10:24:10 +00:00
2007-01-02 19:05:49 +00:00
// Restore page attributes (bookmark, annotations, ...) from the DOM
if ( catName = = " pageList " )
2005-01-28 18:18:48 +00:00
{
2007-01-02 19:05:49 +00:00
QDomNode pageNode = topLevelNode . firstChild ( ) ;
while ( pageNode . isElement ( ) )
2005-01-28 18:18:48 +00:00
{
2007-01-02 19:05:49 +00:00
QDomElement pageElement = pageNode . toElement ( ) ;
if ( pageElement . hasAttribute ( " number " ) )
{
// get page number (node's attribute)
bool ok ;
int pageNumber = pageElement . attribute ( " number " ) . toInt ( & ok ) ;
// pass the domElement to the right page, to read config data from
if ( ok & & pageNumber > = 0 & & pageNumber < ( int ) m_pagesVector . count ( ) )
2007-04-14 19:58:17 +00:00
m_pagesVector [ pageNumber ] - > d - > restoreLocalContents ( pageElement ) ;
2007-01-02 19:05:49 +00:00
}
pageNode = pageNode . nextSibling ( ) ;
2005-01-28 18:18:48 +00:00
}
}
2007-01-02 19:05:49 +00:00
// Restore 'general info' from the DOM
else if ( catName = = " generalInfo " )
{
QDomNode infoNode = topLevelNode . firstChild ( ) ;
while ( infoNode . isElement ( ) )
{
QDomElement infoElement = infoNode . toElement ( ) ;
2005-01-21 20:05:36 +00:00
2007-01-02 19:05:49 +00:00
// restore viewports history
if ( infoElement . tagName ( ) = = " history " )
{
// clear history
m_viewportHistory . clear ( ) ;
// append old viewports
QDomNode historyNode = infoNode . firstChild ( ) ;
while ( historyNode . isElement ( ) )
{
QDomElement historyElement = historyNode . toElement ( ) ;
if ( historyElement . hasAttribute ( " viewport " ) )
{
QString vpString = historyElement . attribute ( " viewport " ) ;
m_viewportIterator = m_viewportHistory . insert ( m_viewportHistory . end ( ) ,
DocumentViewport ( vpString ) ) ;
}
historyNode = historyNode . nextSibling ( ) ;
}
// consistancy check
if ( m_viewportHistory . isEmpty ( ) )
m_viewportIterator = m_viewportHistory . insert ( m_viewportHistory . end ( ) , DocumentViewport ( ) ) ;
}
2007-11-01 16:15:34 +00:00
else if ( infoElement . tagName ( ) = = " rotation " )
{
QString str = infoElement . text ( ) ;
bool ok = true ;
int newrotation = ! str . isEmpty ( ) ? ( str . toInt ( & ok ) % 4 ) : 0 ;
if ( ok & & newrotation ! = 0 )
{
setRotationInternal ( newrotation , false ) ;
}
}
2008-05-31 21:13:15 +00:00
else if ( infoElement . tagName ( ) = = " views " )
{
QDomNode viewNode = infoNode . firstChild ( ) ;
while ( viewNode . isElement ( ) )
{
QDomElement viewElement = viewNode . toElement ( ) ;
if ( viewElement . tagName ( ) = = " view " )
{
const QString viewName = viewElement . attribute ( " name " ) ;
Q_FOREACH ( View * view , m_views )
{
if ( view - > name ( ) = = viewName )
{
loadViewsInfo ( view , viewElement ) ;
break ;
}
}
}
viewNode = viewNode . nextSibling ( ) ;
}
}
2007-01-02 19:05:49 +00:00
infoNode = infoNode . nextSibling ( ) ;
}
}
2005-01-21 20:05:36 +00:00
2007-01-02 19:05:49 +00:00
topLevelNode = topLevelNode . nextSibling ( ) ;
} // </documentInfo>
2004-09-08 12:41:14 +00:00
}
2008-05-31 21:13:15 +00:00
void DocumentPrivate : : loadViewsInfo ( View * view , const QDomElement & e )
{
QDomNode viewNode = e . firstChild ( ) ;
while ( viewNode . isElement ( ) )
{
QDomElement viewElement = viewNode . toElement ( ) ;
if ( viewElement . tagName ( ) = = " zoom " )
{
const QString valueString = viewElement . attribute ( " value " ) ;
bool newzoom_ok = true ;
const double newzoom = ! valueString . isEmpty ( ) ? valueString . toDouble ( & newzoom_ok ) : 1.0 ;
if ( newzoom_ok & & newzoom ! = 0
& & view - > supportsCapability ( View : : Zoom )
2008-07-22 18:14:44 +00:00
& & ( view - > capabilityFlags ( View : : Zoom ) & ( View : : CapabilityRead | View : : CapabilitySerializable ) ) )
2008-05-31 21:13:15 +00:00
{
view - > setCapability ( View : : Zoom , newzoom ) ;
}
const QString modeString = viewElement . attribute ( " mode " ) ;
bool newmode_ok = true ;
const int newmode = ! modeString . isEmpty ( ) ? modeString . toInt ( & newmode_ok ) : 2 ;
if ( newmode_ok
& & view - > supportsCapability ( View : : ZoomModality )
2008-07-22 18:14:44 +00:00
& & ( view - > capabilityFlags ( View : : ZoomModality ) & ( View : : CapabilityRead | View : : CapabilitySerializable ) ) )
2008-05-31 21:13:15 +00:00
{
view - > setCapability ( View : : ZoomModality , newmode ) ;
}
}
viewNode = viewNode . nextSibling ( ) ;
}
}
void DocumentPrivate : : saveViewsInfo ( View * view , QDomElement & e ) const
{
if ( view - > supportsCapability ( View : : Zoom )
2008-07-22 18:14:44 +00:00
& & ( view - > capabilityFlags ( View : : Zoom ) & ( View : : CapabilityRead | View : : CapabilitySerializable ) )
2008-05-31 21:13:15 +00:00
& & view - > supportsCapability ( View : : ZoomModality )
2008-07-22 18:14:44 +00:00
& & ( view - > capabilityFlags ( View : : ZoomModality ) & ( View : : CapabilityRead | View : : CapabilitySerializable ) ) )
2008-05-31 21:13:15 +00:00
{
QDomElement zoomEl = e . ownerDocument ( ) . createElement ( " zoom " ) ;
e . appendChild ( zoomEl ) ;
bool ok = true ;
const double zoom = view - > capability ( View : : Zoom ) . toDouble ( & ok ) ;
if ( ok & & zoom ! = 0 )
{
2009-11-17 19:37:57 +00:00
zoomEl . setAttribute ( " value " , QString : : number ( zoom ) ) ;
2008-05-31 21:13:15 +00:00
}
const int mode = view - > capability ( View : : ZoomModality ) . toInt ( & ok ) ;
if ( ok )
{
zoomEl . setAttribute ( " mode " , mode ) ;
}
}
}
2007-05-24 22:52:29 +00:00
QString DocumentPrivate : : giveAbsolutePath ( const QString & fileName ) const
2005-01-15 01:08:35 +00:00
{
2007-05-21 19:51:30 +00:00
if ( ! QDir : : isRelativePath ( fileName ) )
return fileName ;
2008-05-22 10:23:41 +00:00
if ( ! m_url . isValid ( ) )
return QString ( ) ;
2007-01-02 19:05:49 +00:00
return m_url . upUrl ( ) . url ( ) + fileName ;
- 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-04-14 19:44:07 +00:00
bool DocumentPrivate : : openRelativeFile ( const QString & fileName )
2004-12-05 22:47:32 +00:00
{
2007-01-02 19:05:49 +00:00
QString absFileName = giveAbsolutePath ( fileName ) ;
if ( absFileName . isEmpty ( ) )
return false ;
2004-12-11 17:25:03 +00:00
2007-07-31 10:19:48 +00:00
kDebug ( OkularDebug ) . nospace ( ) < < " openDocument: ' " < < absFileName < < " ' " ;
2004-12-05 22:47:32 +00:00
2007-01-02 19:05:49 +00:00
emit m_parent - > openUrl ( absFileName ) ;
return true ;
2005-06-13 15:46:23 +00:00
}
2007-12-02 20:57:24 +00:00
Generator * DocumentPrivate : : loadGeneratorLibrary ( const KService : : Ptr & service )
2007-01-28 15:46:10 +00:00
{
2007-12-02 20:57:24 +00:00
KPluginFactory * factory = KPluginLoader ( service - > library ( ) ) . factory ( ) ;
if ( ! factory )
2007-01-28 15:46:10 +00:00
{
2007-12-02 20:57:24 +00:00
kWarning ( OkularDebug ) . nospace ( ) < < " Invalid plugin factory for " < < service - > library ( ) < < " ! " ;
2007-01-28 15:46:10 +00:00
return 0 ;
}
2008-12-12 00:16:20 +00:00
Generator * generator = factory - > create < Okular : : Generator > ( service - > pluginKeyword ( ) , 0 ) ;
2007-12-02 20:57:24 +00:00
GeneratorInfo info ( factory - > componentData ( ) ) ;
2007-01-28 15:46:10 +00:00
info . generator = generator ;
2007-12-02 20:57:24 +00:00
if ( info . data . isValid ( ) & & info . data . aboutData ( ) )
info . catalogName = info . data . aboutData ( ) - > catalogName ( ) ;
m_loadedGenerators . insert ( service - > name ( ) , info ) ;
2007-01-28 15:46:10 +00:00
return generator ;
}
2007-04-14 19:44:07 +00:00
void DocumentPrivate : : loadAllGeneratorLibraries ( )
2007-01-28 15:46:10 +00:00
{
if ( m_generatorsLoaded )
return ;
m_generatorsLoaded = true ;
QString constraint ( " ([X-KDE-Priority] > 0) and ( exist Library ) " ) ;
KService : : List offers = KServiceTypeTrader : : self ( ) - > query ( " okular/Generator " , constraint ) ;
2007-01-28 16:10:12 +00:00
loadServiceList ( offers ) ;
}
2007-04-14 19:44:07 +00:00
void DocumentPrivate : : loadServiceList ( const KService : : List & offers )
2007-01-28 16:10:12 +00:00
{
2007-01-28 15:46:10 +00:00
int count = offers . count ( ) ;
if ( count < = 0 )
return ;
for ( int i = 0 ; i < count ; + + i )
{
QString propName = offers . at ( i ) - > name ( ) ;
// don't load already loaded generators
2007-02-03 23:09:40 +00:00
QHash < QString , GeneratorInfo > : : const_iterator genIt = m_loadedGenerators . constFind ( propName ) ;
2008-11-11 18:48:40 +00:00
if ( ! m_loadedGenerators . isEmpty ( ) & & genIt ! = m_loadedGenerators . constEnd ( ) )
2007-01-28 15:46:10 +00:00
continue ;
2007-12-02 20:57:24 +00:00
Generator * g = loadGeneratorLibrary ( offers . at ( i ) ) ;
2007-01-28 15:46:10 +00:00
( void ) g ;
}
}
2007-04-14 19:44:07 +00:00
void DocumentPrivate : : unloadGenerator ( const GeneratorInfo & info )
2007-01-30 12:43:43 +00:00
{
delete info . generator ;
}
2007-04-14 19:44:07 +00:00
void DocumentPrivate : : cacheExportFormats ( )
2007-03-10 20:51:50 +00:00
{
if ( m_exportCached )
return ;
const ExportFormat : : List formats = m_generator - > exportFormats ( ) ;
for ( int i = 0 ; i < formats . count ( ) ; + + i )
{
if ( formats . at ( i ) . mimeType ( ) - > name ( ) = = QLatin1String ( " text/plain " ) )
m_exportToText = formats . at ( i ) ;
else
m_exportFormats . append ( formats . at ( i ) ) ;
}
m_exportCached = true ;
}
2007-11-25 12:49:30 +00:00
ConfigInterface * DocumentPrivate : : generatorConfig ( GeneratorInfo & info )
{
if ( info . configChecked )
return info . config ;
info . config = qobject_cast < Okular : : ConfigInterface * > ( info . generator ) ;
info . configChecked = true ;
return info . config ;
}
2008-03-11 23:40:59 +00:00
SaveInterface * DocumentPrivate : : generatorSave ( GeneratorInfo & info )
{
if ( info . saveChecked )
return info . save ;
info . save = qobject_cast < Okular : : SaveInterface * > ( info . generator ) ;
info . saveChecked = true ;
return info . save ;
}
2014-05-09 17:56:16 +00:00
Document : : OpenResult DocumentPrivate : : openDocumentInternal ( const KService : : Ptr & offer , bool isstdin , const QString & docFile , const QByteArray & filedata , const QString & password )
2008-11-09 14:21:20 +00:00
{
QString propName = offer - > name ( ) ;
QHash < QString , GeneratorInfo > : : const_iterator genIt = m_loadedGenerators . constFind ( propName ) ;
QString catalogName ;
if ( genIt ! = m_loadedGenerators . constEnd ( ) )
{
m_generator = genIt . value ( ) . generator ;
catalogName = genIt . value ( ) . catalogName ;
}
else
{
m_generator = loadGeneratorLibrary ( offer ) ;
if ( ! m_generator )
2014-05-09 17:56:16 +00:00
return Document : : OpenError ;
2008-11-09 14:21:20 +00:00
genIt = m_loadedGenerators . constFind ( propName ) ;
Q_ASSERT ( genIt ! = m_loadedGenerators . constEnd ( ) ) ;
catalogName = genIt . value ( ) . catalogName ;
}
Q_ASSERT_X ( m_generator , " Document::load() " , " null generator?! " ) ;
if ( ! catalogName . isEmpty ( ) )
KGlobal : : locale ( ) - > insertCatalog ( catalogName ) ;
m_generator - > d_func ( ) - > m_document = this ;
// connect error reporting signals
2011-07-31 19:22:04 +00:00
QObject : : connect ( m_generator , SIGNAL ( error ( QString , int ) ) , m_parent , SIGNAL ( error ( QString , int ) ) ) ;
QObject : : connect ( m_generator , SIGNAL ( warning ( QString , int ) ) , m_parent , SIGNAL ( warning ( QString , int ) ) ) ;
QObject : : connect ( m_generator , SIGNAL ( notice ( QString , int ) ) , m_parent , SIGNAL ( notice ( QString , int ) ) ) ;
2008-11-09 14:21:20 +00:00
QApplication : : setOverrideCursor ( Qt : : WaitCursor ) ;
2014-01-13 00:15:55 +00:00
2014-05-15 18:18:22 +00:00
const QSizeF dpi = Utils : : realDpi ( m_widget ) ;
kDebug ( ) < < " Output DPI: " < < dpi ;
m_generator - > setDPI ( dpi ) ;
2014-01-13 00:15:55 +00:00
2014-05-09 17:56:16 +00:00
Document : : OpenResult openResult = Document : : OpenError ;
2008-11-09 14:21:20 +00:00
if ( ! isstdin )
{
2014-05-09 17:56:16 +00:00
openResult = m_generator - > loadDocumentWithPassword ( docFile , m_pagesVector , password ) ;
2008-11-09 14:21:20 +00:00
}
else if ( ! filedata . isEmpty ( ) )
{
if ( m_generator - > hasFeature ( Generator : : ReadRawData ) )
{
2014-05-09 17:56:16 +00:00
openResult = m_generator - > loadDocumentFromDataWithPassword ( filedata , m_pagesVector , password ) ;
2008-11-09 14:21:20 +00:00
}
else
{
m_tempFile = new KTemporaryFile ( ) ;
if ( ! m_tempFile - > open ( ) )
{
delete m_tempFile ;
m_tempFile = 0 ;
}
else
{
m_tempFile - > write ( filedata ) ;
QString tmpFileName = m_tempFile - > fileName ( ) ;
m_tempFile - > close ( ) ;
2014-05-09 17:56:16 +00:00
openResult = m_generator - > loadDocumentWithPassword ( tmpFileName , m_pagesVector , password ) ;
2008-11-09 14:21:20 +00:00
}
}
}
QApplication : : restoreOverrideCursor ( ) ;
2014-05-09 17:56:16 +00:00
if ( openResult ! = Document : : OpenSuccess | | m_pagesVector . size ( ) < = 0 )
2008-11-09 14:21:20 +00:00
{
2014-08-08 22:52:15 +00:00
# pragma("KF5: FIXME load translations")
// if ( !catalogName.isEmpty() )
// KGlobal::locale()->removeCatalog( catalogName );
2008-11-09 14:21:20 +00:00
m_generator - > d_func ( ) - > m_document = 0 ;
QObject : : disconnect ( m_generator , 0 , m_parent , 0 ) ;
m_generator = 0 ;
qDeleteAll ( m_pagesVector ) ;
m_pagesVector . clear ( ) ;
delete m_tempFile ;
m_tempFile = 0 ;
2009-01-03 10:17:15 +00:00
// TODO: emit a message telling the document is empty
2014-05-09 17:56:16 +00:00
if ( openResult = = Document : : OpenSuccess )
openResult = Document : : OpenError ;
2008-11-09 14:21:20 +00:00
}
2014-05-09 17:56:16 +00:00
return openResult ;
2008-11-09 14:21:20 +00:00
}
2008-11-15 14:15:31 +00:00
bool DocumentPrivate : : savePageDocumentInfo ( KTemporaryFile * infoFile , int what ) const
{
if ( infoFile - > open ( ) )
{
// 1. Create DOM
QDomDocument doc ( " documentInfo " ) ;
QDomProcessingInstruction xmlPi = doc . createProcessingInstruction (
QString : : fromLatin1 ( " xml " ) , QString : : fromLatin1 ( " version= \" 1.0 \" encoding= \" utf-8 \" " ) ) ;
doc . appendChild ( xmlPi ) ;
QDomElement root = doc . createElement ( " documentInfo " ) ;
doc . appendChild ( root ) ;
// 2.1. Save page attributes (bookmark state, annotations, ... ) to DOM
QDomElement pageList = doc . createElement ( " pageList " ) ;
root . appendChild ( pageList ) ;
// <page list><page number='x'>.... </page> save pages that hold data
QVector < Page * > : : const_iterator pIt = m_pagesVector . constBegin ( ) , pEnd = m_pagesVector . constEnd ( ) ;
for ( ; pIt ! = pEnd ; + + pIt )
( * pIt ) - > d - > saveLocalContents ( pageList , doc , PageItems ( what ) ) ;
// 3. Save DOM to XML file
QString xml = doc . toString ( ) ;
QTextStream os ( infoFile ) ;
os . setCodec ( " UTF-8 " ) ;
os < < xml ;
return true ;
}
return false ;
}
2009-05-13 14:24:30 +00:00
DocumentViewport DocumentPrivate : : nextDocumentViewport ( ) const
{
DocumentViewport ret = m_nextDocumentViewport ;
if ( ! m_nextDocumentDestination . isEmpty ( ) & & m_generator )
{
2011-11-01 21:13:20 +00:00
DocumentViewport vp ( m_generator - > metaData ( " NamedViewport " , m_nextDocumentDestination ) . toString ( ) ) ;
2009-05-13 14:24:30 +00:00
if ( vp . isValid ( ) )
{
ret = vp ;
}
}
return ret ;
}
2012-05-14 13:51:58 +00:00
void DocumentPrivate : : warnLimitedAnnotSupport ( )
{
if ( ! m_showWarningLimitedAnnotSupport )
return ;
m_showWarningLimitedAnnotSupport = false ; // Show the warning once
2012-05-30 16:38:51 +00:00
if ( m_annotationsNeedSaveAs )
2012-05-14 13:51:58 +00:00
{
2012-06-13 21:06:12 +00:00
// Shown if the user is editing annotations in a file whose metadata is
// not stored locally (.okular archives belong to this category)
2014-05-09 17:56:16 +00:00
KMessageBox : : information ( m_widget , i18n ( " Your annotation changes will not be saved automatically. Use File -> Save As... \n or your changes will be lost once the document is closed " ) , QString ( ) , " annotNeedSaveAs " ) ;
2012-05-14 13:51:58 +00:00
}
2012-06-13 21:06:12 +00:00
else if ( ! canAddAnnotationsNatively ( ) )
2012-05-14 13:51:58 +00:00
{
2012-06-13 21:06:12 +00:00
// If the generator doesn't support native annotations
2014-05-09 17:56:16 +00:00
KMessageBox : : information ( m_widget , i18n ( " Your annotations are saved internally by Okular. \n You can export the annotated document using File -> Export As -> Document Archive " ) , QString ( ) , " annotExportAsArchive " ) ;
2012-05-14 13:51:58 +00:00
}
}
2013-04-05 22:22:48 +00:00
void DocumentPrivate : : performAddPageAnnotation ( int page , Annotation * annotation )
{
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( m_generator ) ;
AnnotationProxy * proxy = iface ? iface - > annotationProxy ( ) : 0 ;
// find out the page to attach annotation
Page * kp = m_pagesVector [ page ] ;
if ( ! m_generator | | ! kp )
return ;
// the annotation belongs already to a page
if ( annotation - > d_ptr - > m_page )
return ;
// add annotation to the page
kp - > addAnnotation ( annotation ) ;
// tell the annotation proxy
if ( proxy & & proxy - > supports ( AnnotationProxy : : Addition ) )
proxy - > notifyAddition ( annotation , page ) ;
// notify observers about the change
notifyAnnotationChanges ( page ) ;
if ( annotation - > flags ( ) & Annotation : : ExternallyDrawn )
{
// Redraw everything, including ExternallyDrawn annotations
refreshPixmaps ( page ) ;
}
warnLimitedAnnotSupport ( ) ;
}
void DocumentPrivate : : performRemovePageAnnotation ( int page , Annotation * annotation )
{
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( m_generator ) ;
AnnotationProxy * proxy = iface ? iface - > annotationProxy ( ) : 0 ;
bool isExternallyDrawn ;
// find out the page
Page * kp = m_pagesVector [ page ] ;
if ( ! m_generator | | ! kp )
return ;
if ( annotation - > flags ( ) & Annotation : : ExternallyDrawn )
isExternallyDrawn = true ;
else
isExternallyDrawn = false ;
// try to remove the annotation
if ( m_parent - > canRemovePageAnnotation ( annotation ) )
{
// tell the annotation proxy
if ( proxy & & proxy - > supports ( AnnotationProxy : : Removal ) )
proxy - > notifyRemoval ( annotation , page ) ;
kp - > removeAnnotation ( annotation ) ; // Also destroys the object
// in case of success, notify observers about the change
notifyAnnotationChanges ( page ) ;
if ( isExternallyDrawn )
{
// Redraw everything, including ExternallyDrawn annotations
refreshPixmaps ( page ) ;
}
}
warnLimitedAnnotSupport ( ) ;
}
void DocumentPrivate : : performModifyPageAnnotation ( int page , Annotation * annotation , bool appearanceChanged )
{
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( m_generator ) ;
AnnotationProxy * proxy = iface ? iface - > annotationProxy ( ) : 0 ;
// find out the page
Page * kp = m_pagesVector [ page ] ;
if ( ! m_generator | | ! kp )
return ;
// tell the annotation proxy
if ( proxy & & proxy - > supports ( AnnotationProxy : : Modification ) )
{
proxy - > notifyModification ( annotation , page , appearanceChanged ) ;
}
// notify observers about the change
notifyAnnotationChanges ( page ) ;
if ( appearanceChanged & & ( annotation - > flags ( ) & Annotation : : ExternallyDrawn ) )
{
/* When an annotation is being moved, the generator will not render it.
* Therefore there ' s no need to refresh pixmaps after the first time */
if ( annotation - > flags ( ) & Annotation : : BeingMoved )
{
if ( m_annotationBeingMoved )
return ;
else // First time: take note
m_annotationBeingMoved = true ;
}
else
{
m_annotationBeingMoved = false ;
}
// Redraw everything, including ExternallyDrawn annotations
kDebug ( OkularDebug ) < < " Refreshing Pixmaps " ;
refreshPixmaps ( page ) ;
}
// If the user is moving the annotation, don't steal the focus
if ( ( annotation - > flags ( ) & Annotation : : BeingMoved ) = = 0 )
warnLimitedAnnotSupport ( ) ;
}
void DocumentPrivate : : performSetAnnotationContents ( const QString & newContents , Annotation * annot , int pageNumber )
{
bool appearanceChanged = false ;
2013-05-14 07:37:00 +00:00
// Check if appearanceChanged should be true
2013-04-05 22:22:48 +00:00
switch ( annot - > subType ( ) )
{
// If it's an in-place TextAnnotation, set the inplace text
case Okular : : Annotation : : AText :
{
Okular : : TextAnnotation * txtann = static_cast < Okular : : TextAnnotation * > ( annot ) ;
if ( txtann - > textType ( ) = = Okular : : TextAnnotation : : InPlace )
{
appearanceChanged = true ;
}
break ;
}
// If it's a LineAnnotation, check if caption text is visible
case Okular : : Annotation : : ALine :
{
Okular : : LineAnnotation * lineann = static_cast < Okular : : LineAnnotation * > ( annot ) ;
if ( lineann - > showCaption ( ) )
appearanceChanged = true ;
break ;
}
default :
break ;
}
// Set contents
annot - > setContents ( newContents ) ;
// Tell the document the annotation has been modified
performModifyPageAnnotation ( pageNumber , annot , appearanceChanged ) ;
}
2007-04-14 19:44:07 +00:00
void DocumentPrivate : : saveDocumentInfo ( ) const
2006-05-28 16:54:54 +00:00
{
2008-01-01 16:22:29 +00:00
if ( m_xmlFileName . isEmpty ( ) )
2007-01-02 19:05:49 +00:00
return ;
2006-05-28 16:54:54 +00:00
2007-01-02 19:05:49 +00:00
QFile infoFile ( m_xmlFileName ) ;
if ( infoFile . open ( QIODevice : : WriteOnly | QIODevice : : Truncate ) )
{
// 1. Create DOM
QDomDocument doc ( " documentInfo " ) ;
2008-07-30 10:57:08 +00:00
QDomProcessingInstruction xmlPi = doc . createProcessingInstruction (
QString : : fromLatin1 ( " xml " ) , QString : : fromLatin1 ( " version= \" 1.0 \" encoding= \" utf-8 \" " ) ) ;
doc . appendChild ( xmlPi ) ;
2007-01-02 19:05:49 +00:00
QDomElement root = doc . createElement ( " documentInfo " ) ;
2007-09-03 17:53:45 +00:00
root . setAttribute ( " url " , m_url . pathOrUrl ( ) ) ;
2007-01-02 19:05:49 +00:00
doc . appendChild ( root ) ;
2004-12-05 22:47:32 +00:00
2007-01-02 19:05:49 +00:00
// 2.1. Save page attributes (bookmark state, annotations, ... ) to DOM
QDomElement pageList = doc . createElement ( " pageList " ) ;
root . appendChild ( pageList ) ;
2012-05-14 13:51:58 +00:00
PageItems saveWhat = AllPageItems ;
2012-05-30 16:38:51 +00:00
if ( m_annotationsNeedSaveAs )
{
/* In this case, if the user makes a modification, he's requested to
* save to a new document . Therefore , if there are existing local
* annotations , we save them back unmodified in the original
* document ' s metadata , so that it appears that it was not changed */
saveWhat | = OriginalAnnotationPageItems ;
}
2007-01-02 19:05:49 +00:00
// <page list><page number='x'>.... </page> save pages that hold data
2008-11-11 18:48:40 +00:00
QVector < Page * > : : const_iterator pIt = m_pagesVector . constBegin ( ) , pEnd = m_pagesVector . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; pIt ! = pEnd ; + + pIt )
2012-05-14 13:51:58 +00:00
( * pIt ) - > d - > saveLocalContents ( pageList , doc , saveWhat ) ;
2005-01-09 23:37:07 +00:00
2007-01-02 19:05:49 +00:00
// 2.2. Save document info (current viewport, history, ... ) to DOM
QDomElement generalInfo = doc . createElement ( " generalInfo " ) ;
root . appendChild ( generalInfo ) ;
2007-11-01 16:15:34 +00:00
// create rotation node
if ( m_rotation ! = Rotation0 )
{
QDomElement rotationNode = doc . createElement ( " rotation " ) ;
generalInfo . appendChild ( rotationNode ) ;
rotationNode . appendChild ( doc . createTextNode ( QString : : number ( ( int ) m_rotation ) ) ) ;
}
2007-07-23 17:12:20 +00:00
// <general info><history> ... </history> save history up to OKULAR_HISTORY_SAVEDSTEPS viewports
2007-01-02 19:05:49 +00:00
QLinkedList < DocumentViewport > : : const_iterator backIterator = m_viewportIterator ;
2008-11-11 18:48:40 +00:00
if ( backIterator ! = m_viewportHistory . constEnd ( ) )
2007-01-02 19:05:49 +00:00
{
2007-07-23 17:12:20 +00:00
// go back up to OKULAR_HISTORY_SAVEDSTEPS steps from the current viewportIterator
int backSteps = OKULAR_HISTORY_SAVEDSTEPS ;
2008-11-11 18:48:40 +00:00
while ( backSteps - - & & backIterator ! = m_viewportHistory . constBegin ( ) )
2007-01-02 19:05:49 +00:00
- - backIterator ;
2006-06-23 21:11:52 +00:00
2007-01-02 19:05:49 +00:00
// create history root node
QDomElement historyNode = doc . createElement ( " history " ) ;
generalInfo . appendChild ( historyNode ) ;
2006-06-23 21:11:52 +00:00
2007-01-02 19:05:49 +00:00
// add old[backIterator] and present[viewportIterator] items
QLinkedList < DocumentViewport > : : const_iterator endIt = m_viewportIterator ;
+ + endIt ;
while ( backIterator ! = endIt )
{
QString name = ( backIterator = = m_viewportIterator ) ? " current " : " oldPage " ;
QDomElement historyEntry = doc . createElement ( name ) ;
historyEntry . setAttribute ( " viewport " , ( * backIterator ) . toString ( ) ) ;
historyNode . appendChild ( historyEntry ) ;
+ + backIterator ;
}
}
2008-05-31 21:13:15 +00:00
// create views root node
QDomElement viewsNode = doc . createElement ( " views " ) ;
generalInfo . appendChild ( viewsNode ) ;
Q_FOREACH ( View * view , m_views )
{
QDomElement viewEntry = doc . createElement ( " view " ) ;
viewEntry . setAttribute ( " name " , view - > name ( ) ) ;
viewsNode . appendChild ( viewEntry ) ;
saveViewsInfo ( view , viewEntry ) ;
}
2004-12-05 22:47:32 +00:00
2007-01-02 19:05:49 +00:00
// 3. Save DOM to XML file
QString xml = doc . toString ( ) ;
QTextStream os ( & infoFile ) ;
2008-07-30 10:57:08 +00:00
os . setCodec ( " UTF-8 " ) ;
2007-01-02 19:05:49 +00:00
os < < xml ;
}
infoFile . close ( ) ;
2004-12-05 22:47:32 +00:00
}
2007-04-14 19:44:07 +00:00
void DocumentPrivate : : slotTimedMemoryCheck ( )
2005-06-13 17:39:58 +00:00
{
2007-01-02 19:05:49 +00:00
// [MEM] clean memory (for 'free mem dependant' profiles only)
2012-10-15 22:27:42 +00:00
if ( SettingsCore : : memoryLevel ( ) ! = SettingsCore : : EnumMemoryLevel : : Low & &
2007-01-02 19:05:49 +00:00
m_allocatedPixmapsTotalMemory > 1024 * 1024 )
cleanupPixmapMemory ( ) ;
2005-06-13 17:39:58 +00:00
}
2012-09-25 09:09:34 +00:00
void DocumentPrivate : : sendGeneratorPixmapRequest ( )
2004-09-09 13:25:40 +00:00
{
2012-07-02 06:22:51 +00:00
/* If the pixmap cache will have to be cleaned in order to make room for the
* next request , get the distance from the current viewport of the page
* whose pixmap will be removed . We will ignore preload requests for pages
* that are at the same distance or farther */
const qulonglong memoryToFree = calculateMemoryToFree ( ) ;
const int currentViewportPage = ( * m_viewportIterator ) . pageNumber ;
int maxDistance = INT_MAX ; // Default: No maximum
if ( memoryToFree )
{
2012-11-08 13:58:08 +00:00
AllocatedPixmap * pixmapToReplace = searchLowestPriorityPixmap ( true ) ;
2012-07-02 06:22:51 +00:00
if ( pixmapToReplace )
maxDistance = qAbs ( pixmapToReplace - > page - currentViewportPage ) ;
}
2007-01-02 19:05:49 +00:00
// find a request
PixmapRequest * request = 0 ;
2007-05-12 21:40:38 +00:00
m_pixmapRequestsMutex . lock ( ) ;
2007-01-02 19:05:49 +00:00
while ( ! m_pixmapRequestsStack . isEmpty ( ) & & ! request )
{
PixmapRequest * r = m_pixmapRequestsStack . last ( ) ;
if ( ! r )
2012-08-19 19:00:15 +00:00
{
2007-01-02 19:05:49 +00:00
m_pixmapRequestsStack . pop_back ( ) ;
2012-08-19 19:00:15 +00:00
continue ;
}
2012-08-24 16:32:39 +00:00
QRect requestRect = r - > isTile ( ) ? r - > normalizedRect ( ) . geometry ( r - > width ( ) , r - > height ( ) ) : QRect ( 0 , 0 , r - > width ( ) , r - > height ( ) ) ;
2014-02-19 22:40:43 +00:00
TilesManager * tilesManager = r - > d - > tilesManager ( ) ;
2005-06-24 16:45:25 +00:00
2013-06-23 16:42:56 +00:00
// If it's a preload but the generator is not threaded no point in trying to preload
2013-06-23 16:45:09 +00:00
if ( r - > preload ( ) & & ! m_generator - > hasFeature ( Generator : : Threaded ) )
2013-06-23 16:42:56 +00:00
{
m_pixmapRequestsStack . pop_back ( ) ;
delete r ;
}
// request only if page isn't already present and request has valid id
2013-02-24 21:58:53 +00:00
// request only if page isn't already present and request has valid id
2013-06-23 16:45:09 +00:00
else if ( ( ! r - > d - > mForce & & r - > page ( ) - > hasPixmap ( r - > observer ( ) , r - > width ( ) , r - > height ( ) , r - > normalizedRect ( ) ) ) | | ! m_observers . contains ( r - > observer ( ) ) )
2007-01-02 19:05:49 +00:00
{
m_pixmapRequestsStack . pop_back ( ) ;
delete r ;
}
2013-02-24 21:58:53 +00:00
else if ( ! r - > d - > mForce & & r - > preload ( ) & & qAbs ( r - > pageNumber ( ) - currentViewportPage ) > = maxDistance )
2007-01-02 19:05:49 +00:00
{
m_pixmapRequestsStack . pop_back ( ) ;
2012-08-15 14:44:22 +00:00
//kDebug() << "Ignoring request that doesn't fit in cache";
2007-01-02 19:05:49 +00:00
delete r ;
}
2012-11-08 12:02:33 +00:00
// Ignore requests for pixmaps that are already being generated
2012-09-25 01:01:47 +00:00
else if ( tilesManager & & tilesManager - > isRequesting ( r - > normalizedRect ( ) , r - > width ( ) , r - > height ( ) ) )
{
m_pixmapRequestsStack . pop_back ( ) ;
delete r ;
}
2012-11-08 12:02:33 +00:00
// If the requested area is above 8000000 pixels, switch on the tile manager
2014-02-19 22:40:43 +00:00
else if ( ! tilesManager & & m_generator - > hasFeature ( Generator : : TiledRendering ) & & ( long ) r - > width ( ) * ( long ) r - > height ( ) > 8000000L )
2012-07-12 05:20:03 +00:00
{
// if the image is too big. start using tiles
2012-11-08 12:02:33 +00:00
kDebug ( OkularDebug ) . nospace ( ) < < " Start using tiles on page " < < r - > pageNumber ( )
2012-07-12 05:20:03 +00:00
< < " ( " < < r - > width ( ) < < " x " < < r - > height ( ) < < " px); " ;
// fill the tiles manager with the last rendered pixmap
2013-02-24 21:58:53 +00:00
const QPixmap * pixmap = r - > page ( ) - > _o_nearestPixmap ( r - > observer ( ) , r - > width ( ) , r - > height ( ) ) ;
2012-07-12 05:20:03 +00:00
if ( pixmap )
{
2012-11-08 13:58:08 +00:00
tilesManager = new TilesManager ( r - > pageNumber ( ) , pixmap - > width ( ) , pixmap - > height ( ) , r - > page ( ) - > rotation ( ) ) ;
2012-09-25 01:01:47 +00:00
tilesManager - > setPixmap ( pixmap , NormalizedRect ( 0 , 0 , 1 , 1 ) ) ;
2012-11-11 19:56:39 +00:00
tilesManager - > setSize ( r - > width ( ) , r - > height ( ) ) ;
2012-07-12 05:20:03 +00:00
}
else
{
// create new tiles manager
2012-11-08 13:58:08 +00:00
tilesManager = new TilesManager ( r - > pageNumber ( ) , r - > width ( ) , r - > height ( ) , r - > page ( ) - > rotation ( ) ) ;
2012-07-12 05:20:03 +00:00
}
2012-10-18 04:24:06 +00:00
tilesManager - > setRequest ( r - > normalizedRect ( ) , r - > width ( ) , r - > height ( ) ) ;
2013-02-24 21:58:53 +00:00
r - > page ( ) - > deletePixmap ( r - > observer ( ) ) ;
2014-02-19 22:40:43 +00:00
r - > page ( ) - > d - > setTilesManager ( r - > observer ( ) , tilesManager ) ;
2012-08-24 16:32:39 +00:00
r - > setTile ( true ) ;
2012-07-12 05:20:03 +00:00
2012-08-26 19:01:07 +00:00
// Change normalizedRect to the smallest rect that contains all
// visible tiles.
if ( ! r - > normalizedRect ( ) . isNull ( ) )
{
NormalizedRect tilesRect ;
2012-11-12 14:55:13 +00:00
const QList < Tile > tiles = tilesManager - > tilesAt ( r - > normalizedRect ( ) , TilesManager : : TerminalTile ) ;
2012-08-26 19:01:07 +00:00
QList < Tile > : : const_iterator tIt = tiles . constBegin ( ) , tEnd = tiles . constEnd ( ) ;
while ( tIt ! = tEnd )
{
Tile tile = * tIt ;
if ( tilesRect . isNull ( ) )
2012-11-08 15:41:00 +00:00
tilesRect = tile . rect ( ) ;
2012-08-26 19:01:07 +00:00
else
2012-11-08 15:41:00 +00:00
tilesRect | = tile . rect ( ) ;
2012-08-26 19:01:07 +00:00
+ + tIt ;
}
r - > setNormalizedRect ( tilesRect ) ;
2012-12-08 19:02:01 +00:00
request = r ;
}
else
{
2012-12-12 22:27:51 +00:00
// Discard request if normalizedRect is null. This happens in
// preload requests issued by PageView if the requested page is
// not visible and the user has just switched from a non-tiled
// zoom level to a tiled one
2012-12-08 19:02:01 +00:00
m_pixmapRequestsStack . pop_back ( ) ;
delete r ;
2012-08-26 19:01:07 +00:00
}
2012-07-12 05:20:03 +00:00
}
2012-11-08 12:02:33 +00:00
// If the requested area is below 6000000 pixels, switch off the tile manager
2012-07-12 05:20:03 +00:00
else if ( tilesManager & & ( long ) r - > width ( ) * ( long ) r - > height ( ) < 6000000L )
{
2012-11-08 12:02:33 +00:00
kDebug ( OkularDebug ) . nospace ( ) < < " Stop using tiles on page " < < r - > pageNumber ( )
2012-07-12 05:20:03 +00:00
< < " ( " < < r - > width ( ) < < " x " < < r - > height ( ) < < " px); " ;
// page is too small. stop using tiles.
2013-02-24 21:58:53 +00:00
r - > page ( ) - > deletePixmap ( r - > observer ( ) ) ;
2012-08-24 16:32:39 +00:00
r - > setTile ( false ) ;
2012-07-12 05:20:03 +00:00
request = r ;
}
2012-08-18 21:06:43 +00:00
else if ( ( long ) requestRect . width ( ) * ( long ) requestRect . height ( ) > 20000000L )
2007-01-02 19:05:49 +00:00
{
m_pixmapRequestsStack . pop_back ( ) ;
if ( ! m_warnedOutOfMemory )
{
2007-11-25 12:18:10 +00:00
kWarning ( OkularDebug ) . nospace ( ) < < " Running out of memory on page " < < r - > pageNumber ( )
2007-07-31 10:19:48 +00:00
< < " ( " < < r - > width ( ) < < " x " < < r - > height ( ) < < " px); " ;
2007-11-25 12:18:10 +00:00
kWarning ( OkularDebug ) < < " this message will be reported only once. " ;
2007-01-02 19:05:49 +00:00
m_warnedOutOfMemory = true ;
}
delete r ;
}
else
2012-07-02 06:22:51 +00:00
{
2007-01-02 19:05:49 +00:00
request = r ;
2012-07-02 06:22:51 +00:00
}
2007-01-02 19:05:49 +00:00
}
2005-07-20 22:28:23 +00:00
2007-01-02 19:05:49 +00:00
// if no request found (or already generated), return
if ( ! request )
2007-05-12 21:40:38 +00:00
{
m_pixmapRequestsMutex . unlock ( ) ;
2007-01-02 19:05:49 +00:00
return ;
2007-05-12 21:40:38 +00:00
}
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
2007-01-02 19:05:49 +00:00
// [MEM] preventive memory freeing
2012-07-16 15:57:51 +00:00
qulonglong pixmapBytes = 0 ;
2014-02-19 22:40:43 +00:00
TilesManager * tm = request - > d - > tilesManager ( ) ;
2012-07-16 15:57:51 +00:00
if ( tm )
pixmapBytes = tm - > totalMemory ( ) ;
else
pixmapBytes = 4 * request - > width ( ) * request - > height ( ) ;
2007-01-02 19:05:49 +00:00
if ( pixmapBytes > ( 1024 * 1024 ) )
2012-07-02 06:22:51 +00:00
cleanupPixmapMemory ( memoryToFree /* previously calculated value */ ) ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
2007-01-02 19:05:49 +00:00
// submit the request to the generator
2007-01-31 18:31:19 +00:00
if ( m_generator - > canGeneratePixmap ( ) )
2007-01-02 19:05:49 +00:00
{
2012-08-24 16:32:39 +00:00
QRect requestRect = ! request - > isTile ( ) ? QRect ( 0 , 0 , request - > width ( ) , request - > height ( ) ) : request - > normalizedRect ( ) . geometry ( request - > width ( ) , request - > height ( ) ) ;
2013-02-24 21:58:53 +00:00
kDebug ( OkularDebug ) . nospace ( ) < < " sending request observer= " < < request - > observer ( ) < < " " < < requestRect . width ( ) < < " x " < < requestRect . height ( ) < < " @ " < < request - > pageNumber ( ) < < " async == " < < request - > asynchronous ( ) < < " isTile == " < < request - > isTile ( ) ;
2007-01-02 19:05:49 +00:00
m_pixmapRequestsStack . removeAll ( request ) ;
2006-10-25 15:35:53 +00:00
2012-09-25 01:01:47 +00:00
if ( tm )
tm - > setRequest ( request - > normalizedRect ( ) , request - > width ( ) , request - > height ( ) ) ;
2007-01-05 17:09:47 +00:00
if ( ( int ) m_rotation % 2 )
2007-12-04 21:36:32 +00:00
request - > d - > swap ( ) ;
2006-10-25 15:35:53 +00:00
2012-08-17 17:25:58 +00:00
if ( m_rotation ! = Rotation0 & & ! request - > normalizedRect ( ) . isNull ( ) )
request - > setNormalizedRect ( TilesManager : : fromRotatedRect (
request - > normalizedRect ( ) , m_rotation ) ) ;
2007-05-12 21:40:38 +00:00
// we always have to unlock _before_ the generatePixmap() because
// a sync generation would end with requestDone() -> deadlock, and
// we can not really know if the generator can do async requests
2008-02-01 00:43:45 +00:00
m_executingPixmapRequests . push_back ( request ) ;
2007-05-12 21:40:38 +00:00
m_pixmapRequestsMutex . unlock ( ) ;
2007-01-31 18:31:19 +00:00
m_generator - > generatePixmap ( request ) ;
2007-01-02 19:05:49 +00:00
}
else
2007-05-12 21:40:38 +00:00
{
m_pixmapRequestsMutex . unlock ( ) ;
2007-01-02 19:05:49 +00:00
// pino (7/4/2006): set the polling interval from 10 to 30
2012-09-25 09:09:34 +00:00
QTimer : : singleShot ( 30 , m_parent , SLOT ( sendGeneratorPixmapRequest ( ) ) ) ;
2007-05-12 21:40:38 +00:00
}
2006-07-01 22:17:53 +00:00
}
2009-06-30 17:21:55 +00:00
void DocumentPrivate : : rotationFinished ( int page , Okular : : Page * okularPage )
2006-07-01 22:17:53 +00:00
{
2009-06-30 17:21:55 +00:00
Okular : : Page * wantedPage = m_pagesVector . value ( page , 0 ) ;
if ( ! wantedPage | | wantedPage ! = okularPage )
return ;
2013-02-24 21:58:53 +00:00
foreach ( DocumentObserver * o , m_observers )
o - > notifyPageChanged ( page , DocumentObserver : : Pixmap | DocumentObserver : : Annotations ) ;
2006-07-01 22:17:53 +00:00
}
2007-07-07 20:35:01 +00:00
void DocumentPrivate : : fontReadingProgress ( int page )
{
emit m_parent - > fontReadingProgress ( page ) ;
2007-12-28 17:06:43 +00:00
if ( page > = ( int ) m_parent - > pages ( ) - 1 )
2007-07-07 20:35:01 +00:00
{
emit m_parent - > fontReadingEnded ( ) ;
m_fontThread = 0 ;
m_fontsCached = true ;
}
}
void DocumentPrivate : : fontReadingGotFont ( const Okular : : FontInfo & font )
{
// TODO try to avoid duplicate fonts
m_fontsCache . append ( font ) ;
emit m_parent - > gotFont ( font ) ;
}
2007-07-12 20:04:56 +00:00
void DocumentPrivate : : slotGeneratorConfigChanged ( const QString & )
{
if ( ! m_generator )
return ;
// reparse generator config and if something changed clear Pages
bool configchanged = false ;
2007-11-25 12:49:30 +00:00
QHash < QString , GeneratorInfo > : : iterator it = m_loadedGenerators . begin ( ) , itEnd = m_loadedGenerators . end ( ) ;
2007-07-12 20:04:56 +00:00
for ( ; it ! = itEnd ; + + it )
{
2007-11-25 12:49:30 +00:00
Okular : : ConfigInterface * iface = generatorConfig ( it . value ( ) ) ;
2007-07-12 20:04:56 +00:00
if ( iface )
{
bool it_changed = iface - > reparseConfig ( ) ;
if ( it_changed & & ( m_generator = = it . value ( ) . generator ) )
configchanged = true ;
}
}
if ( configchanged )
{
// invalidate pixmaps
2008-11-11 18:48:40 +00:00
QVector < Page * > : : const_iterator it = m_pagesVector . constBegin ( ) , end = m_pagesVector . constEnd ( ) ;
2007-07-12 20:04:56 +00:00
for ( ; it ! = end ; + + it ) {
( * it ) - > deletePixmaps ( ) ;
}
// [MEM] remove allocation descriptors
2012-07-01 23:05:02 +00:00
qDeleteAll ( m_allocatedPixmaps ) ;
m_allocatedPixmaps . clear ( ) ;
2007-07-12 20:04:56 +00:00
m_allocatedPixmapsTotalMemory = 0 ;
// send reload signals to observers
foreachObserverD ( notifyContentsCleared ( DocumentObserver : : Pixmap ) ) ;
}
// free memory if in 'low' profile
2012-10-15 22:27:42 +00:00
if ( SettingsCore : : memoryLevel ( ) = = SettingsCore : : EnumMemoryLevel : : Low & &
2012-07-01 23:05:02 +00:00
! m_allocatedPixmaps . isEmpty ( ) & & ! m_pagesVector . isEmpty ( ) )
2007-07-12 20:04:56 +00:00
cleanupPixmapMemory ( ) ;
}
2008-03-07 15:50:48 +00:00
void DocumentPrivate : : refreshPixmaps ( int pageNumber )
{
Page * page = m_pagesVector . value ( pageNumber , 0 ) ;
if ( ! page )
return ;
QLinkedList < Okular : : PixmapRequest * > requestedPixmaps ;
2013-02-24 21:58:53 +00:00
QMap < DocumentObserver * , PagePrivate : : PixmapObject > : : ConstIterator it = page - > d - > m_pixmaps . constBegin ( ) , itEnd = page - > d - > m_pixmaps . constEnd ( ) ;
2008-03-07 15:50:48 +00:00
for ( ; it ! = itEnd ; + + it )
{
QSize size = ( * it ) . m_pixmap - > size ( ) ;
2013-02-24 21:58:53 +00:00
PixmapRequest * p = new PixmapRequest ( it . key ( ) , pageNumber , size . width ( ) , size . height ( ) , 1 , PixmapRequest : : Asynchronous ) ;
2008-03-07 15:50:48 +00:00
p - > d - > mForce = true ;
requestedPixmaps . push_back ( p ) ;
}
2012-10-25 12:16:17 +00:00
2014-02-19 22:40:43 +00:00
foreach ( DocumentObserver * observer , m_observers )
2012-10-25 12:16:17 +00:00
{
2014-02-19 22:40:43 +00:00
TilesManager * tilesManager = page - > d - > tilesManager ( observer ) ;
if ( tilesManager )
{
tilesManager - > markDirty ( ) ;
2012-10-25 12:16:17 +00:00
2014-02-19 22:40:43 +00:00
PixmapRequest * p = new PixmapRequest ( observer , pageNumber , tilesManager - > width ( ) , tilesManager - > height ( ) , 1 , PixmapRequest : : Asynchronous ) ;
2012-10-25 12:16:17 +00:00
2014-02-19 22:40:43 +00:00
NormalizedRect tilesRect ;
2012-11-08 13:58:08 +00:00
2014-02-19 22:40:43 +00:00
// Get the visible page rect
NormalizedRect visibleRect ;
QVector < Okular : : VisiblePageRect * > : : const_iterator vIt = m_pageRects . constBegin ( ) , vEnd = m_pageRects . constEnd ( ) ;
for ( ; vIt ! = vEnd ; + + vIt )
2012-11-08 13:58:08 +00:00
{
2014-02-19 22:40:43 +00:00
if ( ( * vIt ) - > pageNumber = = pageNumber )
{
visibleRect = ( * vIt ) - > rect ;
break ;
}
2012-11-08 13:58:08 +00:00
}
2012-10-25 12:16:17 +00:00
2014-02-19 22:40:43 +00:00
if ( ! visibleRect . isNull ( ) )
{
p - > setNormalizedRect ( visibleRect ) ;
p - > setTile ( true ) ;
p - > d - > mForce = true ;
requestedPixmaps . push_back ( p ) ;
}
else
{
delete p ;
}
2012-10-25 12:16:17 +00:00
}
}
2014-02-19 22:40:43 +00:00
2008-03-07 15:50:48 +00:00
if ( ! requestedPixmaps . isEmpty ( ) )
m_parent - > requestPixmaps ( requestedPixmaps , Okular : : Document : : NoOption ) ;
}
2008-05-04 15:02:35 +00:00
void DocumentPrivate : : _o_configChanged ( )
{
2008-05-04 15:10:32 +00:00
// free text pages if needed
calculateMaxTextPages ( ) ;
while ( m_allocatedTextPagesFifo . count ( ) > m_maxAllocatedTextPages )
{
int pageToKick = m_allocatedTextPagesFifo . takeFirst ( ) ;
m_pagesVector . at ( pageToKick ) - > setTextPage ( 0 ) ; // deletes the textpage
}
2008-05-04 15:02:35 +00:00
}
2012-09-24 22:14:10 +00:00
void DocumentPrivate : : doContinueDirectionMatchSearch ( void * doContinueDirectionMatchSearchStruct )
2007-08-13 22:25:27 +00:00
{
2012-09-24 22:14:10 +00:00
DoContinueDirectionMatchSearchStruct * searchStruct = static_cast < DoContinueDirectionMatchSearchStruct * > ( doContinueDirectionMatchSearchStruct ) ;
RunningSearch * search = m_searches . value ( searchStruct - > searchID ) ;
2007-08-13 22:25:27 +00:00
2012-09-24 22:14:10 +00:00
if ( ( m_searchCancelled & & ! searchStruct - > match ) | | ! search )
2007-08-13 22:25:27 +00:00
{
// if the user cancelled but he just got a match, give him the match!
QApplication : : restoreOverrideCursor ( ) ;
2009-08-10 22:28:54 +00:00
2009-11-06 00:19:10 +00:00
if ( search ) search - > isCurrentlySearching = false ;
2009-08-10 22:28:54 +00:00
2012-09-24 22:14:10 +00:00
emit m_parent - > searchFinished ( searchStruct - > searchID , Document : : SearchCancelled ) ;
delete searchStruct - > pagesToNotify ;
delete searchStruct ;
2007-08-13 22:25:27 +00:00
return ;
}
2014-05-09 22:49:01 +00:00
const bool forward = search - > cachedType = = Document : : NextMatch ;
2012-09-25 10:53:35 +00:00
bool doContinue = false ;
2007-08-13 22:25:27 +00:00
// if no match found, loop through the whole doc, starting from currentPage
2012-09-24 22:14:10 +00:00
if ( ! searchStruct - > match )
2007-08-13 22:25:27 +00:00
{
2012-09-24 22:14:10 +00:00
const int pageCount = m_pagesVector . count ( ) ;
2014-05-10 09:33:21 +00:00
if ( search - > pagesDone < pageCount )
2007-08-13 22:25:27 +00:00
{
2012-09-25 10:53:35 +00:00
doContinue = true ;
2012-09-24 22:14:10 +00:00
if ( searchStruct - > currentPage > = pageCount | | searchStruct - > currentPage < 0 )
2007-08-13 22:25:27 +00:00
{
2014-05-10 09:33:21 +00:00
doContinue = false ;
search - > isCurrentlySearching = false ;
search - > continueOnPage = forward ? 0 : pageCount - 1 ;
search - > continueOnMatch = RegularAreaRect ( ) ;
emit m_parent - > searchFinished ( searchStruct - > searchID , Document : : EndOfDocumentReached ) ;
2007-08-13 22:25:27 +00:00
}
}
}
2012-09-25 10:53:35 +00:00
if ( doContinue )
{
// get page
Page * page = m_pagesVector [ searchStruct - > currentPage ] ;
// request search page if needed
if ( ! page - > hasTextPage ( ) )
m_parent - > requestTextPage ( page - > number ( ) ) ;
2012-09-26 21:28:58 +00:00
// if found a match on the current page, end the loop
2014-05-09 22:49:01 +00:00
searchStruct - > match = page - > findText ( searchStruct - > searchID , search - > cachedString , forward ? FromTop : FromBottom , search - > cachedCaseSensitivity ) ;
2012-09-26 21:28:58 +00:00
if ( ! searchStruct - > match )
{
2014-05-09 22:49:01 +00:00
if ( forward ) searchStruct - > currentPage + + ;
2012-09-26 21:28:58 +00:00
else searchStruct - > currentPage - - ;
2014-05-10 09:33:21 +00:00
search - > pagesDone + + ;
2012-09-25 10:53:35 +00:00
}
else
{
2014-05-10 09:33:21 +00:00
search - > pagesDone = 1 ;
2007-08-13 22:25:27 +00:00
}
2013-04-05 22:22:48 +00:00
2012-09-26 21:28:58 +00:00
// Both of the previous if branches need to call doContinueDirectionMatchSearch
QMetaObject : : invokeMethod ( m_parent , " doContinueDirectionMatchSearch " , Qt : : QueuedConnection , Q_ARG ( void * , searchStruct ) ) ;
2007-08-13 22:25:27 +00:00
}
2012-09-25 10:53:35 +00:00
else
{
2014-05-09 22:49:01 +00:00
doProcessSearchMatch ( searchStruct - > match , search , searchStruct - > pagesToNotify , searchStruct - > currentPage , searchStruct - > searchID , search - > cachedViewportMove , search - > cachedColor ) ;
2012-09-25 10:53:35 +00:00
delete searchStruct ;
}
2010-04-15 22:26:58 +00:00
}
void DocumentPrivate : : doProcessSearchMatch ( RegularAreaRect * match , RunningSearch * search , QSet < int > * pagesToNotify , int currentPage , int searchID , bool moveViewport , const QColor & color )
{
2007-08-13 22:25:27 +00:00
// reset cursor to previous shape
QApplication : : restoreOverrideCursor ( ) ;
bool foundAMatch = false ;
2009-11-06 00:19:10 +00:00
search - > isCurrentlySearching = false ;
2009-08-10 22:28:54 +00:00
2007-08-13 22:25:27 +00:00
// if a match has been found..
if ( match )
{
// update the RunningSearch structure adding this match..
foundAMatch = true ;
2009-11-06 00:19:10 +00:00
search - > continueOnPage = currentPage ;
search - > continueOnMatch = * match ;
search - > highlightedPages . insert ( currentPage ) ;
2007-08-13 22:25:27 +00:00
// ..add highlight to the page..
m_pagesVector [ currentPage ] - > d - > setHighlight ( searchID , match , color ) ;
// ..queue page for notifying changes..
pagesToNotify - > insert ( currentPage ) ;
2013-12-29 22:27:30 +00:00
// Create a normalized rectangle around the search match that includes a 5% buffer on all sides.
const Okular : : NormalizedRect matchRectWithBuffer = Okular : : NormalizedRect ( match - > first ( ) . left - 0.05 ,
match - > first ( ) . top - 0.05 ,
match - > first ( ) . right + 0.05 ,
match - > first ( ) . bottom + 0.05 ) ;
const bool matchRectFullyVisible = isNormalizedRectangleFullyVisible ( matchRectWithBuffer , currentPage ) ;
2007-08-13 22:25:27 +00:00
// ..move the viewport to show the first of the searched word sequence centered
2013-12-29 22:27:30 +00:00
if ( moveViewport & & ! matchRectFullyVisible )
2007-08-13 22:25:27 +00:00
{
DocumentViewport searchViewport ( currentPage ) ;
searchViewport . rePos . enabled = true ;
searchViewport . rePos . normalizedX = ( match - > first ( ) . left + match - > first ( ) . right ) / 2.0 ;
searchViewport . rePos . normalizedY = ( match - > first ( ) . top + match - > first ( ) . bottom ) / 2.0 ;
2013-02-24 21:58:53 +00:00
m_parent - > setViewport ( searchViewport , 0 , true ) ;
2007-08-13 22:25:27 +00:00
}
delete match ;
}
// notify observers about highlights changes
foreach ( int pageNumber , * pagesToNotify )
foreach ( DocumentObserver * observer , m_observers )
observer - > notifyPageChanged ( pageNumber , DocumentObserver : : Highlights ) ;
2007-08-23 22:16:37 +00:00
if ( foundAMatch ) emit m_parent - > searchFinished ( searchID , Document : : MatchFound ) ;
else emit m_parent - > searchFinished ( searchID , Document : : NoMatchFound ) ;
2007-08-13 22:25:27 +00:00
delete pagesToNotify ;
}
2014-05-09 22:49:01 +00:00
void DocumentPrivate : : doContinueAllDocumentSearch ( void * pagesToNotifySet , void * pageMatchesMap , int currentPage , int searchID )
2007-08-13 22:25:27 +00:00
{
QMap < Page * , QVector < RegularAreaRect * > > * pageMatches = static_cast < QMap < Page * , QVector < RegularAreaRect * > > * > ( pageMatchesMap ) ;
QSet < int > * pagesToNotify = static_cast < QSet < int > * > ( pagesToNotifySet ) ;
2009-11-06 00:19:10 +00:00
RunningSearch * search = m_searches . value ( searchID ) ;
2007-08-13 22:25:27 +00:00
2009-11-06 00:19:10 +00:00
if ( m_searchCancelled | | ! search )
2007-08-13 22:25:27 +00:00
{
typedef QVector < RegularAreaRect * > MatchesVector ;
QApplication : : restoreOverrideCursor ( ) ;
2009-08-10 22:28:54 +00:00
2009-11-06 00:19:10 +00:00
if ( search ) search - > isCurrentlySearching = false ;
2009-08-10 22:28:54 +00:00
2007-08-23 22:16:37 +00:00
emit m_parent - > searchFinished ( searchID , Document : : SearchCancelled ) ;
2007-08-13 22:25:27 +00:00
foreach ( const MatchesVector & mv , * pageMatches ) qDeleteAll ( mv ) ;
delete pageMatches ;
delete pagesToNotify ;
return ;
}
if ( currentPage < m_pagesVector . count ( ) )
{
// get page (from the first to the last)
Page * page = m_pagesVector . at ( currentPage ) ;
int pageNumber = page - > number ( ) ; // redundant? is it == currentPage ?
// request search page if needed
if ( ! page - > hasTextPage ( ) )
m_parent - > requestTextPage ( pageNumber ) ;
// loop on a page adding highlights for all found items
RegularAreaRect * lastMatch = 0 ;
while ( 1 )
{
if ( lastMatch )
2014-05-09 22:49:01 +00:00
lastMatch = page - > findText ( searchID , search - > cachedString , NextResult , search - > cachedCaseSensitivity , lastMatch ) ;
2007-08-13 22:25:27 +00:00
else
2014-05-09 22:49:01 +00:00
lastMatch = page - > findText ( searchID , search - > cachedString , FromTop , search - > cachedCaseSensitivity ) ;
2007-08-13 22:25:27 +00:00
if ( ! lastMatch )
break ;
// add highligh rect to the matches map
( * pageMatches ) [ page ] . append ( lastMatch ) ;
}
delete lastMatch ;
2014-05-09 22:49:01 +00:00
QMetaObject : : invokeMethod ( m_parent , " doContinueAllDocumentSearch " , Qt : : QueuedConnection , Q_ARG ( void * , pagesToNotifySet ) , Q_ARG ( void * , pageMatches ) , Q_ARG ( int , currentPage + 1 ) , Q_ARG ( int , searchID ) ) ;
2007-08-13 22:25:27 +00:00
}
else
{
// reset cursor to previous shape
QApplication : : restoreOverrideCursor ( ) ;
2009-11-06 00:19:10 +00:00
search - > isCurrentlySearching = false ;
2007-08-13 22:25:27 +00:00
bool foundAMatch = pageMatches - > count ( ) ! = 0 ;
QMap < Page * , QVector < RegularAreaRect * > > : : const_iterator it , itEnd ;
2008-11-11 18:48:40 +00:00
it = pageMatches - > constBegin ( ) ;
itEnd = pageMatches - > constEnd ( ) ;
2007-08-13 22:25:27 +00:00
for ( ; it ! = itEnd ; + + it )
{
foreach ( RegularAreaRect * match , it . value ( ) )
{
2014-05-09 22:49:01 +00:00
it . key ( ) - > d - > setHighlight ( searchID , match , search - > cachedColor ) ;
2007-08-13 22:25:27 +00:00
delete match ;
}
2009-11-06 00:19:10 +00:00
search - > highlightedPages . insert ( it . key ( ) - > number ( ) ) ;
2007-08-13 22:25:27 +00:00
pagesToNotify - > insert ( it . key ( ) - > number ( ) ) ;
}
foreach ( DocumentObserver * observer , m_observers )
2007-09-09 10:50:36 +00:00
observer - > notifySetup ( m_pagesVector , 0 ) ;
2007-08-13 22:25:27 +00:00
// notify observers about highlights changes
foreach ( int pageNumber , * pagesToNotify )
foreach ( DocumentObserver * observer , m_observers )
observer - > notifyPageChanged ( pageNumber , DocumentObserver : : Highlights ) ;
2007-08-23 22:16:37 +00:00
if ( foundAMatch ) emit m_parent - > searchFinished ( searchID , Document : : MatchFound ) ;
else emit m_parent - > searchFinished ( searchID , Document : : NoMatchFound ) ;
2007-08-13 22:25:27 +00:00
delete pageMatches ;
delete pagesToNotify ;
}
}
2014-05-09 22:49:01 +00:00
void DocumentPrivate : : doContinueGooglesDocumentSearch ( void * pagesToNotifySet , void * pageMatchesMap , int currentPage , int searchID , const QStringList & words )
2007-08-13 22:25:27 +00:00
{
typedef QPair < RegularAreaRect * , QColor > MatchColor ;
QMap < Page * , QVector < MatchColor > > * pageMatches = static_cast < QMap < Page * , QVector < MatchColor > > * > ( pageMatchesMap ) ;
QSet < int > * pagesToNotify = static_cast < QSet < int > * > ( pagesToNotifySet ) ;
2009-11-06 00:19:10 +00:00
RunningSearch * search = m_searches . value ( searchID ) ;
2007-08-13 22:25:27 +00:00
2009-11-06 00:19:10 +00:00
if ( m_searchCancelled | | ! search )
2007-08-13 22:25:27 +00:00
{
typedef QVector < MatchColor > MatchesVector ;
QApplication : : restoreOverrideCursor ( ) ;
2009-08-10 22:28:54 +00:00
2009-11-06 00:19:10 +00:00
if ( search ) search - > isCurrentlySearching = false ;
2009-08-10 22:28:54 +00:00
2007-08-23 22:16:37 +00:00
emit m_parent - > searchFinished ( searchID , Document : : SearchCancelled ) ;
2007-08-13 22:25:27 +00:00
foreach ( const MatchesVector & mv , * pageMatches )
{
foreach ( const MatchColor & mc , mv ) delete mc . first ;
}
delete pageMatches ;
delete pagesToNotify ;
return ;
}
const int wordCount = words . count ( ) ;
const int hueStep = ( wordCount > 1 ) ? ( 60 / ( wordCount - 1 ) ) : 60 ;
int baseHue , baseSat , baseVal ;
2014-05-09 22:49:01 +00:00
search - > cachedColor . getHsv ( & baseHue , & baseSat , & baseVal ) ;
2007-08-13 22:25:27 +00:00
if ( currentPage < m_pagesVector . count ( ) )
{
// get page (from the first to the last)
Page * page = m_pagesVector . at ( currentPage ) ;
int pageNumber = page - > number ( ) ; // redundant? is it == currentPage ?
// request search page if needed
if ( ! page - > hasTextPage ( ) )
m_parent - > requestTextPage ( pageNumber ) ;
// loop on a page adding highlights for all found items
bool allMatched = wordCount > 0 ,
anyMatched = false ;
for ( int w = 0 ; w < wordCount ; w + + )
{
const QString & word = words [ w ] ;
int newHue = baseHue - w * hueStep ;
if ( newHue < 0 )
newHue + = 360 ;
QColor wordColor = QColor : : fromHsv ( newHue , baseSat , baseVal ) ;
RegularAreaRect * lastMatch = 0 ;
// add all highlights for current word
bool wordMatched = false ;
while ( 1 )
{
if ( lastMatch )
2014-05-09 22:49:01 +00:00
lastMatch = page - > findText ( searchID , word , NextResult , search - > cachedCaseSensitivity , lastMatch ) ;
2007-08-13 22:25:27 +00:00
else
2014-05-09 22:49:01 +00:00
lastMatch = page - > findText ( searchID , word , FromTop , search - > cachedCaseSensitivity ) ;
2007-08-13 22:25:27 +00:00
if ( ! lastMatch )
break ;
// add highligh rect to the matches map
( * pageMatches ) [ page ] . append ( MatchColor ( lastMatch , wordColor ) ) ;
wordMatched = true ;
}
allMatched = allMatched & & wordMatched ;
anyMatched = anyMatched | | wordMatched ;
}
// if not all words are present in page, remove partial highlights
2014-05-09 22:49:01 +00:00
const bool matchAll = search - > cachedType = = Document : : GoogleAll ;
2007-08-13 22:25:27 +00:00
if ( ! allMatched & & matchAll )
{
QVector < MatchColor > & matches = ( * pageMatches ) [ page ] ;
foreach ( const MatchColor & mc , matches ) delete mc . first ;
pageMatches - > remove ( page ) ;
}
2014-05-09 22:49:01 +00:00
QMetaObject : : invokeMethod ( m_parent , " doContinueGooglesDocumentSearch " , Qt : : QueuedConnection , Q_ARG ( void * , pagesToNotifySet ) , Q_ARG ( void * , pageMatches ) , Q_ARG ( int , currentPage + 1 ) , Q_ARG ( int , searchID ) , Q_ARG ( QStringList , words ) ) ;
2007-08-13 22:25:27 +00:00
}
else
{
// reset cursor to previous shape
QApplication : : restoreOverrideCursor ( ) ;
2009-11-06 00:19:10 +00:00
search - > isCurrentlySearching = false ;
2007-08-13 22:25:27 +00:00
bool foundAMatch = pageMatches - > count ( ) ! = 0 ;
QMap < Page * , QVector < MatchColor > > : : const_iterator it , itEnd ;
2008-11-11 18:48:40 +00:00
it = pageMatches - > constBegin ( ) ;
itEnd = pageMatches - > constEnd ( ) ;
2007-08-13 22:25:27 +00:00
for ( ; it ! = itEnd ; + + it )
{
foreach ( const MatchColor & mc , it . value ( ) )
{
it . key ( ) - > d - > setHighlight ( searchID , mc . first , mc . second ) ;
delete mc . first ;
}
2009-11-06 00:19:10 +00:00
search - > highlightedPages . insert ( it . key ( ) - > number ( ) ) ;
2007-08-13 22:25:27 +00:00
pagesToNotify - > insert ( it . key ( ) - > number ( ) ) ;
}
// send page lists to update observers (since some filter on bookmarks)
foreach ( DocumentObserver * observer , m_observers )
2007-09-09 10:50:36 +00:00
observer - > notifySetup ( m_pagesVector , 0 ) ;
2007-08-13 22:25:27 +00:00
// notify observers about highlights changes
foreach ( int pageNumber , * pagesToNotify )
foreach ( DocumentObserver * observer , m_observers )
observer - > notifyPageChanged ( pageNumber , DocumentObserver : : Highlights ) ;
2007-08-23 22:16:37 +00:00
if ( foundAMatch ) emit m_parent - > searchFinished ( searchID , Document : : MatchFound ) ;
else emit m_parent - > searchFinished ( searchID , Document : : NoMatchFound ) ;
2007-08-13 22:25:27 +00:00
delete pageMatches ;
delete pagesToNotify ;
}
}
2007-09-14 22:16:00 +00:00
QVariant DocumentPrivate : : documentMetaData ( const QString & key , const QVariant & option ) const
{
if ( key = = QLatin1String ( " PaperColor " ) )
{
bool giveDefault = option . toBool ( ) ;
// load paper color from Settings, or use the default color (white)
// if we were told to do so
QColor color ;
2012-10-15 22:27:42 +00:00
if ( ( SettingsCore : : renderMode ( ) = = SettingsCore : : EnumRenderMode : : Paper )
& & SettingsCore : : changeColors ( ) )
2007-09-14 22:16:00 +00:00
{
2012-10-15 22:27:42 +00:00
color = SettingsCore : : paperColor ( ) ;
2007-09-14 22:16:00 +00:00
}
else if ( giveDefault )
{
color = Qt : : white ;
}
return color ;
}
2007-12-16 23:36:12 +00:00
else if ( key = = QLatin1String ( " TextAntialias " ) )
{
2012-10-15 22:27:42 +00:00
switch ( SettingsCore : : textAntialias ( ) )
2008-01-05 15:50:40 +00:00
{
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumTextAntialias : : Enabled :
2008-01-05 15:50:40 +00:00
return true ;
break ;
#if 0
case Settings : : EnumTextAntialias : : UseKDESettings :
// TODO: read the KDE configuration
return true ;
break ;
# endif
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumTextAntialias : : Disabled :
2008-01-05 15:50:40 +00:00
return false ;
break ;
}
2007-12-16 23:36:12 +00:00
}
else if ( key = = QLatin1String ( " GraphicsAntialias " ) )
{
2012-10-15 22:27:42 +00:00
switch ( SettingsCore : : graphicsAntialias ( ) )
2008-01-05 15:50:40 +00:00
{
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumGraphicsAntialias : : Enabled :
2008-01-05 15:50:40 +00:00
return true ;
break ;
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumGraphicsAntialias : : Disabled :
2008-01-05 15:50:40 +00:00
return false ;
break ;
}
2007-12-16 23:36:12 +00:00
}
2009-10-08 21:55:51 +00:00
else if ( key = = QLatin1String ( " TextHinting " ) )
{
2012-10-15 22:27:42 +00:00
switch ( SettingsCore : : textHinting ( ) )
2009-10-08 21:55:51 +00:00
{
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumTextHinting : : Enabled :
2009-10-08 21:55:51 +00:00
return true ;
break ;
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumTextHinting : : Disabled :
2009-10-08 21:55:51 +00:00
return false ;
break ;
}
}
2007-09-14 22:16:00 +00:00
return QVariant ( ) ;
2014-03-02 12:59:49 +00:00
}
2013-04-05 22:22:48 +00:00
2013-12-29 22:27:30 +00:00
bool DocumentPrivate : : isNormalizedRectangleFullyVisible ( const Okular : : NormalizedRect & rectOfInterest , int rectPage )
{
bool rectFullyVisible = false ;
const QVector < Okular : : VisiblePageRect * > & visibleRects = m_parent - > visiblePageRects ( ) ;
QVector < Okular : : VisiblePageRect * > : : const_iterator vEnd = visibleRects . end ( ) ;
QVector < Okular : : VisiblePageRect * > : : const_iterator vIt = visibleRects . begin ( ) ;
for ( ; ( vIt ! = vEnd ) & & ! rectFullyVisible ; + + vIt )
{
if ( ( * vIt ) - > pageNumber = = rectPage & &
( * vIt ) - > rect . contains ( rectOfInterest . left , rectOfInterest . top ) & &
( * vIt ) - > rect . contains ( rectOfInterest . right , rectOfInterest . bottom ) )
{
rectFullyVisible = true ;
}
}
return rectFullyVisible ;
}
2007-03-30 17:46:50 +00:00
Document : : Document ( QWidget * widget )
2008-09-21 22:44:42 +00:00
: QObject ( 0 ) , d ( new DocumentPrivate ( this ) )
2006-07-01 22:17:53 +00:00
{
2008-09-21 22:44:42 +00:00
d - > m_widget = widget ;
2007-10-28 18:31:33 +00:00
d - > m_bookmarkManager = new BookmarkManager ( d ) ;
2007-10-04 21:41:19 +00:00
d - > m_viewportIterator = d - > m_viewportHistory . insert ( d - > m_viewportHistory . end ( ) , DocumentViewport ( ) ) ;
2013-04-05 22:22:48 +00:00
d - > m_undoStack = new QUndoStack ( this ) ;
2007-03-24 10:47:22 +00:00
2012-10-15 22:27:42 +00:00
connect ( SettingsCore : : self ( ) , SIGNAL ( configChanged ( ) ) , this , SLOT ( _o_configChanged ( ) ) ) ;
2013-04-05 22:22:48 +00:00
connect ( d - > m_undoStack , SIGNAL ( canUndoChanged ( bool ) ) , this , SIGNAL ( canUndoChanged ( bool ) ) ) ;
connect ( d - > m_undoStack , SIGNAL ( canRedoChanged ( bool ) ) , this , SIGNAL ( canRedoChanged ( bool ) ) ) ;
2007-07-07 20:35:01 +00:00
qRegisterMetaType < Okular : : FontInfo > ( ) ;
2006-07-01 22:17:53 +00:00
}
2007-01-02 19:05:49 +00:00
Document : : ~ Document ( )
2005-01-27 17:31:07 +00:00
{
2007-01-02 19:05:49 +00:00
// delete generator, pages, and related stuff
closeDocument ( ) ;
2005-01-27 17:31:07 +00:00
2008-11-11 18:48:40 +00:00
QSet < View * > : : const_iterator viewIt = d - > m_views . constBegin ( ) , viewEnd = d - > m_views . constEnd ( ) ;
2008-04-27 11:05:59 +00:00
for ( ; viewIt ! = viewEnd ; + + viewIt )
{
View * v = * viewIt ;
v - > d_func ( ) - > document = 0 ;
}
2007-02-05 15:54:19 +00:00
// delete the bookmark manager
delete d - > m_bookmarkManager ;
2007-01-28 15:46:10 +00:00
// delete the loaded generators
2007-02-03 23:09:40 +00:00
QHash < QString , GeneratorInfo > : : const_iterator it = d - > m_loadedGenerators . constBegin ( ) , itEnd = d - > m_loadedGenerators . constEnd ( ) ;
2007-01-28 15:46:10 +00:00
for ( ; it ! = itEnd ; + + it )
2007-01-30 12:43:43 +00:00
d - > unloadGenerator ( it . value ( ) ) ;
2007-01-28 15:46:10 +00:00
d - > m_loadedGenerators . clear ( ) ;
2007-01-02 19:05:49 +00:00
// delete the private structure
delete d ;
2005-01-27 17:31:07 +00:00
}
2013-08-06 20:31:13 +00:00
class kMimeTypeMoreThan {
public :
kMimeTypeMoreThan ( const KMimeType : : Ptr & mime ) : _mime ( mime ) { }
bool operator ( ) ( const KService : : Ptr & s1 , const KService : : Ptr & s2 )
{
const QString mimeName = _mime - > name ( ) ;
if ( s1 - > mimeTypes ( ) . contains ( mimeName ) & & ! s2 - > mimeTypes ( ) . contains ( mimeName ) )
return true ;
else if ( s2 - > mimeTypes ( ) . contains ( mimeName ) & & ! s1 - > mimeTypes ( ) . contains ( mimeName ) )
return false ;
return s1 - > property ( " X-KDE-Priority " ) . toInt ( ) > s2 - > property ( " X-KDE-Priority " ) . toInt ( ) ;
}
private :
const KMimeType : : Ptr & _mime ;
} ;
2004-11-09 17:20:19 +00:00
2014-05-09 17:56:16 +00:00
Document : : OpenResult Document : : openDocument ( const QString & docFile , const KUrl & url , const KMimeType : : Ptr & _mime , const QString & password )
2006-06-02 20:42:57 +00:00
{
2007-01-12 22:49:14 +00:00
KMimeType : : Ptr mime = _mime ;
QByteArray filedata ;
2007-09-30 10:49:38 +00:00
qint64 document_size = - 1 ;
2007-01-12 22:49:14 +00:00
bool isstdin = url . fileName ( KUrl : : ObeyTrailingSlash ) = = QLatin1String ( " - " ) ;
2013-04-17 20:13:02 +00:00
bool triedMimeFromFileContent = false ;
2007-01-12 22:49:14 +00:00
if ( ! isstdin )
2007-01-02 19:05:49 +00:00
{
2014-08-08 22:53:01 +00:00
if ( mime - > allMimeTypes ( ) . count ( ) < = 0 )
2014-05-09 17:56:16 +00:00
return OpenError ;
2007-01-12 22:49:14 +00:00
2011-05-05 20:51:05 +00:00
// docFile is always local so we can use QFileInfo on it
QFileInfo fileReadTest ( docFile ) ;
if ( fileReadTest . isFile ( ) & & ! fileReadTest . isReadable ( ) )
2007-01-12 22:49:14 +00:00
{
d - > m_docFileName . clear ( ) ;
2014-05-09 17:56:16 +00:00
return OpenError ;
2007-01-12 22:49:14 +00:00
}
// determine the related "xml document-info" filename
d - > m_url = url ;
d - > m_docFileName = docFile ;
2008-11-15 14:15:31 +00:00
if ( url . isLocalFile ( ) & & ! d - > m_archiveData )
2008-01-01 16:22:29 +00:00
{
2013-04-17 19:02:32 +00:00
QString fn = url . fileName ( ) ;
document_size = fileReadTest . size ( ) ;
fn = QString : : number ( document_size ) + ' . ' + fn + " .xml " ;
QString newokular = " okular/docdata/ " + fn ;
QString newokularfile = KStandardDirs : : locateLocal ( " data " , newokular ) ;
if ( ! QFile : : exists ( newokularfile ) )
2007-09-10 17:20:58 +00:00
{
2013-04-17 19:02:32 +00:00
QString oldkpdf = " kpdf/ " + fn ;
QString oldkpdffile = KStandardDirs : : locateLocal ( " data " , oldkpdf ) ;
if ( QFile : : exists ( oldkpdffile ) )
{
// ### copy or move?
if ( ! QFile : : copy ( oldkpdffile , newokularfile ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2013-04-17 19:02:32 +00:00
}
2007-09-10 17:20:58 +00:00
}
2013-04-17 19:02:32 +00:00
d - > m_xmlFileName = newokularfile ;
2008-01-01 16:22:29 +00:00
}
2007-01-12 22:49:14 +00:00
}
else
{
QFile qstdin ;
qstdin . open ( stdin , QIODevice : : ReadOnly ) ;
filedata = qstdin . readAll ( ) ;
mime = KMimeType : : findByContent ( filedata ) ;
if ( ! mime | | mime - > name ( ) = = QLatin1String ( " application/octet-stream " ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2007-07-10 23:49:37 +00:00
document_size = filedata . size ( ) ;
2013-04-17 20:13:02 +00:00
triedMimeFromFileContent = true ;
2007-01-02 19:05:49 +00:00
}
2007-01-02 22:37:55 +00:00
2007-01-02 19:05:49 +00:00
// 0. load Generator
// request only valid non-disabled plugins suitable for the mimetype
QString constraint ( " ([X-KDE-Priority] > 0) and ( exist Library ) " ) ;
KService : : List offers = KMimeTypeTrader : : self ( ) - > query ( mime - > name ( ) , " okular/Generator " , constraint ) ;
2013-04-17 20:13:02 +00:00
if ( offers . isEmpty ( ) & & ! triedMimeFromFileContent )
2008-11-09 14:21:20 +00:00
{
KMimeType : : Ptr newmime = KMimeType : : findByFileContent ( docFile ) ;
2013-04-17 20:13:02 +00:00
triedMimeFromFileContent = true ;
2009-10-19 00:20:18 +00:00
if ( newmime - > name ( ) ! = mime - > name ( ) )
2008-11-09 14:21:20 +00:00
{
mime = newmime ;
offers = KMimeTypeTrader : : self ( ) - > query ( mime - > name ( ) , " okular/Generator " , constraint ) ;
}
2013-04-17 20:00:02 +00:00
if ( offers . isEmpty ( ) )
{
// There's still no offers, do a final mime search based on the filename
2013-06-24 10:46:16 +00:00
// We need this because sometimes (e.g. when downloading from a webserver) the mimetype we
// use is the one fed by the server, that may be wrong
2013-04-17 20:00:02 +00:00
newmime = KMimeType : : findByUrl ( docFile ) ;
if ( newmime - > name ( ) ! = mime - > name ( ) )
{
mime = newmime ;
offers = KMimeTypeTrader : : self ( ) - > query ( mime - > name ( ) , " okular/Generator " , constraint ) ;
}
}
2008-11-09 14:21:20 +00:00
}
2007-01-02 19:05:49 +00:00
if ( offers . isEmpty ( ) )
2006-10-15 19:37:14 +00:00
{
2008-04-11 21:16:43 +00:00
emit error ( i18n ( " Can not find a plugin which is able to handle the document being passed. " ) , - 1 ) ;
2007-11-25 12:18:10 +00:00
kWarning ( OkularDebug ) . nospace ( ) < < " No plugin for mimetype ' " < < mime - > name ( ) < < " '. " ;
2014-05-09 17:56:16 +00:00
return OpenError ;
2006-10-15 19:37:14 +00:00
}
2007-01-02 19:05:49 +00:00
int hRank = 0 ;
// best ranked offer search
2007-01-28 15:46:10 +00:00
int offercount = offers . count ( ) ;
if ( offercount > 1 )
2006-10-15 19:37:14 +00:00
{
2007-01-28 15:46:10 +00:00
// sort the offers: the offers with an higher priority come before
2013-08-06 20:31:13 +00:00
qStableSort ( offers . begin ( ) , offers . end ( ) , kMimeTypeMoreThan ( mime ) ) ;
2006-10-15 19:37:14 +00:00
2012-10-15 22:27:42 +00:00
if ( SettingsCore : : chooseGenerators ( ) )
2007-01-02 19:05:49 +00:00
{
2007-01-28 15:46:10 +00:00
QStringList list ;
for ( int i = 0 ; i < offercount ; + + i )
{
list < < offers . at ( i ) - > name ( ) ;
}
2014-05-09 17:56:16 +00:00
ChooseEngineDialog choose ( list , mime , d - > m_widget ) ;
2007-01-28 15:46:10 +00:00
if ( choose . exec ( ) = = QDialog : : Rejected )
2014-05-09 17:56:16 +00:00
return OpenError ;
2007-01-28 15:46:10 +00:00
hRank = choose . selectedGenerator ( ) ;
2007-01-02 19:05:49 +00:00
}
2005-01-27 17:31:07 +00:00
}
2004-09-15 20:45:00 +00:00
2008-11-09 14:21:20 +00:00
KService : : Ptr offer = offers . at ( hRank ) ;
// 1. load Document
2014-05-09 17:56:16 +00:00
OpenResult openResult = d - > openDocumentInternal ( offer , isstdin , docFile , filedata , password ) ;
if ( openResult = = OpenError & & ! triedMimeFromFileContent )
2007-01-12 22:49:14 +00:00
{
2008-11-09 14:21:20 +00:00
KMimeType : : Ptr newmime = KMimeType : : findByFileContent ( docFile ) ;
2013-04-17 20:13:02 +00:00
triedMimeFromFileContent = true ;
2009-10-19 00:20:18 +00:00
if ( newmime - > name ( ) ! = mime - > name ( ) )
2007-01-12 22:49:14 +00:00
{
2008-11-09 14:21:20 +00:00
mime = newmime ;
offers = KMimeTypeTrader : : self ( ) - > query ( mime - > name ( ) , " okular/Generator " , constraint ) ;
if ( ! offers . isEmpty ( ) )
2007-01-12 22:49:14 +00:00
{
2008-11-09 14:21:20 +00:00
offer = offers . first ( ) ;
2014-05-09 17:56:16 +00:00
openResult = d - > openDocumentInternal ( offer , isstdin , docFile , filedata , password ) ;
2007-01-12 22:49:14 +00:00
}
}
}
2014-05-09 17:56:16 +00:00
if ( openResult ! = OpenSuccess )
2007-01-02 19:05:49 +00:00
{
2014-05-09 17:56:16 +00:00
return openResult ;
2004-12-21 12:38:52 +00:00
}
2005-01-18 16:43:36 +00:00
2008-11-09 14:21:20 +00:00
d - > m_generatorName = offer - > name ( ) ;
2013-07-30 15:00:32 +00:00
d - > m_pageController = new PageController ( ) ;
connect ( d - > m_pageController , SIGNAL ( rotationFinished ( int , Okular : : Page * ) ) ,
this , SLOT ( rotationFinished ( int , Okular : : Page * ) ) ) ;
2012-05-30 16:38:51 +00:00
bool containsExternalAnnotations = false ;
2011-01-29 15:38:18 +00:00
foreach ( Page * p , d - > m_pagesVector )
{
p - > d - > m_doc = d ;
2012-05-14 13:51:58 +00:00
if ( ! p - > annotations ( ) . empty ( ) )
2012-05-30 16:38:51 +00:00
containsExternalAnnotations = true ;
2011-01-29 15:38:18 +00:00
}
2007-03-11 22:35:14 +00:00
2012-05-30 16:38:51 +00:00
// Be quiet while restoring local annotations
d - > m_showWarningLimitedAnnotSupport = false ;
d - > m_annotationsNeedSaveAs = false ;
2012-05-14 13:51:58 +00:00
// 2. load Additional Data (bookmarks, local annotations and metadata) about the document
2008-11-15 14:15:31 +00:00
if ( d - > m_archiveData )
{
2014-05-10 09:35:33 +00:00
d - > loadDocumentInfo ( d - > m_archiveData - > metadataFile ) ;
2012-05-30 16:38:51 +00:00
d - > m_annotationsNeedSaveAs = true ;
2008-11-15 14:15:31 +00:00
}
else
{
d - > loadDocumentInfo ( ) ;
2012-05-30 16:38:51 +00:00
d - > m_annotationsNeedSaveAs = ( d - > canAddAnnotationsNatively ( ) & & containsExternalAnnotations ) ;
2008-11-15 14:15:31 +00:00
}
2012-05-30 16:38:51 +00:00
d - > m_showWarningLimitedAnnotSupport = true ;
2007-01-02 19:05:49 +00:00
d - > m_bookmarkManager - > setUrl ( d - > m_url ) ;
2004-09-15 20:45:00 +00:00
2007-01-02 19:05:49 +00:00
// 3. setup observers inernal lists and data
2007-09-09 10:50:36 +00:00
foreachObserver ( notifySetup ( d - > m_pagesVector , DocumentObserver : : DocumentChanged ) ) ;
2004-12-10 16:04:45 +00:00
2007-01-02 19:05:49 +00:00
// 4. set initial page (restoring the page saved in xml if loaded)
DocumentViewport loadedViewport = ( * d - > m_viewportIterator ) ;
if ( loadedViewport . isValid ( ) )
{
( * d - > m_viewportIterator ) = DocumentViewport ( ) ;
if ( loadedViewport . pageNumber > = ( int ) d - > m_pagesVector . size ( ) )
loadedViewport . pageNumber = d - > m_pagesVector . size ( ) - 1 ;
}
else
loadedViewport . pageNumber = 0 ;
setViewport ( loadedViewport ) ;
2004-12-21 12:38:52 +00:00
2007-01-02 19:05:49 +00:00
// start bookmark saver timer
if ( ! d - > m_saveBookmarksTimer )
{
d - > m_saveBookmarksTimer = new QTimer ( this ) ;
2011-07-31 19:22:04 +00:00
connect ( d - > m_saveBookmarksTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( saveDocumentInfo ( ) ) ) ;
2007-01-02 19:05:49 +00:00
}
d - > m_saveBookmarksTimer - > start ( 5 * 60 * 1000 ) ;
2005-02-18 18:24:45 +00:00
2007-01-02 19:05:49 +00:00
// start memory check timer
if ( ! d - > m_memCheckTimer )
{
d - > m_memCheckTimer = new QTimer ( this ) ;
2011-07-31 19:22:04 +00:00
connect ( d - > m_memCheckTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( slotTimedMemoryCheck ( ) ) ) ;
2007-01-02 19:05:49 +00:00
}
d - > m_memCheckTimer - > start ( 2000 ) ;
2005-02-18 18:24:45 +00:00
2009-05-13 14:24:30 +00:00
const DocumentViewport nextViewport = d - > nextDocumentViewport ( ) ;
if ( nextViewport . isValid ( ) )
2007-01-02 19:05:49 +00:00
{
2009-05-13 14:24:30 +00:00
setViewport ( nextViewport ) ;
2007-01-02 19:05:49 +00:00
d - > m_nextDocumentViewport = DocumentViewport ( ) ;
2009-05-13 14:24:30 +00:00
d - > m_nextDocumentDestination = QString ( ) ;
2007-01-02 19:05:49 +00:00
}
2005-02-18 18:24:45 +00:00
2007-07-10 18:24:18 +00:00
AudioPlayer : : instance ( ) - > d - > m_currentDocument = isstdin ? KUrl ( ) : d - > m_url ;
2007-07-10 23:49:37 +00:00
d - > m_docSize = document_size ;
2007-07-10 18:24:18 +00:00
2008-04-13 22:31:59 +00:00
const QStringList docScripts = d - > m_generator - > metaData ( " DocumentScripts " , " JavaScript " ) . toStringList ( ) ;
if ( ! docScripts . isEmpty ( ) )
{
d - > m_scripter = new Scripter ( d ) ;
Q_FOREACH ( const QString & docscript , docScripts )
{
d - > m_scripter - > execute ( JavaScript , docscript ) ;
}
}
2014-05-09 17:56:16 +00:00
return OpenSuccess ;
2005-02-18 18:24:45 +00:00
}
2006-08-08 15:31:13 +00:00
2007-01-02 19:05:49 +00:00
2007-08-28 23:17:00 +00:00
KXMLGUIClient * Document : : guiClient ( )
2006-08-08 15:31:13 +00:00
{
2007-01-02 19:05:49 +00:00
if ( d - > m_generator )
2006-09-14 18:42:28 +00:00
{
2007-01-02 19:05:49 +00:00
Okular : : GuiInterface * iface = qobject_cast < Okular : : GuiInterface * > ( d - > m_generator ) ;
if ( iface )
2007-08-28 23:17:00 +00:00
return iface - > guiClient ( ) ;
2006-09-14 18:42:28 +00:00
}
2007-08-28 23:17:00 +00:00
return 0 ;
2006-08-08 15:31:13 +00:00
}
2006-11-01 15:17:22 +00:00
2007-01-02 19:05:49 +00:00
void Document : : closeDocument ( )
2006-11-01 15:17:22 +00:00
{
2007-10-03 15:03:49 +00:00
// check if there's anything to close...
if ( ! d - > m_generator )
return ;
2013-07-30 15:00:32 +00:00
delete d - > m_pageController ;
d - > m_pageController = 0 ;
2008-04-13 22:31:59 +00:00
delete d - > m_scripter ;
d - > m_scripter = 0 ;
2009-11-11 19:36:58 +00:00
// remove requests left in queue
d - > m_pixmapRequestsMutex . lock ( ) ;
QLinkedList < PixmapRequest * > : : const_iterator sIt = d - > m_pixmapRequestsStack . constBegin ( ) ;
QLinkedList < PixmapRequest * > : : const_iterator sEnd = d - > m_pixmapRequestsStack . constEnd ( ) ;
for ( ; sIt ! = sEnd ; + + sIt )
delete * sIt ;
d - > m_pixmapRequestsStack . clear ( ) ;
d - > m_pixmapRequestsMutex . unlock ( ) ;
2008-02-01 00:43:45 +00:00
QEventLoop loop ;
bool startEventLoop = false ;
do
{
d - > m_pixmapRequestsMutex . lock ( ) ;
startEventLoop = ! d - > m_executingPixmapRequests . isEmpty ( ) ;
d - > m_pixmapRequestsMutex . unlock ( ) ;
if ( startEventLoop )
{
d - > m_closingLoop = & loop ;
loop . exec ( ) ;
d - > m_closingLoop = 0 ;
}
}
while ( startEventLoop ) ;
2007-07-08 21:22:37 +00:00
if ( d - > m_fontThread )
{
disconnect ( d - > m_fontThread , 0 , this , 0 ) ;
d - > m_fontThread - > stopExtraction ( ) ;
d - > m_fontThread - > wait ( ) ;
d - > m_fontThread = 0 ;
}
2008-04-14 21:58:14 +00:00
// stop any audio playback
AudioPlayer : : instance ( ) - > stopPlaybacks ( ) ;
2007-01-02 19:05:49 +00:00
// close the current document and save document info if a document is still opened
if ( d - > m_generator & & d - > m_pagesVector . size ( ) > 0 )
{
d - > saveDocumentInfo ( ) ;
2007-07-04 09:28:31 +00:00
d - > m_generator - > closeDocument ( ) ;
2007-01-02 19:05:49 +00:00
}
2006-11-01 15:17:22 +00:00
2007-01-02 19:05:49 +00:00
// stop timers
if ( d - > m_memCheckTimer )
d - > m_memCheckTimer - > stop ( ) ;
if ( d - > m_saveBookmarksTimer )
d - > m_saveBookmarksTimer - > stop ( ) ;
if ( d - > m_generator )
2006-11-01 15:17:22 +00:00
{
2007-01-28 15:46:10 +00:00
// disconnect the generator from this document ...
2007-09-14 13:31:55 +00:00
d - > m_generator - > d_func ( ) - > m_document = 0 ;
2007-01-28 15:46:10 +00:00
// .. and this document from the generator signals
disconnect ( d - > m_generator , 0 , this , 0 ) ;
2007-03-11 22:35:14 +00:00
QHash < QString , GeneratorInfo > : : const_iterator genIt = d - > m_loadedGenerators . constFind ( d - > m_generatorName ) ;
Q_ASSERT ( genIt ! = d - > m_loadedGenerators . constEnd ( ) ) ;
2014-08-08 22:52:15 +00:00
# pragma("KF5: FIXME load translations")
// if ( !genIt.value().catalogName.isEmpty() && !genIt.value().config )
// KGlobal::locale()->removeCatalog( genIt.value().catalogName );
2006-11-01 15:17:22 +00:00
}
2007-01-02 19:05:49 +00:00
d - > m_generator = 0 ;
2007-03-11 22:35:14 +00:00
d - > m_generatorName = QString ( ) ;
2007-01-02 19:05:49 +00:00
d - > m_url = KUrl ( ) ;
2007-01-12 22:49:14 +00:00
d - > m_docFileName = QString ( ) ;
d - > m_xmlFileName = QString ( ) ;
delete d - > m_tempFile ;
d - > m_tempFile = 0 ;
2008-11-15 14:15:31 +00:00
delete d - > m_archiveData ;
d - > m_archiveData = 0 ;
2007-07-10 23:49:37 +00:00
d - > m_docSize = - 1 ;
2007-03-10 20:51:50 +00:00
d - > m_exportCached = false ;
d - > m_exportFormats . clear ( ) ;
d - > m_exportToText = ExportFormat ( ) ;
2007-07-07 20:35:01 +00:00
d - > m_fontsCached = false ;
d - > m_fontsCache . clear ( ) ;
2007-05-24 22:52:29 +00:00
d - > m_rotation = Rotation0 ;
2006-09-26 22:22:01 +00:00
2007-01-02 19:05:49 +00:00
// send an empty list to observers (to free their data)
2007-09-09 10:50:36 +00:00
foreachObserver ( notifySetup ( QVector < Page * > ( ) , DocumentObserver : : DocumentChanged ) ) ;
2006-09-26 22:22:01 +00:00
2007-01-02 19:05:49 +00:00
// delete pages and clear 'd->m_pagesVector' container
2008-11-11 18:48:40 +00:00
QVector < Page * > : : const_iterator pIt = d - > m_pagesVector . constBegin ( ) ;
QVector < Page * > : : const_iterator pEnd = d - > m_pagesVector . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; pIt ! = pEnd ; + + pIt )
delete * pIt ;
d - > m_pagesVector . clear ( ) ;
2006-09-26 22:22:01 +00:00
2007-01-02 19:05:49 +00:00
// clear 'memory allocation' descriptors
2012-07-01 23:05:02 +00:00
qDeleteAll ( d - > m_allocatedPixmaps ) ;
d - > m_allocatedPixmaps . clear ( ) ;
2006-09-26 22:22:01 +00:00
2007-01-02 19:05:49 +00:00
// clear 'running searches' descriptors
2008-11-11 18:48:40 +00:00
QMap < int , RunningSearch * > : : const_iterator rIt = d - > m_searches . constBegin ( ) ;
QMap < int , RunningSearch * > : : const_iterator rEnd = d - > m_searches . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; rIt ! = rEnd ; + + rIt )
delete * rIt ;
d - > m_searches . clear ( ) ;
2004-10-09 08:10:56 +00:00
2007-01-02 19:05:49 +00:00
// clear the visible areas and notify the observers
2008-11-11 18:48:40 +00:00
QVector < VisiblePageRect * > : : const_iterator vIt = d - > m_pageRects . constBegin ( ) ;
QVector < VisiblePageRect * > : : const_iterator vEnd = d - > m_pageRects . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; vIt ! = vEnd ; + + vIt )
delete * vIt ;
d - > m_pageRects . clear ( ) ;
foreachObserver ( notifyVisibleRectsChanged ( ) ) ;
2005-01-09 23:37:07 +00:00
2007-01-02 19:05:49 +00:00
// reset internal variables
d - > m_viewportHistory . clear ( ) ;
d - > m_viewportHistory . append ( DocumentViewport ( ) ) ;
d - > m_viewportIterator = d - > m_viewportHistory . begin ( ) ;
d - > m_allocatedPixmapsTotalMemory = 0 ;
2009-02-08 01:32:49 +00:00
d - > m_allocatedTextPagesFifo . clear ( ) ;
2007-01-05 23:12:06 +00:00
d - > m_pageSize = PageSize ( ) ;
d - > m_pageSizes . clear ( ) ;
2013-04-05 22:22:48 +00:00
2009-11-16 00:46:33 +00:00
delete d - > m_documentInfo ;
d - > m_documentInfo = 0 ;
2007-07-10 18:24:18 +00:00
AudioPlayer : : instance ( ) - > d - > m_currentDocument = KUrl ( ) ;
2013-04-13 20:54:47 +00:00
d - > m_undoStack - > clear ( ) ;
2005-01-09 23:37:07 +00:00
}
2007-01-02 19:05:49 +00:00
void Document : : addObserver ( DocumentObserver * pObserver )
2005-01-09 23:37:07 +00:00
{
2013-02-24 21:58:53 +00:00
Q_ASSERT ( ! d - > m_observers . contains ( pObserver ) ) ;
d - > m_observers < < pObserver ;
2005-01-09 23:37:07 +00:00
2007-01-02 19:05:49 +00:00
// if the observer is added while a document is already opened, tell it
if ( ! d - > m_pagesVector . isEmpty ( ) )
2005-01-27 17:31:07 +00:00
{
2007-09-09 10:50:36 +00:00
pObserver - > notifySetup ( d - > m_pagesVector , DocumentObserver : : DocumentChanged ) ;
2007-01-02 19:05:49 +00:00
pObserver - > notifyViewportChanged ( false /*disables smoothMove*/ ) ;
2005-01-27 17:31:07 +00:00
}
2007-01-02 19:05:49 +00:00
}
2005-01-27 17:31:07 +00:00
2007-01-02 19:05:49 +00:00
void Document : : removeObserver ( DocumentObserver * pObserver )
{
// remove observer from the map. it won't receive notifications anymore
2013-02-24 21:58:53 +00:00
if ( d - > m_observers . contains ( pObserver ) )
2005-01-20 17:33:05 +00:00
{
2007-01-02 19:05:49 +00:00
// free observer's pixmap data
2008-11-11 18:48:40 +00:00
QVector < Page * > : : const_iterator it = d - > m_pagesVector . constBegin ( ) , end = d - > m_pagesVector . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; it ! = end ; + + it )
2013-02-24 21:58:53 +00:00
( * it ) - > deletePixmap ( pObserver ) ;
2007-01-02 19:05:49 +00:00
// [MEM] free observer's allocation descriptors
2012-07-01 23:05:02 +00:00
QLinkedList < AllocatedPixmap * > : : iterator aIt = d - > m_allocatedPixmaps . begin ( ) ;
QLinkedList < AllocatedPixmap * > : : iterator aEnd = d - > m_allocatedPixmaps . end ( ) ;
2005-01-26 10:42:07 +00:00
while ( aIt ! = aEnd )
2005-01-20 17:33:05 +00:00
{
2007-01-02 19:05:49 +00:00
AllocatedPixmap * p = * aIt ;
2013-02-24 21:58:53 +00:00
if ( p - > observer = = pObserver )
2005-01-20 17:33:05 +00:00
{
2012-07-01 23:05:02 +00:00
aIt = d - > m_allocatedPixmaps . erase ( aIt ) ;
2007-01-02 19:05:49 +00:00
delete p ;
2005-01-20 17:33:05 +00:00
}
2007-01-02 19:05:49 +00:00
else
+ + aIt ;
2005-01-20 17:33:05 +00:00
}
2007-01-02 19:05:49 +00:00
// delete observer entry from the map
2013-02-24 21:58:53 +00:00
d - > m_observers . remove ( pObserver ) ;
2005-01-26 10:42:07 +00:00
}
2004-09-08 12:41:14 +00:00
}
2007-01-02 19:05:49 +00:00
void Document : : reparseConfig ( )
2005-01-27 17:31:07 +00:00
{
2007-01-02 19:05:49 +00:00
// reparse generator config and if something changed clear Pages
bool configchanged = false ;
if ( d - > m_generator )
2005-01-27 17:31:07 +00:00
{
2007-01-02 19:05:49 +00:00
Okular : : ConfigInterface * iface = qobject_cast < Okular : : ConfigInterface * > ( d - > m_generator ) ;
if ( iface )
configchanged = iface - > reparseConfig ( ) ;
2005-01-27 17:31:07 +00:00
}
2007-01-02 19:05:49 +00:00
if ( configchanged )
2005-01-27 17:31:07 +00:00
{
2007-01-02 19:05:49 +00:00
// invalidate pixmaps
2008-11-11 18:48:40 +00:00
QVector < Page * > : : const_iterator it = d - > m_pagesVector . constBegin ( ) , end = d - > m_pagesVector . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; it ! = end ; + + it ) {
( * it ) - > deletePixmaps ( ) ;
}
// [MEM] remove allocation descriptors
2012-07-01 23:05:02 +00:00
qDeleteAll ( d - > m_allocatedPixmaps ) ;
d - > m_allocatedPixmaps . clear ( ) ;
2007-01-02 19:05:49 +00:00
d - > m_allocatedPixmapsTotalMemory = 0 ;
// send reload signals to observers
foreachObserver ( notifyContentsCleared ( DocumentObserver : : Pixmap ) ) ;
2005-01-27 17:31:07 +00:00
}
2007-01-02 19:05:49 +00:00
// free memory if in 'low' profile
2012-10-15 22:27:42 +00:00
if ( SettingsCore : : memoryLevel ( ) = = SettingsCore : : EnumMemoryLevel : : Low & &
2012-07-01 23:05:02 +00:00
! d - > m_allocatedPixmaps . isEmpty ( ) & & ! d - > m_pagesVector . isEmpty ( ) )
2007-01-02 19:05:49 +00:00
d - > cleanupPixmapMemory ( ) ;
2005-01-27 17:31:07 +00:00
}
2007-01-02 19:05:49 +00:00
bool Document : : isOpened ( ) const
2006-09-15 21:08:48 +00:00
{
2007-01-02 19:05:49 +00:00
return d - > m_generator ;
2006-09-15 21:08:48 +00:00
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
bool Document : : canConfigurePrinter ( ) const
2004-09-16 21:04:49 +00:00
{
2007-01-02 19:05:49 +00:00
if ( d - > m_generator )
2005-02-01 18:26:56 +00:00
{
2007-01-02 19:05:49 +00:00
Okular : : PrintInterface * iface = qobject_cast < Okular : : PrintInterface * > ( d - > m_generator ) ;
return iface ? true : false ;
2005-02-01 18:26:56 +00:00
}
2007-01-02 19:05:49 +00:00
else
return 0 ;
}
const DocumentInfo * Document : : documentInfo ( ) const
{
2009-11-16 00:46:33 +00:00
if ( d - > m_documentInfo )
return d - > m_documentInfo ;
2007-01-02 19:05:49 +00:00
if ( d - > m_generator )
2006-07-11 19:57:17 +00:00
{
2009-11-16 00:46:33 +00:00
DocumentInfo * info = new DocumentInfo ( ) ;
const DocumentInfo * tmp = d - > m_generator - > generateDocumentInfo ( ) ;
if ( tmp )
* info = * tmp ;
2007-07-10 23:49:37 +00:00
2011-01-22 18:46:56 +00:00
info - > set ( DocumentInfo : : FilePath , currentDocument ( ) . prettyUrl ( ) ) ;
2009-11-16 00:46:33 +00:00
const QString pagesSize = d - > pagesSizeString ( ) ;
2007-07-10 23:49:37 +00:00
if ( d - > m_docSize ! = - 1 )
{
2009-11-16 00:46:33 +00:00
const QString sizeString = KGlobal : : locale ( ) - > formatByteSize ( d - > m_docSize ) ;
info - > set ( DocumentInfo : : DocumentSize , sizeString ) ;
2007-07-10 23:49:37 +00:00
}
2007-01-02 19:05:49 +00:00
if ( ! pagesSize . isEmpty ( ) )
{
2009-11-16 00:46:33 +00:00
info - > set ( DocumentInfo : : PagesSize , pagesSize ) ;
}
const DocumentInfo : : Key keyPages = DocumentInfo : : Pages ;
const QString keyString = DocumentInfo : : getKeyString ( keyPages ) ;
2013-04-05 22:22:48 +00:00
2009-11-16 00:46:33 +00:00
if ( info - > get ( keyString ) . isEmpty ( ) ) {
2013-04-05 22:22:48 +00:00
info - > set ( keyString , QString : : number ( this - > pages ( ) ) ,
2009-11-16 00:46:33 +00:00
DocumentInfo : : getKeyTitle ( keyPages ) ) ;
2007-01-02 19:05:49 +00:00
}
2009-11-16 00:46:33 +00:00
d - > m_documentInfo = info ;
2007-01-02 19:05:49 +00:00
return info ;
2006-07-11 19:57:17 +00:00
}
2007-01-02 19:05:49 +00:00
else return NULL ;
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
const DocumentSynopsis * Document : : documentSynopsis ( ) const
{
return d - > m_generator ? d - > m_generator - > generateDocumentSynopsis ( ) : NULL ;
}
2005-02-01 18:26:56 +00:00
2007-07-07 20:35:01 +00:00
void Document : : startFontReading ( )
2007-01-02 19:05:49 +00:00
{
2007-07-07 20:35:01 +00:00
if ( ! d - > m_generator | | ! d - > m_generator - > hasFeature ( Generator : : FontInfo ) | | d - > m_fontThread )
return ;
if ( d - > m_fontsCached )
{
// in case we have cached fonts, simulate a reading
// this way the API is the same, and users no need to care about the
// internal caching
for ( int i = 0 ; i < d - > m_fontsCache . count ( ) ; + + i )
{
emit gotFont ( d - > m_fontsCache . at ( i ) ) ;
emit fontReadingProgress ( i / pages ( ) ) ;
}
emit fontReadingEnded ( ) ;
return ;
}
d - > m_fontThread = new FontExtractionThread ( d - > m_generator , pages ( ) ) ;
2011-07-31 19:22:04 +00:00
connect ( d - > m_fontThread , SIGNAL ( gotFont ( Okular : : FontInfo ) ) , this , SLOT ( fontReadingGotFont ( Okular : : FontInfo ) ) ) ;
connect ( d - > m_fontThread , SIGNAL ( progress ( int ) ) , this , SLOT ( fontReadingProgress ( int ) ) ) ;
2007-07-07 20:35:01 +00:00
d - > m_fontThread - > startExtraction ( /*d->m_generator->hasFeature( Generator::Threaded )*/ true ) ;
}
2007-07-08 21:22:37 +00:00
void Document : : stopFontReading ( )
{
if ( ! d - > m_fontThread )
return ;
disconnect ( d - > m_fontThread , 0 , this , 0 ) ;
d - > m_fontThread - > stopExtraction ( ) ;
d - > m_fontThread = 0 ;
d - > m_fontsCache . clear ( ) ;
}
2007-07-07 20:35:01 +00:00
bool Document : : canProvideFontInformation ( ) const
{
return d - > m_generator ? d - > m_generator - > hasFeature ( Generator : : FontInfo ) : false ;
2007-01-02 19:05:49 +00:00
}
2005-02-02 18:18:26 +00:00
2007-01-02 19:05:49 +00:00
const QList < EmbeddedFile * > * Document : : embeddedFiles ( ) const
{
return d - > m_generator ? d - > m_generator - > embeddedFiles ( ) : NULL ;
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
const Page * Document : : page ( int n ) const
{
2007-02-03 23:09:40 +00:00
return ( n < d - > m_pagesVector . count ( ) ) ? d - > m_pagesVector . at ( n ) : 0 ;
2007-01-02 19:05:49 +00:00
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
const DocumentViewport & Document : : viewport ( ) const
{
return ( * d - > m_viewportIterator ) ;
}
2005-02-02 18:18:26 +00:00
2007-01-02 19:05:49 +00:00
const QVector < VisiblePageRect * > & Document : : visiblePageRects ( ) const
{
return d - > m_pageRects ;
}
2004-09-08 12:41:14 +00:00
2013-02-24 21:58:53 +00:00
void Document : : setVisiblePageRects ( const QVector < VisiblePageRect * > & visiblePageRects , DocumentObserver * excludeObserver )
2007-01-02 19:05:49 +00:00
{
2008-11-11 18:48:40 +00:00
QVector < VisiblePageRect * > : : const_iterator vIt = d - > m_pageRects . constBegin ( ) ;
QVector < VisiblePageRect * > : : const_iterator vEnd = d - > m_pageRects . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; vIt ! = vEnd ; + + vIt )
delete * vIt ;
d - > m_pageRects = visiblePageRects ;
// notify change to all other (different from id) observers
2013-02-24 21:58:53 +00:00
foreach ( DocumentObserver * o , d - > m_observers )
if ( o ! = excludeObserver )
o - > notifyVisibleRectsChanged ( ) ;
2007-01-02 19:05:49 +00:00
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
uint Document : : currentPage ( ) const
{
return ( * d - > m_viewportIterator ) . pageNumber ;
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
uint Document : : pages ( ) const
{
return d - > m_pagesVector . size ( ) ;
}
2005-02-02 18:18:26 +00:00
2007-01-02 19:05:49 +00:00
KUrl Document : : currentDocument ( ) const
{
return d - > m_url ;
}
2005-02-02 18:18:26 +00:00
2007-03-10 23:59:11 +00:00
bool Document : : isAllowed ( Permission action ) const
2007-01-02 19:05:49 +00:00
{
2012-05-23 21:43:44 +00:00
if ( action = = Okular : : AllowNotes & & ! d - > m_annotationEditingEnabled )
return false ;
2007-01-29 14:28:58 +00:00
# if !OKULAR_FORCE_DRM
2014-08-08 22:37:02 +00:00
if ( KAuthorized : : authorize ( " skip_drm " ) & & ! SettingsCore : : obeyDRM ( ) )
2007-01-29 14:28:58 +00:00
return true ;
# endif
2007-03-10 23:59:11 +00:00
return d - > m_generator ? d - > m_generator - > isAllowed ( action ) : false ;
2007-01-02 19:05:49 +00:00
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
bool Document : : supportsSearching ( ) const
{
2007-01-17 11:58:20 +00:00
return d - > m_generator ? d - > m_generator - > hasFeature ( Generator : : TextExtraction ) : false ;
2007-01-02 19:05:49 +00:00
}
2004-09-13 08:51:36 +00:00
2007-01-05 23:12:06 +00:00
bool Document : : supportsPageSizes ( ) const
2007-01-02 19:05:49 +00:00
{
2007-01-17 18:02:53 +00:00
return d - > m_generator ? d - > m_generator - > hasFeature ( Generator : : PageSizes ) : false ;
2007-01-02 19:05:49 +00:00
}
2005-02-02 18:18:26 +00:00
2012-11-15 22:18:59 +00:00
bool Document : : supportsTiles ( ) const
{
return d - > m_generator ? d - > m_generator - > hasFeature ( Generator : : TiledRendering ) : false ;
}
2007-01-05 23:12:06 +00:00
PageSize : : List Document : : pageSizes ( ) const
2007-01-02 19:05:49 +00:00
{
2007-01-05 23:12:06 +00:00
if ( d - > m_generator )
{
if ( d - > m_pageSizes . isEmpty ( ) )
d - > m_pageSizes = d - > m_generator - > pageSizes ( ) ;
return d - > m_pageSizes ;
}
return PageSize : : List ( ) ;
2007-01-02 19:05:49 +00:00
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
bool Document : : canExportToText ( ) const
{
if ( ! d - > m_generator )
return false ;
2005-02-01 18:26:56 +00:00
2007-03-10 20:51:50 +00:00
d - > cacheExportFormats ( ) ;
return ! d - > m_exportToText . isNull ( ) ;
2007-01-02 19:05:49 +00:00
}
2005-02-20 16:04:40 +00:00
2007-01-02 19:05:49 +00:00
bool Document : : exportToText ( const QString & fileName ) const
{
if ( ! d - > m_generator )
return false ;
2005-02-20 16:04:40 +00:00
2007-03-10 20:51:50 +00:00
d - > cacheExportFormats ( ) ;
if ( d - > m_exportToText . isNull ( ) )
return false ;
2005-02-01 18:26:56 +00:00
2007-03-10 20:51:50 +00:00
return d - > m_generator - > exportTo ( fileName , d - > m_exportToText ) ;
2004-09-08 12:41:14 +00:00
}
2007-01-02 19:05:49 +00:00
ExportFormat : : List Document : : exportFormats ( ) const
2004-11-09 17:20:19 +00:00
{
2007-03-10 20:51:50 +00:00
if ( ! d - > m_generator )
return ExportFormat : : List ( ) ;
d - > cacheExportFormats ( ) ;
return d - > m_exportFormats ;
2004-11-09 17:20:19 +00:00
}
2007-01-02 19:05:49 +00:00
bool Document : : exportTo ( const QString & fileName , const ExportFormat & format ) const
2005-02-01 18:26:56 +00:00
{
2007-01-02 19:05:49 +00:00
return d - > m_generator ? d - > m_generator - > exportTo ( fileName , format ) : false ;
2005-02-01 18:26:56 +00:00
}
2007-01-02 19:05:49 +00:00
bool Document : : historyAtBegin ( ) const
2006-07-11 19:57:17 +00:00
{
2007-01-02 19:05:49 +00:00
return d - > m_viewportIterator = = d - > m_viewportHistory . begin ( ) ;
2006-07-11 19:57:17 +00:00
}
2005-02-01 18:26:56 +00:00
2007-01-02 19:05:49 +00:00
bool Document : : historyAtEnd ( ) const
2004-11-09 17:20:19 +00:00
{
2007-01-02 19:05:49 +00:00
return d - > m_viewportIterator = = - - ( d - > m_viewportHistory . end ( ) ) ;
2004-11-09 17:20:19 +00:00
}
2007-01-02 22:37:55 +00:00
QVariant Document : : metaData ( const QString & key , const QVariant & option ) const
2006-12-27 16:04:49 +00:00
{
2007-01-02 19:05:49 +00:00
return d - > m_generator ? d - > m_generator - > metaData ( key , option ) : QVariant ( ) ;
2006-12-27 16:04:49 +00:00
}
2007-01-05 17:09:47 +00:00
Rotation Document : : rotation ( ) const
2006-12-27 16:04:49 +00:00
{
2007-01-02 19:05:49 +00:00
return d - > m_rotation ;
2006-12-27 16:04:49 +00:00
}
2007-01-02 19:05:49 +00:00
QSizeF Document : : allPagesSize ( ) const
2006-12-27 16:04:49 +00:00
{
2007-01-02 19:05:49 +00:00
bool allPagesSameSize = true ;
QSizeF size ;
for ( int i = 0 ; allPagesSameSize & & i < d - > m_pagesVector . count ( ) ; + + i )
{
2007-02-12 14:15:51 +00:00
const Page * p = d - > m_pagesVector . at ( i ) ;
2007-01-02 19:05:49 +00:00
if ( i = = 0 ) size = QSizeF ( p - > width ( ) , p - > height ( ) ) ;
else
{
allPagesSameSize = ( size = = QSizeF ( p - > width ( ) , p - > height ( ) ) ) ;
}
}
if ( allPagesSameSize ) return size ;
else return QSizeF ( ) ;
2006-12-27 16:04:49 +00:00
}
2007-01-02 19:05:49 +00:00
QString Document : : pageSizeString ( int page ) const
2006-12-27 16:04:49 +00:00
{
2007-01-02 19:05:49 +00:00
if ( d - > m_generator )
{
if ( d - > m_generator - > pagesSizeMetric ( ) ! = Generator : : None )
{
2007-02-12 14:15:51 +00:00
const Page * p = d - > m_pagesVector . at ( page ) ;
2007-01-02 19:05:49 +00:00
return d - > localizedSize ( QSizeF ( p - > width ( ) , p - > height ( ) ) ) ;
}
}
return QString ( ) ;
2006-12-27 16:04:49 +00:00
}
2007-01-02 19:05:49 +00:00
void Document : : requestPixmaps ( const QLinkedList < PixmapRequest * > & requests )
2008-03-07 15:50:48 +00:00
{
requestPixmaps ( requests , RemoveAllPrevious ) ;
}
void Document : : requestPixmaps ( const QLinkedList < PixmapRequest * > & requests , PixmapRequestFlags reqOptions )
2004-09-08 12:41:14 +00:00
{
2007-05-24 22:52:29 +00:00
if ( requests . isEmpty ( ) )
return ;
2014-07-31 23:27:27 +00:00
if ( ! d - > m_pageController )
2007-01-02 19:05:49 +00:00
{
// delete requests..
2008-11-11 18:48:40 +00:00
QLinkedList < PixmapRequest * > : : const_iterator rIt = requests . constBegin ( ) , rEnd = requests . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; rIt ! = rEnd ; + + rIt )
delete * rIt ;
// ..and return
2004-10-06 00:05:49 +00:00
return ;
2007-01-02 19:05:49 +00:00
}
2004-10-06 00:05:49 +00:00
2007-01-02 19:05:49 +00:00
// 1. [CLEAN STACK] remove previous requests of requesterID
2013-06-24 10:46:16 +00:00
// FIXME This assumes all requests come from the same observer, that is true atm but not enforced anywhere
2013-02-24 21:58:53 +00:00
DocumentObserver * requesterObserver = requests . first ( ) - > observer ( ) ;
2008-03-07 15:50:48 +00:00
QSet < int > requestedPages ;
{
2008-11-11 18:48:40 +00:00
QLinkedList < PixmapRequest * > : : const_iterator rIt = requests . constBegin ( ) , rEnd = requests . constEnd ( ) ;
2008-03-07 15:50:48 +00:00
for ( ; rIt ! = rEnd ; + + rIt )
requestedPages . insert ( ( * rIt ) - > pageNumber ( ) ) ;
}
const bool removeAllPrevious = reqOptions & RemoveAllPrevious ;
2007-05-12 21:40:38 +00:00
d - > m_pixmapRequestsMutex . lock ( ) ;
2007-01-02 19:05:49 +00:00
QLinkedList < PixmapRequest * > : : iterator sIt = d - > m_pixmapRequestsStack . begin ( ) , sEnd = d - > m_pixmapRequestsStack . end ( ) ;
while ( sIt ! = sEnd )
2004-10-06 00:05:49 +00:00
{
2013-02-24 21:58:53 +00:00
if ( ( * sIt ) - > observer ( ) = = requesterObserver
2008-03-07 15:50:48 +00:00
& & ( removeAllPrevious | | requestedPages . contains ( ( * sIt ) - > pageNumber ( ) ) ) )
2007-01-02 19:05:49 +00:00
{
// delete request and remove it from stack
delete * sIt ;
sIt = d - > m_pixmapRequestsStack . erase ( sIt ) ;
}
else
+ + sIt ;
}
2005-02-04 22:35:44 +00:00
2007-01-02 19:05:49 +00:00
// 2. [ADD TO STACK] add requests to stack
2008-11-11 18:48:40 +00:00
QLinkedList < PixmapRequest * > : : const_iterator rIt = requests . constBegin ( ) , rEnd = requests . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; rIt ! = rEnd ; + + rIt )
{
// set the 'page field' (see PixmapRequest) and check if it is valid
PixmapRequest * request = * rIt ;
2013-02-24 21:58:53 +00:00
kDebug ( OkularDebug ) . nospace ( ) < < " request observer= " < < request - > observer ( ) < < " " < < request - > width ( ) < < " x " < < request - > height ( ) < < " @ " < < request - > pageNumber ( ) ;
2007-01-02 19:05:49 +00:00
if ( d - > m_pagesVector . value ( request - > pageNumber ( ) ) = = 0 )
{
// skip requests referencing an invalid page (must not happen)
delete request ;
continue ;
}
2004-12-10 16:04:45 +00:00
2007-09-30 21:44:31 +00:00
request - > d - > mPage = d - > m_pagesVector . value ( request - > pageNumber ( ) ) ;
2005-06-13 17:44:33 +00:00
2012-11-12 14:55:13 +00:00
if ( request - > isTile ( ) )
{
// Change the current request rect so that only invalid tiles are
// requested. Also make sure the rect is tile-aligned.
NormalizedRect tilesRect ;
2014-02-19 22:40:43 +00:00
const QList < Tile > tiles = request - > d - > tilesManager ( ) - > tilesAt ( request - > normalizedRect ( ) , TilesManager : : TerminalTile ) ;
2012-11-12 14:55:13 +00:00
QList < Tile > : : const_iterator tIt = tiles . constBegin ( ) , tEnd = tiles . constEnd ( ) ;
while ( tIt ! = tEnd )
{
const Tile & tile = * tIt ;
if ( ! tile . isValid ( ) )
{
if ( tilesRect . isNull ( ) )
tilesRect = tile . rect ( ) ;
else
tilesRect | = tile . rect ( ) ;
}
tIt + + ;
}
request - > setNormalizedRect ( tilesRect ) ;
}
2007-01-02 19:05:49 +00:00
if ( ! request - > asynchronous ( ) )
2007-09-30 21:44:31 +00:00
request - > d - > mPriority = 0 ;
2004-10-06 00:05:49 +00:00
2007-01-02 19:05:49 +00:00
// add request to the 'stack' at the right place
if ( ! request - > priority ( ) )
// add priority zero requests to the top of the stack
d - > m_pixmapRequestsStack . append ( request ) ;
else
{
// insert in stack sorted by priority
sIt = d - > m_pixmapRequestsStack . begin ( ) ;
sEnd = d - > m_pixmapRequestsStack . end ( ) ;
2007-01-04 14:28:54 +00:00
while ( sIt ! = sEnd & & ( * sIt ) - > priority ( ) > request - > priority ( ) )
2007-01-02 19:05:49 +00:00
+ + sIt ;
d - > m_pixmapRequestsStack . insert ( sIt , request ) ;
}
}
2007-05-12 21:40:38 +00:00
d - > m_pixmapRequestsMutex . unlock ( ) ;
2004-12-10 16:04:45 +00:00
2007-01-02 19:05:49 +00:00
// 3. [START FIRST GENERATION] if <NO>generator is ready, start a new generation,
// or else (if gen is running) it will be started when the new contents will
//come from generator (in requestDone())</NO>
2012-09-25 09:09:34 +00:00
// all handling of requests put into sendGeneratorPixmapRequest
2007-01-24 15:06:45 +00:00
// if ( generator->canRequestPixmap() )
2012-09-25 09:09:34 +00:00
d - > sendGeneratorPixmapRequest ( ) ;
2007-01-02 19:05:49 +00:00
}
2004-12-10 16:04:45 +00:00
2007-08-13 22:25:27 +00:00
void Document : : requestTextPage ( uint page )
2007-01-02 19:05:49 +00:00
{
Page * kp = d - > m_pagesVector [ page ] ;
if ( ! d - > m_generator | | ! kp )
return ;
2004-12-10 16:04:45 +00:00
2007-01-02 19:05:49 +00:00
// Memory management for TextPages
2004-12-10 16:04:45 +00:00
2007-08-13 22:25:27 +00:00
d - > m_generator - > generateTextPage ( kp ) ;
2007-01-02 19:05:49 +00:00
}
2005-03-05 15:59:15 +00:00
2012-05-23 21:43:44 +00:00
void DocumentPrivate : : notifyAnnotationChanges ( int page )
{
int flags = DocumentObserver : : Annotations ;
2012-05-30 16:38:51 +00:00
if ( m_annotationsNeedSaveAs )
flags | = DocumentObserver : : NeedSaveAs ;
2012-05-23 21:43:44 +00:00
foreachObserverD ( notifyPageChanged ( page , flags ) ) ;
}
2007-01-02 19:05:49 +00:00
void Document : : addPageAnnotation ( int page , Annotation * annotation )
{
2013-04-13 20:54:47 +00:00
// Transform annotation's base boundary rectangle into unrotated coordinates
Page * p = d - > m_pagesVector [ page ] ;
QTransform t = p - > d - > rotationMatrix ( ) ;
annotation - > d_ptr - > baseTransform ( t . inverted ( ) ) ;
2013-04-05 22:22:48 +00:00
QUndoCommand * uc = new AddAnnotationCommand ( this - > d , annotation , page ) ;
d - > m_undoStack - > push ( uc ) ;
2004-09-09 13:25:40 +00:00
}
2004-11-09 17:20:19 +00:00
2012-03-09 13:59:24 +00:00
bool Document : : canModifyPageAnnotation ( const Annotation * annotation ) const
{
if ( ! annotation | | ( annotation - > flags ( ) & Annotation : : DenyWrite ) )
return false ;
if ( ! isAllowed ( Okular : : AllowNotes ) )
return false ;
if ( ( annotation - > flags ( ) & Annotation : : External ) & & ! d - > canModifyExternalAnnotations ( ) )
return false ;
switch ( annotation - > subType ( ) )
{
case Annotation : : AText :
case Annotation : : ALine :
case Annotation : : AGeom :
case Annotation : : AHighlight :
case Annotation : : AStamp :
case Annotation : : AInk :
return true ;
default :
return false ;
}
}
2013-04-05 22:22:48 +00:00
void Document : : prepareToModifyAnnotationProperties ( Annotation * annotation )
2006-11-17 22:15:15 +00:00
{
2013-04-05 22:28:39 +00:00
Q_ASSERT ( d - > m_prevPropsOfAnnotBeingModified . isNull ( ) ) ;
2013-04-05 22:22:48 +00:00
if ( ! d - > m_prevPropsOfAnnotBeingModified . isNull ( ) )
{
kError ( OkularDebug ) < < " Error: Document::prepareToModifyAnnotationProperties has already been called since last call to Document::modifyPageAnnotationProperties " ;
return ;
}
d - > m_prevPropsOfAnnotBeingModified = annotation - > getAnnotationPropertiesDomNode ( ) ;
2012-05-13 22:50:41 +00:00
}
2013-04-05 22:22:48 +00:00
void Document : : modifyPageAnnotationProperties ( int page , Annotation * annotation )
2012-05-13 22:50:41 +00:00
{
2013-04-05 22:28:39 +00:00
Q_ASSERT ( ! d - > m_prevPropsOfAnnotBeingModified . isNull ( ) ) ;
2013-04-05 22:22:48 +00:00
if ( d - > m_prevPropsOfAnnotBeingModified . isNull ( ) )
2012-05-13 22:50:41 +00:00
{
2013-04-05 22:22:48 +00:00
kError ( OkularDebug ) < < " Error: Document::prepareToModifyAnnotationProperties must be called before Annotation is modified " ;
return ;
2012-05-13 22:50:41 +00:00
}
2013-04-05 22:22:48 +00:00
QDomNode prevProps = d - > m_prevPropsOfAnnotBeingModified ;
QUndoCommand * uc = new Okular : : ModifyAnnotationPropertiesCommand ( d ,
annotation ,
page ,
prevProps ,
annotation - > getAnnotationPropertiesDomNode ( ) ) ;
d - > m_undoStack - > push ( uc ) ;
d - > m_prevPropsOfAnnotBeingModified . clear ( ) ;
}
2012-05-14 13:51:58 +00:00
2013-04-05 22:22:48 +00:00
void Document : : translatePageAnnotation ( int page , Annotation * annotation , const NormalizedPoint & delta )
{
int complete = ( annotation - > flags ( ) & Okular : : Annotation : : BeingMoved ) = = 0 ;
QUndoCommand * uc = new Okular : : TranslateAnnotationCommand ( d , annotation , page , delta , complete ) ;
d - > m_undoStack - > push ( uc ) ;
}
void Document : : editPageAnnotationContents ( int page , Annotation * annotation ,
const QString & newContents ,
int newCursorPos ,
int prevCursorPos ,
int prevAnchorPos
)
{
QString prevContents = annotation - > contents ( ) ;
QUndoCommand * uc = new EditAnnotationContentsCommand ( d , annotation , page , newContents , newCursorPos ,
prevContents , prevCursorPos , prevAnchorPos ) ;
d - > m_undoStack - > push ( uc ) ;
2007-01-02 19:05:49 +00:00
}
2006-11-17 22:15:15 +00:00
2012-05-13 22:50:41 +00:00
bool Document : : canRemovePageAnnotation ( const Annotation * annotation ) const
{
if ( ! annotation | | ( annotation - > flags ( ) & Annotation : : DenyDelete ) )
return false ;
2012-03-09 13:59:24 +00:00
if ( ( annotation - > flags ( ) & Annotation : : External ) & & ! d - > canRemoveExternalAnnotations ( ) )
return false ;
2012-05-13 22:50:41 +00:00
switch ( annotation - > subType ( ) )
{
case Annotation : : AText :
case Annotation : : ALine :
case Annotation : : AGeom :
case Annotation : : AHighlight :
case Annotation : : AStamp :
case Annotation : : AInk :
return true ;
default :
return false ;
}
}
2007-01-02 19:05:49 +00:00
void Document : : removePageAnnotation ( int page , Annotation * annotation )
{
2013-04-05 22:22:48 +00:00
QUndoCommand * uc = new RemoveAnnotationCommand ( this - > d , annotation , page ) ;
d - > m_undoStack - > push ( uc ) ;
2007-01-02 19:05:49 +00:00
}
2006-11-17 22:15:15 +00:00
2013-04-05 22:22:48 +00:00
void Document : : removePageAnnotations ( int page , const QList < Annotation * > & annotations )
2007-01-02 19:05:49 +00:00
{
2013-04-05 22:22:48 +00:00
d - > m_undoStack - > beginMacro ( i18nc ( " remove a collection of annotations from the page " , " remove annotations " ) ) ;
foreach ( Annotation * annotation , annotations )
2007-01-02 19:05:49 +00:00
{
2013-04-05 22:22:48 +00:00
QUndoCommand * uc = new RemoveAnnotationCommand ( this - > d , annotation , page ) ;
d - > m_undoStack - > push ( uc ) ;
2007-01-02 19:05:49 +00:00
}
2013-04-05 22:22:48 +00:00
d - > m_undoStack - > endMacro ( ) ;
2012-05-14 13:51:58 +00:00
}
bool DocumentPrivate : : canAddAnnotationsNatively ( ) const
{
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( m_generator ) ;
if ( iface & & iface - > supportsOption ( Okular : : SaveInterface : : SaveChanges ) & &
iface - > annotationProxy ( ) & & iface - > annotationProxy ( ) - > supports ( AnnotationProxy : : Addition ) )
return true ;
return false ;
2007-01-02 19:05:49 +00:00
}
2006-11-17 22:15:15 +00:00
2012-03-09 13:59:24 +00:00
bool DocumentPrivate : : canModifyExternalAnnotations ( ) const
{
2012-05-17 18:49:21 +00:00
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( m_generator ) ;
2012-03-09 13:59:24 +00:00
2012-05-17 18:49:21 +00:00
if ( iface & & iface - > supportsOption ( Okular : : SaveInterface : : SaveChanges ) & &
iface - > annotationProxy ( ) & & iface - > annotationProxy ( ) - > supports ( AnnotationProxy : : Modification ) )
2012-03-09 13:59:24 +00:00
return true ;
2012-05-17 18:49:21 +00:00
2012-03-09 13:59:24 +00:00
return false ;
}
bool DocumentPrivate : : canRemoveExternalAnnotations ( ) const
{
2012-05-17 18:49:21 +00:00
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( m_generator ) ;
2012-03-09 13:59:24 +00:00
2012-05-17 18:49:21 +00:00
if ( iface & & iface - > supportsOption ( Okular : : SaveInterface : : SaveChanges ) & &
iface - > annotationProxy ( ) & & iface - > annotationProxy ( ) - > supports ( AnnotationProxy : : Removal ) )
2012-03-09 13:59:24 +00:00
return true ;
2012-05-17 18:49:21 +00:00
2012-03-09 13:59:24 +00:00
return false ;
}
2007-01-02 19:05:49 +00:00
void Document : : setPageTextSelection ( int page , RegularAreaRect * rect , const QColor & color )
{
Page * kp = d - > m_pagesVector [ page ] ;
if ( ! d - > m_generator | | ! kp )
2006-11-17 22:15:15 +00:00
return ;
2007-01-02 19:05:49 +00:00
// add or remove the selection basing whether rect is null or not
if ( rect )
2007-05-05 18:07:34 +00:00
kp - > d - > setTextSelections ( rect , color ) ;
2007-01-02 19:05:49 +00:00
else
2007-09-03 23:47:12 +00:00
kp - > d - > deleteTextSelections ( ) ;
2007-01-02 19:05:49 +00:00
// notify observers about the change
foreachObserver ( notifyPageChanged ( page , DocumentObserver : : TextSelection ) ) ;
2006-11-17 22:15:15 +00:00
}
2013-04-05 22:22:48 +00:00
bool Document : : canUndo ( ) const
{
return d - > m_undoStack - > canUndo ( ) ;
}
bool Document : : canRedo ( ) const
{
return d - > m_undoStack - > canRedo ( ) ;
}
2007-01-02 19:05:49 +00:00
/* REFERENCE IMPLEMENTATION: better calling setViewport from other code
void Document : : setNextPage ( )
2004-11-09 17:20:19 +00:00
{
2007-01-02 19:05:49 +00:00
// advance page and set viewport on observers
if ( ( * d - > m_viewportIterator ) . pageNumber < ( int ) d - > m_pagesVector . count ( ) - 1 )
setViewport ( DocumentViewport ( ( * d - > m_viewportIterator ) . pageNumber + 1 ) ) ;
2004-11-09 17:20:19 +00:00
}
2004-12-10 16:04:45 +00:00
2007-01-02 19:05:49 +00:00
void Document : : setPrevPage ( )
2007-01-02 16:11:40 +00:00
{
2007-01-02 19:05:49 +00:00
// go to previous page and set viewport on observers
if ( ( * d - > m_viewportIterator ) . pageNumber > 0 )
setViewport ( DocumentViewport ( ( * d - > m_viewportIterator ) . pageNumber - 1 ) ) ;
}
*/
2013-02-24 21:58:53 +00:00
void Document : : setViewportPage ( int page , DocumentObserver * excludeObserver , bool smoothMove )
2007-01-02 19:05:49 +00:00
{
// clamp page in range [0 ... numPages-1]
if ( page < 0 )
page = 0 ;
else if ( page > ( int ) d - > m_pagesVector . count ( ) )
page = d - > m_pagesVector . count ( ) - 1 ;
// make a viewport from the page and broadcast it
2013-02-24 21:58:53 +00:00
setViewport ( DocumentViewport ( page ) , excludeObserver , smoothMove ) ;
2007-01-02 19:05:49 +00:00
}
2013-02-24 21:58:53 +00:00
void Document : : setViewport ( const DocumentViewport & viewport , DocumentObserver * excludeObserver , bool smoothMove )
2007-01-02 19:05:49 +00:00
{
2008-11-30 11:28:08 +00:00
if ( ! viewport . isValid ( ) )
{
kDebug ( OkularDebug ) < < " invalid viewport: " < < viewport . toString ( ) ;
return ;
}
2011-02-12 14:49:32 +00:00
if ( viewport . pageNumber > = int ( d - > m_pagesVector . count ( ) ) )
{
//kDebug(OkularDebug) << "viewport out of document:" << viewport.toString();
return ;
}
2008-11-30 11:28:08 +00:00
2007-01-02 19:05:49 +00:00
// if already broadcasted, don't redo it
DocumentViewport & oldViewport = * d - > m_viewportIterator ;
// disabled by enrico on 2005-03-18 (less debug output)
//if ( viewport == oldViewport )
2007-07-31 10:19:48 +00:00
// kDebug(OkularDebug) << "setViewport with the same viewport.";
2007-01-02 19:05:49 +00:00
2012-08-16 15:37:39 +00:00
const int oldPageNumber = oldViewport . pageNumber ;
2007-01-02 19:05:49 +00:00
// set internal viewport taking care of history
if ( oldViewport . pageNumber = = viewport . pageNumber | | ! oldViewport . isValid ( ) )
2007-01-02 16:11:40 +00:00
{
2007-01-02 19:05:49 +00:00
// if page is unchanged save the viewport at current position in queue
oldViewport = viewport ;
2007-01-02 16:11:40 +00:00
}
else
2007-01-02 19:05:49 +00:00
{
// remove elements after viewportIterator in queue
d - > m_viewportHistory . erase ( + + d - > m_viewportIterator , d - > m_viewportHistory . end ( ) ) ;
// keep the list to a reasonable size by removing head when needed
2007-07-23 17:12:20 +00:00
if ( d - > m_viewportHistory . count ( ) > = OKULAR_HISTORY_MAXSTEPS )
2007-01-02 19:05:49 +00:00
d - > m_viewportHistory . pop_front ( ) ;
// add the item at the end of the queue
d - > m_viewportIterator = d - > m_viewportHistory . insert ( d - > m_viewportHistory . end ( ) , viewport ) ;
}
2012-08-16 15:37:39 +00:00
const int currentViewportPage = ( * d - > m_viewportIterator ) . pageNumber ;
const bool currentPageChanged = ( oldPageNumber ! = currentViewportPage ) ;
2007-01-02 19:05:49 +00:00
// notify change to all other (different from id) observers
2013-02-24 21:58:53 +00:00
foreach ( DocumentObserver * o , d - > m_observers )
2012-08-16 15:37:39 +00:00
{
2013-02-24 21:58:53 +00:00
if ( o ! = excludeObserver )
o - > notifyViewportChanged ( smoothMove ) ;
2012-08-16 15:37:39 +00:00
if ( currentPageChanged )
2013-02-24 21:58:53 +00:00
o - > notifyCurrentPageChanged ( oldPageNumber , currentViewportPage ) ;
2012-08-16 15:37:39 +00:00
}
2007-01-02 16:11:40 +00:00
}
2013-02-24 21:58:53 +00:00
void Document : : setZoom ( int factor , DocumentObserver * excludeObserver )
2007-07-08 14:25:08 +00:00
{
// notify change to all other (different from id) observers
2013-02-24 21:58:53 +00:00
foreach ( DocumentObserver * o , d - > m_observers )
if ( o ! = excludeObserver )
o - > notifyZoom ( factor ) ;
2007-07-08 14:25:08 +00:00
}
2007-01-02 19:05:49 +00:00
void Document : : setPrevViewport ( )
// restore viewport from the history
2005-01-18 16:43:36 +00:00
{
2007-01-02 19:05:49 +00:00
if ( d - > m_viewportIterator ! = d - > m_viewportHistory . begin ( ) )
{
2013-11-27 23:05:24 +00:00
const int oldViewportPage = ( * d - > m_viewportIterator ) . pageNumber ;
2007-01-02 19:05:49 +00:00
// restore previous viewport and notify it to observers
- - d - > m_viewportIterator ;
foreachObserver ( notifyViewportChanged ( true ) ) ;
2013-11-27 23:05:24 +00:00
const int currentViewportPage = ( * d - > m_viewportIterator ) . pageNumber ;
if ( oldViewportPage ! = currentViewportPage )
foreachObserver ( notifyCurrentPageChanged ( oldViewportPage , currentViewportPage ) ) ;
2007-01-02 19:05:49 +00:00
}
}
2005-01-20 17:33:05 +00:00
2007-01-02 19:05:49 +00:00
void Document : : setNextViewport ( )
// restore next viewport from the history
{
QLinkedList < DocumentViewport > : : const_iterator nextIterator = d - > m_viewportIterator ;
+ + nextIterator ;
if ( nextIterator ! = d - > m_viewportHistory . end ( ) )
{
2013-11-27 23:05:24 +00:00
const int oldViewportPage = ( * d - > m_viewportIterator ) . pageNumber ;
2007-01-02 19:05:49 +00:00
// restore next viewport and notify it to observers
+ + d - > m_viewportIterator ;
foreachObserver ( notifyViewportChanged ( true ) ) ;
2013-11-27 23:05:24 +00:00
const int currentViewportPage = ( * d - > m_viewportIterator ) . pageNumber ;
if ( oldViewportPage ! = currentViewportPage )
foreachObserver ( notifyCurrentPageChanged ( oldViewportPage , currentViewportPage ) ) ;
2007-01-02 19:05:49 +00:00
}
}
void Document : : setNextDocumentViewport ( const DocumentViewport & viewport )
{
d - > m_nextDocumentViewport = viewport ;
}
2009-05-13 14:24:30 +00:00
void Document : : setNextDocumentDestination ( const QString & namedDestination )
{
d - > m_nextDocumentDestination = namedDestination ;
}
2007-08-13 22:25:27 +00:00
void Document : : searchText ( int searchID , const QString & text , bool fromStart , Qt : : CaseSensitivity caseSensitivity ,
2014-05-10 09:33:21 +00:00
SearchType type , bool moveViewport , const QColor & color )
2007-01-02 19:05:49 +00:00
{
2007-08-13 22:25:27 +00:00
d - > m_searchCancelled = false ;
2007-01-02 19:05:49 +00:00
// safety checks: don't perform searches on empty or unsearchable docs
2007-01-17 11:58:20 +00:00
if ( ! d - > m_generator | | ! d - > m_generator - > hasFeature ( Generator : : TextExtraction ) | | d - > m_pagesVector . isEmpty ( ) )
2007-08-13 22:25:27 +00:00
{
2007-08-23 22:16:37 +00:00
emit searchFinished ( searchID , NoMatchFound ) ;
2007-08-13 22:25:27 +00:00
return ;
}
2007-01-02 19:05:49 +00:00
// if searchID search not recorded, create new descriptor and init params
2007-02-12 14:15:51 +00:00
QMap < int , RunningSearch * > : : iterator searchIt = d - > m_searches . find ( searchID ) ;
if ( searchIt = = d - > m_searches . end ( ) )
2007-01-02 19:05:49 +00:00
{
RunningSearch * search = new RunningSearch ( ) ;
search - > continueOnPage = - 1 ;
2007-02-12 14:15:51 +00:00
searchIt = d - > m_searches . insert ( searchID , search ) ;
2007-01-02 19:05:49 +00:00
}
2007-02-12 14:15:51 +00:00
RunningSearch * s = * searchIt ;
2007-01-02 19:05:49 +00:00
2010-04-02 18:49:13 +00:00
// update search structure
2007-01-02 19:05:49 +00:00
bool newText = text ! = s - > cachedString ;
s - > cachedString = text ;
s - > cachedType = type ;
s - > cachedCaseSensitivity = caseSensitivity ;
s - > cachedViewportMove = moveViewport ;
s - > cachedColor = color ;
2009-08-10 22:28:54 +00:00
s - > isCurrentlySearching = true ;
2007-01-02 19:05:49 +00:00
// global data for search
2007-08-13 22:25:27 +00:00
QSet < int > * pagesToNotify = new QSet < int > ;
2007-01-02 19:05:49 +00:00
// remove highlights from pages and queue them for notifying changes
2007-08-13 22:25:27 +00:00
* pagesToNotify + = s - > highlightedPages ;
foreach ( int pageNumber , s - > highlightedPages )
d - > m_pagesVector . at ( pageNumber ) - > d - > deleteHighlights ( searchID ) ;
2007-01-02 19:05:49 +00:00
s - > highlightedPages . clear ( ) ;
// set hourglass cursor
QApplication : : setOverrideCursor ( Qt : : WaitCursor ) ;
// 1. ALLDOC - proces all document marking pages
2007-01-02 22:37:55 +00:00
if ( type = = AllDocument )
2007-01-02 19:05:49 +00:00
{
2007-08-13 22:25:27 +00:00
QMap < Page * , QVector < RegularAreaRect * > > * pageMatches = new QMap < Page * , QVector < RegularAreaRect * > > ;
2007-01-02 19:05:49 +00:00
2007-08-13 22:25:27 +00:00
// search and highlight 'text' (as a solid phrase) on all pages
2014-05-09 22:49:01 +00:00
QMetaObject : : invokeMethod ( this , " doContinueAllDocumentSearch " , Qt : : QueuedConnection , Q_ARG ( void * , pagesToNotify ) , Q_ARG ( void * , pageMatches ) , Q_ARG ( int , 0 ) , Q_ARG ( int , searchID ) ) ;
2007-01-02 19:05:49 +00:00
}
// 2. NEXTMATCH - find next matching item (or start from top)
2008-03-14 14:14:06 +00:00
// 3. PREVMATCH - find previous matching item (or start from bottom)
2012-09-24 22:14:10 +00:00
else if ( type = = NextMatch | | type = = PreviousMatch )
2007-01-02 19:05:49 +00:00
{
2008-03-14 14:14:06 +00:00
// find out from where to start/resume search from
2012-09-24 22:14:10 +00:00
const bool forward = type = = NextMatch ;
const int viewportPage = ( * d - > m_viewportIterator ) . pageNumber ;
const int fromStartSearchPage = forward ? 0 : d - > m_pagesVector . count ( ) - 1 ;
int currentPage = fromStart ? fromStartSearchPage : ( ( s - > continueOnPage ! = - 1 ) ? s - > continueOnPage : viewportPage ) ;
2008-03-14 14:14:06 +00:00
Page * lastPage = fromStart ? 0 : d - > m_pagesVector [ currentPage ] ;
2008-11-30 11:02:02 +00:00
int pagesDone = 0 ;
2008-03-14 14:14:06 +00:00
// continue checking last TextPage first (if it is the current page)
RegularAreaRect * match = 0 ;
if ( lastPage & & lastPage - > number ( ) = = s - > continueOnPage )
{
if ( newText )
2012-09-24 22:14:10 +00:00
match = lastPage - > findText ( searchID , text , forward ? FromTop : FromBottom , caseSensitivity ) ;
2008-03-14 14:14:06 +00:00
else
2012-09-24 22:14:10 +00:00
match = lastPage - > findText ( searchID , text , forward ? NextResult : PreviousResult , caseSensitivity , & s - > continueOnMatch ) ;
2008-03-14 14:14:06 +00:00
if ( ! match )
2008-11-30 11:02:02 +00:00
{
2012-09-24 22:14:10 +00:00
if ( forward ) currentPage + + ;
else currentPage - - ;
2008-11-30 11:02:02 +00:00
pagesDone + + ;
}
2008-03-14 14:14:06 +00:00
}
2013-04-05 22:22:48 +00:00
2014-05-10 09:33:21 +00:00
s - > pagesDone = pagesDone ;
2012-09-24 22:14:10 +00:00
DoContinueDirectionMatchSearchStruct * searchStruct = new DoContinueDirectionMatchSearchStruct ( ) ;
searchStruct - > pagesToNotify = pagesToNotify ;
searchStruct - > match = match ;
searchStruct - > currentPage = currentPage ;
searchStruct - > searchID = searchID ;
QMetaObject : : invokeMethod ( this , " doContinueDirectionMatchSearch " , Qt : : QueuedConnection , Q_ARG ( void * , searchStruct ) ) ;
2007-01-02 19:05:49 +00:00
}
// 4. GOOGLE* - process all document marking pages
else if ( type = = GoogleAll | | type = = GoogleAny )
{
2007-08-13 22:25:27 +00:00
QMap < Page * , QVector < QPair < RegularAreaRect * , QColor > > > * pageMatches = new QMap < Page * , QVector < QPair < RegularAreaRect * , QColor > > > ;
2008-10-19 10:07:48 +00:00
const QStringList words = text . split ( ' ' , QString : : SkipEmptyParts ) ;
2007-01-02 19:05:49 +00:00
2007-08-13 22:25:27 +00:00
// search and highlight every word in 'text' on all pages
2014-05-09 22:49:01 +00:00
QMetaObject : : invokeMethod ( this , " doContinueGooglesDocumentSearch " , Qt : : QueuedConnection , Q_ARG ( void * , pagesToNotify ) , Q_ARG ( void * , pageMatches ) , Q_ARG ( int , 0 ) , Q_ARG ( int , searchID ) , Q_ARG ( QStringList , words ) ) ;
2007-01-02 19:05:49 +00:00
}
}
2007-08-13 22:25:27 +00:00
void Document : : continueSearch ( int searchID )
2007-01-02 19:05:49 +00:00
{
// check if searchID is present in runningSearches
2007-02-12 14:15:51 +00:00
QMap < int , RunningSearch * > : : const_iterator it = d - > m_searches . constFind ( searchID ) ;
if ( it = = d - > m_searches . constEnd ( ) )
2007-08-13 22:25:27 +00:00
{
2007-08-23 22:16:37 +00:00
emit searchFinished ( searchID , NoMatchFound ) ;
2007-08-13 22:25:27 +00:00
return ;
}
2007-01-02 19:05:49 +00:00
// start search with cached parameters from last search by searchID
2007-02-12 14:15:51 +00:00
RunningSearch * p = * it ;
2009-08-10 22:28:54 +00:00
if ( ! p - > isCurrentlySearching )
searchText ( searchID , p - > cachedString , false , p - > cachedCaseSensitivity ,
2014-05-10 09:33:21 +00:00
p - > cachedType , p - > cachedViewportMove , p - > cachedColor ) ;
2005-01-18 16:43:36 +00:00
}
2008-03-14 13:57:01 +00:00
void Document : : continueSearch ( int searchID , SearchType type )
{
// check if searchID is present in runningSearches
QMap < int , RunningSearch * > : : const_iterator it = d - > m_searches . constFind ( searchID ) ;
if ( it = = d - > m_searches . constEnd ( ) )
{
emit searchFinished ( searchID , NoMatchFound ) ;
return ;
}
// start search with cached parameters from last search by searchID
RunningSearch * p = * it ;
2009-08-10 22:28:54 +00:00
if ( ! p - > isCurrentlySearching )
searchText ( searchID , p - > cachedString , false , p - > cachedCaseSensitivity ,
2014-05-10 09:33:21 +00:00
type , p - > cachedViewportMove , p - > cachedColor ) ;
2008-03-14 13:57:01 +00:00
}
2007-01-02 19:05:49 +00:00
void Document : : resetSearch ( int searchID )
2005-01-18 16:43:36 +00:00
{
2014-01-05 00:26:41 +00:00
// if we are closing down, don't bother doing anything
if ( ! d - > m_generator )
return ;
2007-01-02 19:05:49 +00:00
// check if searchID is present in runningSearches
2007-02-12 14:15:51 +00:00
QMap < int , RunningSearch * > : : iterator searchIt = d - > m_searches . find ( searchID ) ;
if ( searchIt = = d - > m_searches . end ( ) )
2005-01-18 16:43:36 +00:00
return ;
2007-01-02 19:05:49 +00:00
// get previous parameters for search
2007-02-12 14:15:51 +00:00
RunningSearch * s = * searchIt ;
2005-01-18 16:43:36 +00:00
2007-01-02 19:05:49 +00:00
// unhighlight pages and inform observers about that
2007-08-13 22:25:27 +00:00
foreach ( int pageNumber , s - > highlightedPages )
- 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-08-13 22:25:27 +00:00
d - > m_pagesVector . at ( pageNumber ) - > d - > deleteHighlights ( searchID ) ;
2007-01-02 19:05:49 +00:00
foreachObserver ( notifyPageChanged ( pageNumber , DocumentObserver : : Highlights ) ) ;
}
2006-11-20 07:53:32 +00:00
2007-01-02 19:05:49 +00:00
// send the setup signal too (to update views that filter on matches)
2007-09-09 10:50:36 +00:00
foreachObserver ( notifySetup ( d - > m_pagesVector , 0 ) ) ;
2006-11-20 07:53:32 +00:00
2007-01-02 19:05:49 +00:00
// remove serch from the runningSearches list and delete it
2007-02-12 14:15:51 +00:00
d - > m_searches . erase ( searchIt ) ;
2007-01-02 19:05:49 +00:00
delete s ;
}
2007-08-13 22:25:27 +00:00
void Document : : cancelSearch ( )
{
d - > m_searchCancelled = true ;
}
2007-01-02 19:05:49 +00:00
2013-04-05 22:22:48 +00:00
void Document : : undo ( )
{
d - > m_undoStack - > undo ( ) ;
}
void Document : : redo ( )
{
d - > m_undoStack - > redo ( ) ;
}
2013-06-03 20:46:41 +00:00
void Document : : editFormText ( int pageNumber ,
Okular : : FormFieldText * form ,
const QString & newContents ,
int newCursorPos ,
int prevCursorPos ,
int prevAnchorPos )
{
2013-12-29 22:27:30 +00:00
QUndoCommand * uc = new EditFormTextCommand ( this - > d , form , pageNumber , newContents , newCursorPos , form - > text ( ) , prevCursorPos , prevAnchorPos ) ;
2013-06-03 20:46:41 +00:00
d - > m_undoStack - > push ( uc ) ;
}
void Document : : editFormList ( int pageNumber ,
FormFieldChoice * form ,
const QList < int > & newChoices )
{
const QList < int > prevChoices = form - > currentChoices ( ) ;
2013-12-29 22:27:30 +00:00
QUndoCommand * uc = new EditFormListCommand ( this - > d , form , pageNumber , newChoices , prevChoices ) ;
2013-06-03 20:46:41 +00:00
d - > m_undoStack - > push ( uc ) ;
}
void Document : : editFormCombo ( int pageNumber ,
FormFieldChoice * form ,
const QString & newText ,
int newCursorPos ,
int prevCursorPos ,
int prevAnchorPos )
{
QString prevText ;
if ( form - > currentChoices ( ) . isEmpty ( ) )
{
prevText = form - > editChoice ( ) ;
}
else
{
prevText = form - > choices ( ) [ form - > currentChoices ( ) [ 0 ] ] ;
}
2013-12-29 22:27:30 +00:00
QUndoCommand * uc = new EditFormComboCommand ( this - > d , form , pageNumber , newText , newCursorPos , prevText , prevCursorPos , prevAnchorPos ) ;
2013-06-03 20:46:41 +00:00
d - > m_undoStack - > push ( uc ) ;
}
void Document : : editFormButtons ( int pageNumber , const QList < FormFieldButton * > & formButtons , const QList < bool > & newButtonStates )
{
2013-12-29 22:27:30 +00:00
QUndoCommand * uc = new EditFormButtonsCommand ( this - > d , pageNumber , formButtons , newButtonStates ) ;
2013-06-03 20:46:41 +00:00
d - > m_undoStack - > push ( uc ) ;
}
2007-10-28 18:31:33 +00:00
BookmarkManager * Document : : bookmarkManager ( ) const
2007-01-02 19:05:49 +00:00
{
return d - > m_bookmarkManager ;
}
2004-12-22 18:21:36 +00:00
2007-11-26 21:43:54 +00:00
QList < int > Document : : bookmarkedPageList ( ) const
{
QList < int > list ;
uint docPages = pages ( ) ;
//pages are 0-indexed internally, but 1-indexed externally
for ( uint i = 0 ; i < docPages ; i + + )
{
if ( bookmarkManager ( ) - > isBookmarked ( i ) )
{
list < < i + 1 ;
}
}
return list ;
}
QString Document : : bookmarkedPageRange ( ) const
{
// Code formerly in Part::slotPrint()
// range detecting
QString range ;
uint docPages = pages ( ) ;
int startId = - 1 ;
int endId = - 1 ;
for ( uint i = 0 ; i < docPages ; + + i )
{
if ( bookmarkManager ( ) - > isBookmarked ( i ) )
{
if ( startId < 0 )
startId = i ;
if ( endId < 0 )
endId = startId ;
else
+ + endId ;
}
else if ( startId > = 0 & & endId > = 0 )
{
if ( ! range . isEmpty ( ) )
range + = ' , ' ;
if ( endId - startId > 0 )
range + = QString ( " %1-%2 " ) . arg ( startId + 1 ) . arg ( endId + 1 ) ;
else
range + = QString : : number ( startId + 1 ) ;
startId = - 1 ;
endId = - 1 ;
}
}
if ( startId > = 0 & & endId > = 0 )
{
if ( ! range . isEmpty ( ) )
range + = ' , ' ;
if ( endId - startId > 0 )
range + = QString ( " %1-%2 " ) . arg ( startId + 1 ) . arg ( endId + 1 ) ;
else
range + = QString : : number ( startId + 1 ) ;
}
return range ;
}
2007-04-20 12:49:17 +00:00
void Document : : processAction ( const Action * action )
2007-01-02 19:05:49 +00:00
{
2007-04-20 12:49:17 +00:00
if ( ! action )
2007-01-02 19:05:49 +00:00
return ;
2004-12-24 10:24:10 +00:00
2007-04-20 12:49:17 +00:00
switch ( action - > actionType ( ) )
2004-12-22 18:21:36 +00:00
{
2007-04-20 12:37:12 +00:00
case Action : : Goto : {
2007-05-02 22:50:27 +00:00
const GotoAction * go = static_cast < const GotoAction * > ( action ) ;
2007-01-02 19:05:49 +00:00
d - > m_nextDocumentViewport = go - > destViewport ( ) ;
2009-05-13 14:24:30 +00:00
d - > m_nextDocumentDestination = go - > destinationName ( ) ;
2007-01-02 19:05:49 +00:00
// Explanation of why d->m_nextDocumentViewport is needed:
// all openRelativeFile does is launch a signal telling we
2007-03-10 05:38:23 +00:00
// want to open another URL, the problem is that when the file is
2007-01-02 19:05:49 +00:00
// non local, the loading is done assynchronously so you can't
// do a setViewport after the if as it was because you are doing the setViewport
// on the old file and when the new arrives there is no setViewport for it and
// it does not show anything
// first open filename if link is pointing outside this document
if ( go - > isExternal ( ) & & ! d - > openRelativeFile ( go - > fileName ( ) ) )
2005-01-21 20:05:36 +00:00
{
2007-11-25 12:18:10 +00:00
kWarning ( OkularDebug ) . nospace ( ) < < " Action: Error opening ' " < < go - > fileName ( ) < < " '. " ;
2007-01-02 19:05:49 +00:00
return ;
}
else
{
2009-05-13 14:24:30 +00:00
const DocumentViewport nextViewport = d - > nextDocumentViewport ( ) ;
2007-01-02 19:05:49 +00:00
// skip local links that point to nowhere (broken ones)
2009-05-13 14:24:30 +00:00
if ( ! nextViewport . isValid ( ) )
2007-01-02 19:05:49 +00:00
return ;
2004-12-22 18:21:36 +00:00
2013-02-24 21:58:53 +00:00
setViewport ( nextViewport , 0 , true ) ;
2007-01-02 19:05:49 +00:00
d - > m_nextDocumentViewport = DocumentViewport ( ) ;
2009-05-13 14:24:30 +00:00
d - > m_nextDocumentDestination = QString ( ) ;
2007-01-02 19:05:49 +00:00
}
2004-12-22 18:21:36 +00:00
2007-01-02 19:05:49 +00:00
} break ;
2004-12-21 12:38:52 +00:00
2007-04-20 12:37:12 +00:00
case Action : : Execute : {
2007-05-02 22:50:27 +00:00
const ExecuteAction * exe = static_cast < const ExecuteAction * > ( action ) ;
2007-01-02 19:05:49 +00:00
QString fileName = exe - > fileName ( ) ;
if ( fileName . endsWith ( " .pdf " ) | | fileName . endsWith ( " .PDF " ) )
{
d - > openRelativeFile ( fileName ) ;
return ;
}
2004-12-21 12:38:52 +00:00
2007-01-02 19:05:49 +00:00
// Albert: the only pdf i have that has that kind of link don't define
// an application and use the fileName as the file to open
fileName = d - > giveAbsolutePath ( fileName ) ;
KMimeType : : Ptr mime = KMimeType : : findByPath ( fileName ) ;
// Check executables
if ( KRun : : isExecutableFile ( fileName , mime - > name ( ) ) )
{
// Don't have any pdf that uses this code path, just a guess on how it should work
if ( ! exe - > parameters ( ) . isEmpty ( ) )
{
fileName = d - > giveAbsolutePath ( exe - > parameters ( ) ) ;
mime = KMimeType : : findByPath ( fileName ) ;
if ( KRun : : isExecutableFile ( fileName , mime - > name ( ) ) )
{
// this case is a link pointing to an executable with a parameter
// that also is an executable, possibly a hand-crafted pdf
2014-05-09 17:56:16 +00:00
KMessageBox : : information ( d - > m_widget , i18n ( " The document is trying to execute an external application and, for your safety, Okular does not allow that. " ) ) ;
2007-01-02 19:05:49 +00:00
return ;
}
}
else
{
// this case is a link pointing to an executable with no parameters
// core developers find unacceptable executing it even after asking the user
2014-05-09 17:56:16 +00:00
KMessageBox : : information ( d - > m_widget , i18n ( " The document is trying to execute an external application and, for your safety, Okular does not allow that. " ) ) ;
2007-01-02 19:05:49 +00:00
return ;
}
}
2006-11-15 19:39:39 +00:00
2007-01-02 19:05:49 +00:00
KService : : Ptr ptr = KMimeTypeTrader : : self ( ) - > preferredService ( mime - > name ( ) , " Application " ) ;
if ( ptr )
{
KUrl : : List lst ;
lst . append ( fileName ) ;
KRun : : run ( * ptr , lst , 0 ) ;
}
else
2014-05-09 17:56:16 +00:00
KMessageBox : : information ( d - > m_widget , i18n ( " No application found for opening file of mimetype %1. " , mime - > name ( ) ) ) ;
2007-01-02 19:05:49 +00:00
} break ;
2007-05-02 22:50:27 +00:00
case Action : : DocAction : {
const DocumentAction * docaction = static_cast < const DocumentAction * > ( action ) ;
2007-04-20 19:32:09 +00:00
switch ( docaction - > documentActionType ( ) )
2007-01-02 19:05:49 +00:00
{
2007-05-02 22:50:27 +00:00
case DocumentAction : : PageFirst :
2007-01-02 19:05:49 +00:00
setViewportPage ( 0 ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : PagePrev :
2007-01-02 19:05:49 +00:00
if ( ( * d - > m_viewportIterator ) . pageNumber > 0 )
setViewportPage ( ( * d - > m_viewportIterator ) . pageNumber - 1 ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : PageNext :
2007-01-02 19:05:49 +00:00
if ( ( * d - > m_viewportIterator ) . pageNumber < ( int ) d - > m_pagesVector . count ( ) - 1 )
setViewportPage ( ( * d - > m_viewportIterator ) . pageNumber + 1 ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : PageLast :
2007-01-02 19:05:49 +00:00
setViewportPage ( d - > m_pagesVector . count ( ) - 1 ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : HistoryBack :
2007-01-02 19:05:49 +00:00
setPrevViewport ( ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : HistoryForward :
2007-01-02 19:05:49 +00:00
setNextViewport ( ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : Quit :
2007-01-02 19:05:49 +00:00
emit quit ( ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : Presentation :
2007-01-02 19:05:49 +00:00
emit linkPresentation ( ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : EndPresentation :
2007-01-02 19:05:49 +00:00
emit linkEndPresentation ( ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : Find :
2007-01-02 19:05:49 +00:00
emit linkFind ( ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : GoToPage :
2007-01-02 19:05:49 +00:00
emit linkGoToPage ( ) ;
break ;
2007-05-02 22:50:27 +00:00
case DocumentAction : : Close :
2007-01-02 19:05:49 +00:00
emit close ( ) ;
break ;
}
} break ;
2006-11-15 19:39:39 +00:00
2007-04-20 12:37:12 +00:00
case Action : : Browse : {
2007-05-02 22:50:27 +00:00
const BrowseAction * browse = static_cast < const BrowseAction * > ( action ) ;
2008-09-22 13:41:28 +00:00
QString lilySource ;
int lilyRow = 0 , lilyCol = 0 ;
2007-01-02 19:05:49 +00:00
// if the url is a mailto one, invoke mailer
if ( browse - > url ( ) . startsWith ( " mailto: " , Qt : : CaseInsensitive ) )
KToolInvocation : : invokeMailer ( browse - > url ( ) ) ;
2008-09-22 13:41:28 +00:00
else if ( extractLilyPondSourceReference ( browse - > url ( ) , & lilySource , & lilyRow , & lilyCol ) )
{
const SourceReference ref ( lilySource , lilyRow , lilyCol ) ;
processSourceReference ( & ref ) ;
}
2007-01-02 19:05:49 +00:00
else
{
QString url = browse - > url ( ) ;
2004-12-21 12:38:52 +00:00
2007-01-02 19:05:49 +00:00
// fix for #100366, documents with relative links that are the form of http:foo.pdf
if ( url . indexOf ( " http: " ) = = 0 & & url . indexOf ( " http:// " ) = = - 1 & & url . right ( 4 ) = = " .pdf " )
{
d - > openRelativeFile ( url . mid ( 5 ) ) ;
return ;
}
2006-11-15 19:39:39 +00:00
2008-06-05 20:22:46 +00:00
KUrl realUrl = KUrl ( url ) ;
2008-06-05 20:08:07 +00:00
// handle documents with relative path
if ( d - > m_url . isValid ( ) )
{
2008-06-05 20:22:46 +00:00
realUrl = KUrl ( d - > m_url . upUrl ( ) , url ) ;
2008-06-05 20:08:07 +00:00
}
2007-03-10 05:38:23 +00:00
// Albert: this is not a leak!
2014-05-09 17:56:16 +00:00
new KRun ( realUrl , d - > m_widget ) ;
2007-01-02 19:05:49 +00:00
}
} break ;
2006-11-15 19:39:39 +00:00
2007-04-20 12:37:12 +00:00
case Action : : Sound : {
2007-05-02 22:50:27 +00:00
const SoundAction * linksound = static_cast < const SoundAction * > ( action ) ;
2007-02-05 00:49:40 +00:00
AudioPlayer : : instance ( ) - > playSound ( linksound - > sound ( ) , linksound ) ;
} break ;
2008-04-13 22:31:59 +00:00
case Action : : Script : {
const ScriptAction * linkscript = static_cast < const ScriptAction * > ( action ) ;
if ( ! d - > m_scripter )
d - > m_scripter = new Scripter ( d ) ;
d - > m_scripter - > execute ( linkscript - > scriptType ( ) , linkscript - > script ( ) ) ;
} break ;
2007-04-20 12:37:12 +00:00
case Action : : Movie :
2012-04-03 12:18:10 +00:00
emit processMovieAction ( static_cast < const MovieAction * > ( action ) ) ;
2007-01-02 19:05:49 +00:00
break ;
2012-09-27 12:15:04 +00:00
case Action : : Rendition : {
const RenditionAction * linkrendition = static_cast < const RenditionAction * > ( action ) ;
if ( ! linkrendition - > script ( ) . isEmpty ( ) )
{
if ( ! d - > m_scripter )
d - > m_scripter = new Scripter ( d ) ;
d - > m_scripter - > execute ( linkrendition - > scriptType ( ) , linkrendition - > script ( ) ) ;
}
else
{
emit processRenditionAction ( static_cast < const RenditionAction * > ( action ) ) ;
}
} break ;
2007-01-02 19:05:49 +00:00
}
2004-12-21 12:38:52 +00:00
}
2007-01-02 19:05:49 +00:00
void Document : : processSourceReference ( const SourceReference * ref )
2005-01-03 00:28:46 +00:00
{
2007-01-02 19:05:49 +00:00
if ( ! ref )
2005-01-28 17:21:51 +00:00
return ;
2009-03-23 01:22:17 +00:00
const KUrl url ( d - > giveAbsolutePath ( ref - > fileName ( ) ) ) ;
if ( ! url . isLocalFile ( ) )
2005-01-03 00:28:46 +00:00
{
2009-03-23 01:22:17 +00:00
kDebug ( OkularDebug ) < < url . url ( ) < < " is not a local file. " ;
return ;
}
const QString absFileName = url . toLocalFile ( ) ;
if ( ! QFile : : exists ( absFileName ) )
{
kDebug ( OkularDebug ) < < " No such file: " < < absFileName ;
2005-01-28 17:21:51 +00:00
return ;
}
2005-01-03 00:28:46 +00:00
2011-09-10 17:15:52 +00:00
bool handled = false ;
2011-10-23 13:22:58 +00:00
emit sourceReferenceActivated ( absFileName , ref - > row ( ) , ref - > column ( ) , & handled ) ;
2011-09-10 17:15:52 +00:00
if ( handled ) {
return ;
}
2007-01-02 19:05:49 +00:00
static QHash < int , QString > editors ;
// init the editors table if empty (on first run, usually)
if ( editors . isEmpty ( ) )
2005-01-28 17:21:51 +00:00
{
2008-10-19 18:01:16 +00:00
editors = buildEditorsMap ( ) ;
2007-01-02 19:05:49 +00:00
}
2005-03-13 13:14:44 +00:00
2012-10-15 22:27:42 +00:00
QHash < int , QString > : : const_iterator it = editors . constFind ( SettingsCore : : externalEditor ( ) ) ;
2007-01-02 19:05:49 +00:00
QString p ;
2008-11-11 18:48:40 +00:00
if ( it ! = editors . constEnd ( ) )
2007-01-02 19:05:49 +00:00
p = * it ;
else
2012-10-15 22:27:42 +00:00
p = SettingsCore : : externalEditorCommand ( ) ;
2007-01-02 19:05:49 +00:00
// custom editor not yet configured
if ( p . isEmpty ( ) )
return ;
2005-01-28 17:21:51 +00:00
2008-10-19 19:40:17 +00:00
// manually append the %f placeholder if not specified
if ( p . indexOf ( QLatin1String ( " %f " ) ) = = - 1 )
p . append ( QLatin1String ( " %f " ) ) ;
2005-01-28 17:21:51 +00:00
2008-10-19 19:40:17 +00:00
// replacing the placeholders
QHash < QChar , QString > map ;
2009-03-23 01:22:17 +00:00
map . insert ( ' f ' , absFileName ) ;
2008-10-19 19:40:17 +00:00
map . insert ( ' c ' , QString : : number ( ref - > column ( ) ) ) ;
map . insert ( ' l ' , QString : : number ( ref - > row ( ) ) ) ;
const QString cmd = KMacroExpander : : expandMacrosShellQuote ( p , map ) ;
if ( cmd . isEmpty ( ) )
return ;
const QStringList args = KShell : : splitArgs ( cmd ) ;
if ( args . isEmpty ( ) )
2007-01-02 19:05:49 +00:00
return ;
2005-03-13 13:14:44 +00:00
2008-10-19 19:40:17 +00:00
KProcess : : startDetached ( args ) ;
2005-01-03 00:28:46 +00:00
}
2009-07-27 14:15:33 +00:00
const SourceReference * Document : : dynamicSourceReference ( int pageNr , double absX , double absY )
{
const SourceReference * ref = 0 ;
if ( d - > m_generator )
{
QMetaObject : : invokeMethod ( d - > m_generator , " dynamicSourceReference " , Qt : : DirectConnection , Q_RETURN_ARG ( const Okular : : SourceReference * , ref ) , Q_ARG ( int , pageNr ) , Q_ARG ( double , absX ) , Q_ARG ( double , absY ) ) ;
}
return ref ;
}
2007-11-26 21:43:54 +00:00
Document : : PrintingType Document : : printingSupport ( ) const
{
if ( d - > m_generator )
{
if ( d - > m_generator - > hasFeature ( Generator : : PrintNative ) )
{
return NativePrinting ;
}
# ifndef Q_OS_WIN
if ( d - > m_generator - > hasFeature ( Generator : : PrintPostscript ) )
{
return PostscriptPrinting ;
}
# endif
}
return NoPrinting ;
}
bool Document : : supportsPrintToFile ( ) const
{
return d - > m_generator ? d - > m_generator - > hasFeature ( Generator : : PrintToFile ) : false ;
}
2007-10-15 23:01:27 +00:00
bool Document : : print ( QPrinter & printer )
2004-10-17 18:40:02 +00:00
{
2007-01-02 19:05:49 +00:00
return d - > m_generator ? d - > m_generator - > print ( printer ) : false ;
2004-10-17 18:40:02 +00:00
}
2010-04-14 23:07:27 +00:00
QString Document : : printError ( ) const
{
2010-04-14 23:33:14 +00:00
Okular : : Generator : : PrintError err = Generator : : UnknownPrintError ;
if ( d - > m_generator )
{
QMetaObject : : invokeMethod ( d - > m_generator , " printError " , Qt : : DirectConnection , Q_RETURN_ARG ( Okular : : Generator : : PrintError , err ) ) ;
}
2010-04-14 23:07:27 +00:00
Q_ASSERT ( err ! = Generator : : NoPrintError ) ;
switch ( err )
{
case Generator : : TemporaryFileOpenPrintError :
return i18n ( " Could not open a temporary file " ) ;
case Generator : : FileConversionPrintError :
return i18n ( " Print conversion failed " ) ;
case Generator : : PrintingProcessCrashPrintError :
return i18n ( " Printing process crashed " ) ;
case Generator : : PrintingProcessStartPrintError :
return i18n ( " Printing process could not start " ) ;
case Generator : : PrintToFilePrintError :
return i18n ( " Printing to file failed " ) ;
case Generator : : InvalidPrinterStatePrintError :
return i18n ( " Printer was in invalid state " ) ;
case Generator : : UnableToFindFilePrintError :
return i18n ( " Unable to find file to print " ) ;
case Generator : : NoFileToPrintError :
return i18n ( " There was no file to print " ) ;
case Generator : : NoBinaryToPrintError :
2010-07-11 15:32:43 +00:00
return i18n ( " Could not find a suitable binary for printing. Make sure CUPS lpr binary is available " ) ;
2014-01-12 18:20:54 +00:00
case Generator : : InvalidPageSizePrintError :
return i18n ( " The page print size is invalid " ) ;
2010-04-14 23:07:27 +00:00
case Generator : : NoPrintError :
return QString ( ) ;
case Generator : : UnknownPrintError :
return QString ( ) ;
}
2013-04-05 22:22:48 +00:00
2010-04-14 23:07:27 +00:00
return QString ( ) ;
}
2007-10-15 23:01:27 +00:00
QWidget * Document : : printConfigurationWidget ( ) const
2004-10-06 00:05:49 +00:00
{
2007-01-02 19:05:49 +00:00
if ( d - > m_generator )
{
PrintInterface * iface = qobject_cast < Okular : : PrintInterface * > ( d - > m_generator ) ;
2007-01-12 23:48:29 +00:00
return iface ? iface - > printConfigurationWidget ( ) : 0 ;
2007-01-02 19:05:49 +00:00
}
else
return 0 ;
2004-10-06 00:05:49 +00:00
}
2007-01-28 15:46:10 +00:00
void Document : : fillConfigDialog ( KConfigDialog * dialog )
{
if ( ! dialog )
return ;
2007-01-28 16:10:12 +00:00
// ensure that we have all the generators with settings loaded
QString constraint ( " ([X-KDE-Priority] > 0) and ( exist Library ) and ( [ X - KDE - okularHasInternalSettings ] ) " ) ;
KService : : List offers = KServiceTypeTrader : : self ( ) - > query ( " okular/Generator " , constraint ) ;
d - > loadServiceList ( offers ) ;
2007-01-28 15:46:10 +00:00
2007-07-12 20:04:56 +00:00
bool pagesAdded = false ;
2007-01-28 15:46:10 +00:00
QHash < QString , GeneratorInfo > : : iterator it = d - > m_loadedGenerators . begin ( ) ;
QHash < QString , GeneratorInfo > : : iterator itEnd = d - > m_loadedGenerators . end ( ) ;
for ( ; it ! = itEnd ; + + it )
{
2007-11-25 12:49:30 +00:00
Okular : : ConfigInterface * iface = d - > generatorConfig ( it . value ( ) ) ;
2007-01-28 15:46:10 +00:00
if ( iface )
2007-07-12 17:52:14 +00:00
{
2007-01-28 15:46:10 +00:00
iface - > addPages ( dialog ) ;
2007-07-12 20:04:56 +00:00
pagesAdded = true ;
2007-11-25 12:49:30 +00:00
if ( ! it . value ( ) . catalogName . isEmpty ( ) )
KGlobal : : locale ( ) - > insertCatalog ( it . value ( ) . catalogName ) ;
2007-07-12 17:52:14 +00:00
}
2007-01-28 15:46:10 +00:00
}
2007-07-12 20:04:56 +00:00
if ( pagesAdded )
{
2011-07-31 19:22:04 +00:00
connect ( dialog , SIGNAL ( settingsChanged ( QString ) ) ,
this , SLOT ( slotGeneratorConfigChanged ( QString ) ) ) ;
2007-07-12 20:04:56 +00:00
}
2007-01-28 15:46:10 +00:00
}
2007-07-12 17:52:14 +00:00
int Document : : configurableGenerators ( ) const
{
QString constraint ( " ([X-KDE-Priority] > 0) and ( exist Library ) and ( [ X - KDE - okularHasInternalSettings ] ) " ) ;
KService : : List offers = KServiceTypeTrader : : self ( ) - > query ( " okular/Generator " , constraint ) ;
2007-07-30 22:29:41 +00:00
return offers . count ( ) ;
2007-07-12 17:52:14 +00:00
}
2007-01-28 15:46:10 +00:00
QStringList Document : : supportedMimeTypes ( ) const
{
if ( ! d - > m_supportedMimeTypes . isEmpty ( ) )
return d - > m_supportedMimeTypes ;
2008-01-02 00:37:51 +00:00
QString constraint ( " (Library == 'okularpart') " ) ;
QLatin1String basePartService ( " KParts/ReadOnlyPart " ) ;
KService : : List offers = KServiceTypeTrader : : self ( ) - > query ( basePartService , constraint ) ;
2008-11-11 18:48:40 +00:00
KService : : List : : ConstIterator it = offers . constBegin ( ) , itEnd = offers . constEnd ( ) ;
2007-01-28 15:46:10 +00:00
for ( ; it ! = itEnd ; + + it )
{
KService : : Ptr service = * it ;
QStringList mimeTypes = service - > serviceTypes ( ) ;
foreach ( const QString & mimeType , mimeTypes )
2008-01-02 00:37:51 +00:00
if ( mimeType ! = basePartService )
2007-01-28 15:46:10 +00:00
d - > m_supportedMimeTypes . append ( mimeType ) ;
}
return d - > m_supportedMimeTypes ;
}
2007-03-07 18:15:00 +00:00
const KComponentData * Document : : componentData ( ) const
{
2007-11-24 18:07:59 +00:00
if ( ! d - > m_generator )
return 0 ;
2007-12-02 20:57:24 +00:00
QHash < QString , GeneratorInfo > : : const_iterator genIt = d - > m_loadedGenerators . constFind ( d - > m_generatorName ) ;
Q_ASSERT ( genIt ! = d - > m_loadedGenerators . constEnd ( ) ) ;
const KComponentData * kcd = & genIt . value ( ) . data ;
2007-11-24 18:07:59 +00:00
// empty about data
2007-12-02 20:57:24 +00:00
if ( kcd - > isValid ( ) & & kcd - > aboutData ( ) & & kcd - > aboutData ( ) - > programName ( ) . isEmpty ( ) )
2007-11-24 18:07:59 +00:00
return 0 ;
return kcd ;
2007-03-07 18:15:00 +00:00
}
2008-03-11 23:40:59 +00:00
bool Document : : canSaveChanges ( ) const
{
if ( ! d - > m_generator )
return false ;
Q_ASSERT ( ! d - > m_generatorName . isEmpty ( ) ) ;
QHash < QString , GeneratorInfo > : : iterator genIt = d - > m_loadedGenerators . find ( d - > m_generatorName ) ;
Q_ASSERT ( genIt ! = d - > m_loadedGenerators . end ( ) ) ;
SaveInterface * saveIface = d - > generatorSave ( genIt . value ( ) ) ;
if ( ! saveIface )
return false ;
return saveIface - > supportsOption ( SaveInterface : : SaveChanges ) ;
}
2012-06-13 13:33:49 +00:00
bool Document : : canSaveChanges ( SaveCapability cap ) const
{
switch ( cap )
{
2012-06-13 22:27:22 +00:00
case SaveFormsCapability :
2012-06-13 13:33:49 +00:00
/* Assume that if the generator supports saving, forms can be saved.
* We have no means to actually query the generator at the moment
* TODO : Add some method to query the generator in SaveInterface */
return canSaveChanges ( ) ;
2012-06-13 22:27:22 +00:00
case SaveAnnotationsCapability :
2012-06-13 13:33:49 +00:00
return d - > canAddAnnotationsNatively ( ) ;
}
return false ;
}
2008-03-11 23:40:59 +00:00
bool Document : : saveChanges ( const QString & fileName )
2009-10-19 23:00:52 +00:00
{
QString errorText ;
return saveChanges ( fileName , & errorText ) ;
}
bool Document : : saveChanges ( const QString & fileName , QString * errorText )
2008-03-11 23:40:59 +00:00
{
if ( ! d - > m_generator | | fileName . isEmpty ( ) )
return false ;
Q_ASSERT ( ! d - > m_generatorName . isEmpty ( ) ) ;
QHash < QString , GeneratorInfo > : : iterator genIt = d - > m_loadedGenerators . find ( d - > m_generatorName ) ;
Q_ASSERT ( genIt ! = d - > m_loadedGenerators . end ( ) ) ;
SaveInterface * saveIface = d - > generatorSave ( genIt . value ( ) ) ;
if ( ! saveIface | | ! saveIface - > supportsOption ( SaveInterface : : SaveChanges ) )
return false ;
2009-10-19 23:00:52 +00:00
return saveIface - > save ( fileName , SaveInterface : : SaveChanges , errorText ) ;
2008-03-11 23:40:59 +00:00
}
2008-04-27 11:05:59 +00:00
void Document : : registerView ( View * view )
{
if ( ! view )
return ;
Document * viewDoc = view - > viewDocument ( ) ;
if ( viewDoc )
{
// check if already registered for this document
if ( viewDoc = = this )
return ;
viewDoc - > unregisterView ( view ) ;
}
d - > m_views . insert ( view ) ;
view - > d_func ( ) - > document = d ;
}
void Document : : unregisterView ( View * view )
{
if ( ! view )
return ;
Document * viewDoc = view - > viewDocument ( ) ;
if ( ! viewDoc | | viewDoc ! = this )
return ;
view - > d_func ( ) - > document = 0 ;
d - > m_views . remove ( view ) ;
}
2008-08-01 20:26:22 +00:00
QByteArray Document : : fontData ( const FontInfo & font ) const
{
QByteArray result ;
2013-04-05 22:22:48 +00:00
2008-08-01 20:26:22 +00:00
if ( d - > m_generator )
{
QMetaObject : : invokeMethod ( d - > m_generator , " requestFontData " , Qt : : DirectConnection , Q_ARG ( Okular : : FontInfo , font ) , Q_ARG ( QByteArray * , & result ) ) ;
}
2013-04-05 22:22:48 +00:00
2008-08-01 20:26:22 +00:00
return result ;
}
2014-05-09 17:56:16 +00:00
Document : : OpenResult Document : : openDocumentArchive ( const QString & docFile , const KUrl & url , const QString & password )
2008-11-15 14:15:31 +00:00
{
const KMimeType : : Ptr mime = KMimeType : : findByPath ( docFile , 0 , false /* content too */ ) ;
2008-11-16 01:17:48 +00:00
if ( ! mime - > is ( " application/vnd.kde.okular-archive " ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2008-11-15 14:15:31 +00:00
KZip okularArchive ( docFile ) ;
if ( ! okularArchive . open ( QIODevice : : ReadOnly ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2008-11-15 14:15:31 +00:00
const KArchiveDirectory * mainDir = okularArchive . directory ( ) ;
const KArchiveEntry * mainEntry = mainDir - > entry ( " content.xml " ) ;
if ( ! mainEntry | | ! mainEntry - > isFile ( ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2008-11-15 14:15:31 +00:00
std : : auto_ptr < QIODevice > mainEntryDevice ( static_cast < const KZipFileEntry * > ( mainEntry ) - > createDevice ( ) ) ;
QDomDocument doc ;
if ( ! doc . setContent ( mainEntryDevice . get ( ) ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2008-11-15 14:15:31 +00:00
mainEntryDevice . reset ( ) ;
QDomElement root = doc . documentElement ( ) ;
if ( root . tagName ( ) ! = " OkularArchive " )
2014-05-09 17:56:16 +00:00
return OpenError ;
2008-11-15 14:15:31 +00:00
QString documentFileName ;
QString metadataFileName ;
QDomElement el = root . firstChild ( ) . toElement ( ) ;
for ( ; ! el . isNull ( ) ; el = el . nextSibling ( ) . toElement ( ) )
{
if ( el . tagName ( ) = = " Files " )
{
QDomElement fileEl = el . firstChild ( ) . toElement ( ) ;
for ( ; ! fileEl . isNull ( ) ; fileEl = fileEl . nextSibling ( ) . toElement ( ) )
{
if ( fileEl . tagName ( ) = = " DocumentFileName " )
documentFileName = fileEl . text ( ) ;
else if ( fileEl . tagName ( ) = = " MetadataFileName " )
metadataFileName = fileEl . text ( ) ;
}
}
}
if ( documentFileName . isEmpty ( ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2008-11-15 14:15:31 +00:00
const KArchiveEntry * docEntry = mainDir - > entry ( documentFileName ) ;
if ( ! docEntry | | ! docEntry - > isFile ( ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2008-11-15 14:15:31 +00:00
std : : auto_ptr < ArchiveData > archiveData ( new ArchiveData ( ) ) ;
const int dotPos = documentFileName . indexOf ( ' . ' ) ;
if ( dotPos ! = - 1 )
archiveData - > document . setSuffix ( documentFileName . mid ( dotPos ) ) ;
if ( ! archiveData - > document . open ( ) )
2014-05-09 17:56:16 +00:00
return OpenError ;
2008-11-15 14:15:31 +00:00
QString tempFileName = archiveData - > document . fileName ( ) ;
{
std : : auto_ptr < QIODevice > docEntryDevice ( static_cast < const KZipFileEntry * > ( docEntry ) - > createDevice ( ) ) ;
copyQIODevice ( docEntryDevice . get ( ) , & archiveData - > document ) ;
archiveData - > document . close ( ) ;
}
const KArchiveEntry * metadataEntry = mainDir - > entry ( metadataFileName ) ;
if ( metadataEntry & & metadataEntry - > isFile ( ) )
{
std : : auto_ptr < QIODevice > metadataEntryDevice ( static_cast < const KZipFileEntry * > ( metadataEntry ) - > createDevice ( ) ) ;
2014-05-10 09:35:33 +00:00
archiveData - > metadataFile . setSuffix ( " .xml " ) ;
if ( archiveData - > metadataFile . open ( ) )
2008-11-15 14:15:31 +00:00
{
2014-05-10 09:35:33 +00:00
copyQIODevice ( metadataEntryDevice . get ( ) , & archiveData - > metadataFile ) ;
archiveData - > metadataFile . close ( ) ;
2008-11-15 14:15:31 +00:00
}
}
const KMimeType : : Ptr docMime = KMimeType : : findByPath ( tempFileName , 0 , true /* local file */ ) ;
d - > m_archiveData = archiveData . get ( ) ;
2012-06-07 15:05:00 +00:00
d - > m_archivedFileName = documentFileName ;
2014-05-09 17:56:16 +00:00
const OpenResult ret = openDocument ( tempFileName , url , docMime , password ) ;
2008-11-15 14:15:31 +00:00
2014-05-09 17:56:16 +00:00
if ( ret = = OpenSuccess )
2008-11-15 14:15:31 +00:00
{
archiveData . release ( ) ;
}
else
{
d - > m_archiveData = 0 ;
}
return ret ;
}
bool Document : : saveDocumentArchive ( const QString & fileName )
{
if ( ! d - > m_generator )
return false ;
2012-06-07 15:05:00 +00:00
/* If we opened an archive, use the name of original file (eg foo.pdf)
* instead of the archive ' s one ( eg foo . okular ) */
QString docFileName = d - > m_archiveData ? d - > m_archivedFileName : d - > m_url . fileName ( ) ;
2008-11-15 14:15:31 +00:00
if ( docFileName = = QLatin1String ( " - " ) )
return false ;
2010-08-10 23:49:30 +00:00
QString docPath = d - > m_docFileName ;
const QFileInfo fi ( docPath ) ;
if ( fi . isSymLink ( ) )
docPath = fi . symLinkTarget ( ) ;
2008-11-15 14:15:31 +00:00
KZip okularArchive ( fileName ) ;
if ( ! okularArchive . open ( QIODevice : : WriteOnly ) )
return false ;
const KUser user ;
2008-11-17 22:16:28 +00:00
# ifndef Q_OS_WIN
2008-11-15 14:15:31 +00:00
const KUserGroup userGroup ( user . gid ( ) ) ;
2008-11-17 22:16:28 +00:00
# else
const KUserGroup userGroup ( QString ( " " ) ) ;
# endif
2008-11-15 14:15:31 +00:00
QDomDocument contentDoc ( " OkularArchive " ) ;
QDomProcessingInstruction xmlPi = contentDoc . createProcessingInstruction (
QString : : fromLatin1 ( " xml " ) , QString : : fromLatin1 ( " version= \" 1.0 \" encoding= \" utf-8 \" " ) ) ;
contentDoc . appendChild ( xmlPi ) ;
QDomElement root = contentDoc . createElement ( " OkularArchive " ) ;
contentDoc . appendChild ( root ) ;
QDomElement filesNode = contentDoc . createElement ( " Files " ) ;
root . appendChild ( filesNode ) ;
QDomElement fileNameNode = contentDoc . createElement ( " DocumentFileName " ) ;
filesNode . appendChild ( fileNameNode ) ;
fileNameNode . appendChild ( contentDoc . createTextNode ( docFileName ) ) ;
QDomElement metadataFileNameNode = contentDoc . createElement ( " MetadataFileName " ) ;
filesNode . appendChild ( metadataFileNameNode ) ;
metadataFileNameNode . appendChild ( contentDoc . createTextNode ( " metadata.xml " ) ) ;
2012-05-14 13:51:58 +00:00
// If the generator can save annotations natively, do it
KTemporaryFile modifiedFile ;
bool annotationsSavedNatively = false ;
if ( d - > canAddAnnotationsNatively ( ) )
{
if ( ! modifiedFile . open ( ) )
return false ;
modifiedFile . close ( ) ; // We're only interested in the file name
QString errorText ;
if ( saveChanges ( modifiedFile . fileName ( ) , & errorText ) )
{
docPath = modifiedFile . fileName ( ) ; // Save this instead of the original file
annotationsSavedNatively = true ;
}
else
{
kWarning ( OkularDebug ) < < " saveChanges failed: " < < errorText ;
kDebug ( OkularDebug ) < < " Falling back to saving a copy of the original file " ;
}
}
2008-11-15 14:15:31 +00:00
KTemporaryFile metadataFile ;
2012-05-14 13:51:58 +00:00
PageItems saveWhat = annotationsSavedNatively ? None : AnnotationPageItems ;
if ( ! d - > savePageDocumentInfo ( & metadataFile , saveWhat ) )
2008-11-15 14:15:31 +00:00
return false ;
const QByteArray contentDocXml = contentDoc . toByteArray ( ) ;
okularArchive . writeFile ( " content.xml " , user . loginName ( ) , userGroup . name ( ) ,
contentDocXml . constData ( ) , contentDocXml . length ( ) ) ;
2010-08-10 23:49:30 +00:00
okularArchive . addLocalFile ( docPath , docFileName ) ;
2008-11-15 14:15:31 +00:00
okularArchive . addLocalFile ( metadataFile . fileName ( ) , " metadata.xml " ) ;
if ( ! okularArchive . close ( ) )
return false ;
return true ;
}
2011-06-05 22:40:22 +00:00
QPrinter : : Orientation Document : : orientation ( ) const
{
double width , height ;
int landscape , portrait ;
const Okular : : Page * currentPage ;
// if some pages are landscape and others are not, the most common wins, as
// QPrinter does not accept a per-page setting
landscape = 0 ;
portrait = 0 ;
for ( uint i = 0 ; i < pages ( ) ; i + + )
{
currentPage = page ( i ) ;
width = currentPage - > width ( ) ;
height = currentPage - > height ( ) ;
if ( currentPage - > orientation ( ) = = Okular : : Rotation90 | | currentPage - > orientation ( ) = = Okular : : Rotation270 ) qSwap ( width , height ) ;
if ( width > height ) landscape + + ;
else portrait + + ;
}
return ( landscape > portrait ) ? QPrinter : : Landscape : QPrinter : : Portrait ;
}
2012-05-23 21:43:44 +00:00
void Document : : setAnnotationEditingEnabled ( bool enable )
{
d - > m_annotationEditingEnabled = enable ;
foreachObserver ( notifySetup ( d - > m_pagesVector , 0 ) ) ;
}
2014-05-10 13:31:59 +00:00
void Document : : walletDataForFile ( const QString & fileName , QString * walletName , QString * walletFolder , QString * walletKey ) const
{
if ( d - > m_generator ) {
d - > m_generator - > walletDataForFile ( fileName , walletName , walletFolder , walletKey ) ;
}
}
2007-09-14 15:29:16 +00:00
void DocumentPrivate : : requestDone ( PixmapRequest * req )
2005-01-03 00:28:46 +00:00
{
2008-02-01 00:43:45 +00:00
if ( ! req )
return ;
if ( ! m_generator | | m_closingLoop )
{
m_pixmapRequestsMutex . lock ( ) ;
m_executingPixmapRequests . removeAll ( req ) ;
m_pixmapRequestsMutex . unlock ( ) ;
delete req ;
if ( m_closingLoop )
m_closingLoop - > exit ( ) ;
2007-05-24 22:52:29 +00:00
return ;
2008-02-01 00:43:45 +00:00
}
2007-05-24 22:52:29 +00:00
2007-01-02 19:05:49 +00:00
# ifndef NDEBUG
2007-09-14 15:29:16 +00:00
if ( ! m_generator - > canGeneratePixmap ( ) )
2007-07-31 10:19:48 +00:00
kDebug ( OkularDebug ) < < " requestDone with generator not in READY state. " ;
2007-01-02 19:05:49 +00:00
# endif
2005-01-03 00:28:46 +00:00
2007-01-02 19:05:49 +00:00
// [MEM] 1.1 find and remove a previous entry for the same page and id
2012-07-01 23:05:02 +00:00
QLinkedList < AllocatedPixmap * > : : iterator aIt = m_allocatedPixmaps . begin ( ) ;
QLinkedList < AllocatedPixmap * > : : iterator aEnd = m_allocatedPixmaps . end ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; aIt ! = aEnd ; + + aIt )
2013-02-24 21:58:53 +00:00
if ( ( * aIt ) - > page = = req - > pageNumber ( ) & & ( * aIt ) - > observer = = req - > observer ( ) )
2005-01-27 17:31:07 +00:00
{
2007-01-02 19:05:49 +00:00
AllocatedPixmap * p = * aIt ;
2012-07-01 23:05:02 +00:00
m_allocatedPixmaps . erase ( aIt ) ;
2007-09-14 15:29:16 +00:00
m_allocatedPixmapsTotalMemory - = p - > memory ;
2007-01-02 19:05:49 +00:00
delete p ;
break ;
}
2005-01-28 17:21:51 +00:00
2013-02-24 21:58:53 +00:00
DocumentObserver * observer = req - > observer ( ) ;
if ( m_observers . contains ( observer ) )
2007-05-17 16:52:44 +00:00
{
// [MEM] 1.2 append memory allocation descriptor to the FIFO
2012-07-16 15:57:51 +00:00
qulonglong memoryBytes = 0 ;
2014-02-19 22:40:43 +00:00
const TilesManager * tm = req - > d - > tilesManager ( ) ;
2012-07-16 15:57:51 +00:00
if ( tm )
memoryBytes = tm - > totalMemory ( ) ;
else
memoryBytes = 4 * req - > width ( ) * req - > height ( ) ;
2013-02-24 21:58:53 +00:00
AllocatedPixmap * memoryPage = new AllocatedPixmap ( req - > observer ( ) , req - > pageNumber ( ) , memoryBytes ) ;
2012-07-01 23:05:02 +00:00
m_allocatedPixmaps . append ( memoryPage ) ;
2007-09-14 15:29:16 +00:00
m_allocatedPixmapsTotalMemory + = memoryBytes ;
2007-05-17 16:52:44 +00:00
// 2. notify an observer that its pixmap changed
2013-02-24 21:58:53 +00:00
observer - > notifyPageChanged ( req - > pageNumber ( ) , DocumentObserver : : Pixmap ) ;
2007-05-17 16:52:44 +00:00
}
# ifndef NDEBUG
else
2013-02-24 21:58:53 +00:00
kWarning ( OkularDebug ) < < " Receiving a done request for the defunct observer " < < observer ;
2007-05-17 16:52:44 +00:00
# endif
2005-01-28 17:21:51 +00:00
2007-01-02 19:05:49 +00:00
// 3. delete request
2008-02-01 00:43:45 +00:00
m_pixmapRequestsMutex . lock ( ) ;
m_executingPixmapRequests . removeAll ( req ) ;
m_pixmapRequestsMutex . unlock ( ) ;
2007-01-02 19:05:49 +00:00
delete req ;
2005-01-03 00:28:46 +00:00
2007-01-02 19:05:49 +00:00
// 4. start a new generation if some is pending
2007-09-14 15:29:16 +00:00
m_pixmapRequestsMutex . lock ( ) ;
bool hasPixmaps = ! m_pixmapRequestsStack . isEmpty ( ) ;
m_pixmapRequestsMutex . unlock ( ) ;
2007-05-12 21:40:38 +00:00
if ( hasPixmaps )
2012-09-25 09:09:34 +00:00
sendGeneratorPixmapRequest ( ) ;
2004-12-24 10:24:10 +00:00
}
2008-05-18 23:06:21 +00:00
void DocumentPrivate : : setPageBoundingBox ( int page , const NormalizedRect & boundingBox )
{
Page * kp = m_pagesVector [ page ] ;
if ( ! m_generator | | ! kp )
return ;
if ( kp - > boundingBox ( ) = = boundingBox )
return ;
kp - > setBoundingBox ( boundingBox ) ;
// notify observers about the change
foreachObserverD ( notifyPageChanged ( page , DocumentObserver : : BoundingBox ) ) ;
// TODO: For generators that generate the bbox by pixmap scanning, if the first generated pixmap is very small, the bounding box will forever be inaccurate.
// TODO: Crop computation should also consider annotations, actions, etc. to make sure they're not cropped away.
// TODO: Help compute bounding box for generators that create a QPixmap without a QImage, like text and plucker.
// TODO: Don't compute the bounding box if no one needs it (e.g., Trim Borders is off).
}
2008-05-04 15:10:32 +00:00
void DocumentPrivate : : calculateMaxTextPages ( )
{
int multipliers = qMax ( 1 , qRound ( getTotalMemory ( ) / 536870912.0 ) ) ; // 512 MB
2012-10-15 22:27:42 +00:00
switch ( SettingsCore : : memoryLevel ( ) )
2008-05-04 15:10:32 +00:00
{
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumMemoryLevel : : Low :
2008-05-04 15:10:32 +00:00
m_maxAllocatedTextPages = multipliers * 2 ;
break ;
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumMemoryLevel : : Normal :
2008-05-04 15:10:32 +00:00
m_maxAllocatedTextPages = multipliers * 50 ;
break ;
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumMemoryLevel : : Aggressive :
2008-05-04 15:10:32 +00:00
m_maxAllocatedTextPages = multipliers * 250 ;
break ;
2012-03-08 23:12:20 +00:00
2012-10-15 22:27:42 +00:00
case SettingsCore : : EnumMemoryLevel : : Greedy :
2012-03-08 23:12:20 +00:00
m_maxAllocatedTextPages = multipliers * 1250 ;
break ;
2008-05-04 15:10:32 +00:00
}
}
void DocumentPrivate : : textGenerationDone ( Page * page )
{
2014-07-31 23:27:27 +00:00
if ( ! m_pageController ) return ;
2008-05-04 15:10:32 +00:00
// 1. If we reached the cache limit, delete the first text page from the fifo
if ( m_allocatedTextPagesFifo . size ( ) = = m_maxAllocatedTextPages )
{
int pageToKick = m_allocatedTextPagesFifo . takeFirst ( ) ;
if ( pageToKick ! = page - > number ( ) ) // this should never happen but better be safe than sorry
{
m_pagesVector . at ( pageToKick ) - > setTextPage ( 0 ) ; // deletes the textpage
}
}
// 2. Add the page to the fifo of generated text pages
m_allocatedTextPagesFifo . append ( page - > number ( ) ) ;
}
2007-05-01 23:09:45 +00:00
void Document : : setRotation ( int r )
2007-11-01 16:15:34 +00:00
{
d - > setRotationInternal ( r , true ) ;
}
void DocumentPrivate : : setRotationInternal ( int r , bool notify )
2005-11-04 11:59:51 +00:00
{
2007-01-05 17:09:47 +00:00
Rotation rotation = ( Rotation ) r ;
2007-11-01 16:15:34 +00:00
if ( ! m_generator | | ( m_rotation = = rotation ) )
2007-07-17 18:13:50 +00:00
return ;
2006-10-25 15:35:53 +00:00
// tell the pages to rotate
2008-11-11 18:48:40 +00:00
QVector < Okular : : Page * > : : const_iterator pIt = m_pagesVector . constBegin ( ) ;
QVector < Okular : : Page * > : : const_iterator pEnd = m_pagesVector . constEnd ( ) ;
2006-10-25 15:35:53 +00:00
for ( ; pIt ! = pEnd ; + + pIt )
2007-05-01 23:36:57 +00:00
( * pIt ) - > d - > rotateAt ( rotation ) ;
2007-11-01 16:15:34 +00:00
if ( notify )
{
// notify the generator that the current rotation has changed
m_generator - > rotationChanged ( rotation , m_rotation ) ;
}
2006-10-25 15:35:53 +00:00
// set the new rotation
2007-11-01 16:15:34 +00:00
m_rotation = rotation ;
2006-10-25 15:35:53 +00:00
2007-11-01 16:15:34 +00:00
if ( notify )
{
foreachObserverD ( notifySetup ( m_pagesVector , DocumentObserver : : NewLayoutForPages ) ) ;
foreachObserverD ( notifyContentsCleared ( DocumentObserver : : Pixmap | DocumentObserver : : Highlights | DocumentObserver : : Annotations ) ) ;
}
2007-07-31 10:19:48 +00:00
kDebug ( OkularDebug ) < < " Rotated: " < < r ;
2005-11-04 11:59:51 +00:00
}
2005-01-09 23:37:07 +00:00
2007-05-01 23:21:29 +00:00
void Document : : setPageSize ( const PageSize & size )
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
{
2007-05-24 22:52:29 +00:00
if ( ! d - > m_generator | | ! d - > m_generator - > hasFeature ( Generator : : PageSizes ) )
return ;
if ( d - > m_pageSizes . isEmpty ( ) )
d - > m_pageSizes = d - > m_generator - > pageSizes ( ) ;
2007-05-01 23:21:29 +00:00
int sizeid = d - > m_pageSizes . indexOf ( size ) ;
2007-05-24 22:52:29 +00:00
if ( sizeid = = - 1 )
2007-01-05 23:12:06 +00:00
return ;
// tell the pages to change size
2008-11-11 18:48:40 +00:00
QVector < Okular : : Page * > : : const_iterator pIt = d - > m_pagesVector . constBegin ( ) ;
QVector < Okular : : Page * > : : const_iterator pEnd = d - > m_pagesVector . constEnd ( ) ;
2007-01-05 23:12:06 +00:00
for ( ; pIt ! = pEnd ; + + pIt )
2007-05-01 23:36:57 +00:00
( * pIt ) - > d - > changeSize ( size ) ;
2007-01-05 23:12:06 +00:00
// clear 'memory allocation' descriptors
2012-07-01 23:05:02 +00:00
qDeleteAll ( d - > m_allocatedPixmaps ) ;
d - > m_allocatedPixmaps . clear ( ) ;
2007-01-05 23:12:06 +00:00
d - > m_allocatedPixmapsTotalMemory = 0 ;
// notify the generator that the current page size has changed
2007-05-01 23:21:29 +00:00
d - > m_generator - > pageSizeChanged ( size , d - > m_pageSize ) ;
2007-01-05 23:12:06 +00:00
// set the new page size
2007-05-01 23:21:29 +00:00
d - > m_pageSize = size ;
2007-01-05 23:12:06 +00:00
2007-09-09 10:50:36 +00:00
foreachObserver ( notifySetup ( d - > m_pagesVector , DocumentObserver : : NewLayoutForPages ) ) ;
2007-01-17 23:06:40 +00:00
foreachObserver ( notifyContentsCleared ( DocumentObserver : : Pixmap | DocumentObserver : : Highlights ) ) ;
2007-07-31 10:19:48 +00:00
kDebug ( OkularDebug ) < < " New PageSize id: " < < sizeid ;
- GIGANTIC 2700 line diff with LOTS OF FEATURES!
- 1. editor-like text selection, and I do mean it, its not pseudo-editor
(like the ones acroread and kviewshell have) it doesnt intersect the
selection area with words under it, no, it does a lot more, including
work on cursors and searching for the text area closest to the given
cursor
- 2. rotation support, change the orientation of the documents if
you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender
instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended,
the kviewshell is only one state, while we support it in both
continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
it is an impressive bit right? but oKular cant be run by only one person,
join in on the fun! i can introduce you into the code just mail niedakh@gmail.com
svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
2006-02-15 18:54:49 +00:00
}
2007-01-17 14:20:00 +00:00
2005-01-09 23:37:07 +00:00
/** DocumentViewport **/
DocumentViewport : : DocumentViewport ( int n )
: pageNumber ( n )
{
// default settings
2005-06-13 11:53:47 +00:00
rePos . enabled = false ;
rePos . normalizedX = 0.5 ;
rePos . normalizedY = 0.0 ;
rePos . pos = Center ;
2005-01-09 23:37:07 +00:00
autoFit . enabled = false ;
autoFit . width = false ;
autoFit . height = false ;
}
2011-11-01 21:13:20 +00:00
DocumentViewport : : DocumentViewport ( const QString & xmlDesc )
: pageNumber ( - 1 )
2005-01-09 23:37:07 +00:00
{
// default settings (maybe overridden below)
2005-06-13 11:53:47 +00:00
rePos . enabled = false ;
rePos . normalizedX = 0.5 ;
rePos . normalizedY = 0.0 ;
rePos . pos = Center ;
2005-01-09 23:37:07 +00:00
autoFit . enabled = false ;
autoFit . width = false ;
autoFit . height = false ;
// check for string presence
if ( xmlDesc . isEmpty ( ) )
return ;
// decode the string
bool ok ;
int field = 0 ;
QString token = xmlDesc . section ( ' ; ' , field , field ) ;
while ( ! token . isEmpty ( ) )
{
// decode the current token
if ( field = = 0 )
{
pageNumber = token . toInt ( & ok ) ;
if ( ! ok )
return ;
}
else if ( token . startsWith ( " C1 " ) )
{
2005-06-13 11:53:47 +00:00
rePos . enabled = true ;
rePos . normalizedX = token . section ( ' : ' , 1 , 1 ) . toDouble ( ) ;
rePos . normalizedY = token . section ( ' : ' , 2 , 2 ) . toDouble ( ) ;
rePos . pos = Center ;
}
else if ( token . startsWith ( " C2 " ) )
{
rePos . enabled = true ;
rePos . normalizedX = token . section ( ' : ' , 1 , 1 ) . toDouble ( ) ;
rePos . normalizedY = token . section ( ' : ' , 2 , 2 ) . toDouble ( ) ;
if ( token . section ( ' : ' , 3 , 3 ) . toInt ( ) = = 1 ) rePos . pos = Center ;
else rePos . pos = TopLeft ;
2005-01-09 23:37:07 +00:00
}
else if ( token . startsWith ( " AF1 " ) )
{
autoFit . enabled = true ;
autoFit . width = token . section ( ' : ' , 1 , 1 ) = = " T " ;
autoFit . height = token . section ( ' : ' , 2 , 2 ) = = " T " ;
}
// proceed tokenizing string
field + + ;
token = xmlDesc . section ( ' ; ' , field , field ) ;
}
2004-12-22 18:21:36 +00:00
}
2005-01-09 23:37:07 +00:00
QString DocumentViewport : : toString ( ) const
{
// start string with page number
QString s = QString : : number ( pageNumber ) ;
// if has center coordinates, save them on string
2005-06-13 11:53:47 +00:00
if ( rePos . enabled )
s + = QString ( " ;C2: " ) + QString : : number ( rePos . normalizedX ) +
' : ' + QString : : number ( rePos . normalizedY ) +
' : ' + QString : : number ( rePos . pos ) ;
2005-01-09 23:37:07 +00:00
// if has autofit enabled, save its state on string
if ( autoFit . enabled )
s + = QString ( " ;AF1: " ) + ( autoFit . width ? " T " : " F " ) +
' : ' + ( autoFit . height ? " T " : " F " ) ;
return s ;
}
2006-12-26 12:26:49 +00:00
bool DocumentViewport : : isValid ( ) const
{
2007-05-02 18:21:15 +00:00
return pageNumber > = 0 ;
2006-12-26 12:26:49 +00:00
}
2005-01-09 23:37:07 +00:00
bool DocumentViewport : : operator = = ( const DocumentViewport & vp ) const
{
bool equal = ( pageNumber = = vp . pageNumber ) & &
2005-06-13 11:53:47 +00:00
( rePos . enabled = = vp . rePos . enabled ) & &
2005-01-09 23:37:07 +00:00
( autoFit . enabled = = vp . autoFit . enabled ) ;
if ( ! equal )
return false ;
2005-06-13 11:53:47 +00:00
if ( rePos . enabled & &
( ( rePos . normalizedX ! = vp . rePos . normalizedX ) | |
( rePos . normalizedY ! = vp . rePos . normalizedY ) | | rePos . pos ! = vp . rePos . pos ) )
2005-01-09 23:37:07 +00:00
return false ;
if ( autoFit . enabled & &
( ( autoFit . width ! = vp . autoFit . width ) | |
( autoFit . height ! = vp . autoFit . height ) ) )
return false ;
return true ;
}
2012-06-04 14:10:33 +00:00
bool DocumentViewport : : operator < ( const DocumentViewport & vp ) const
{
// TODO: Check autoFit and Position
if ( pageNumber ! = vp . pageNumber )
return pageNumber < vp . pageNumber ;
if ( ! rePos . enabled & & vp . rePos . enabled )
return true ;
if ( ! vp . rePos . enabled )
return false ;
if ( rePos . normalizedY ! = vp . rePos . normalizedY )
return rePos . normalizedY < vp . rePos . normalizedY ;
return rePos . normalizedX < vp . rePos . normalizedX ;
}
2005-01-09 23:37:07 +00:00
2005-01-02 22:37:52 +00:00
/** DocumentInfo **/
DocumentInfo : : DocumentInfo ( )
: QDomDocument ( " DocumentInformation " )
{
QDomElement docElement = createElement ( " DocumentInfo " ) ;
appendChild ( docElement ) ;
}
void DocumentInfo : : set ( const QString & key , const QString & value ,
const QString & title )
{
QDomElement docElement = documentElement ( ) ;
QDomElement element ;
// check whether key already exists
QDomNodeList list = docElement . elementsByTagName ( key ) ;
if ( list . count ( ) > 0 )
element = list . item ( 0 ) . toElement ( ) ;
else
element = createElement ( key ) ;
element . setAttribute ( " value " , value ) ;
element . setAttribute ( " title " , title ) ;
if ( list . count ( ) = = 0 )
docElement . appendChild ( element ) ;
}
2009-11-16 00:46:33 +00:00
void DocumentInfo : : set ( Key key , const QString & value )
{
const QString keyString = getKeyString ( key ) ;
if ( ! keyString . isEmpty ( ) )
set ( keyString , value , getKeyTitle ( key ) ) ;
else
kWarning ( OkularDebug ) < < " Invalid key passed " ;
}
QString DocumentInfo : : get ( const QString & key ) const
{
const QDomElement docElement = documentElement ( ) ;
// check whether key already exists
const QDomNodeList list = docElement . elementsByTagName ( key ) ;
if ( list . count ( ) > 0 )
return list . item ( 0 ) . toElement ( ) . attribute ( " value " ) ;
else
return QString ( ) ;
}
QString DocumentInfo : : getKeyString ( Key key ) //const
2007-05-13 12:54:46 +00:00
{
switch ( key ) {
case Title :
2009-11-16 00:46:33 +00:00
return " title " ;
2007-05-13 12:54:46 +00:00
break ;
case Subject :
2009-11-16 00:46:33 +00:00
return " subject " ;
2007-05-13 12:54:46 +00:00
break ;
case Description :
2009-11-16 00:46:33 +00:00
return " description " ;
2007-05-13 12:54:46 +00:00
break ;
case Author :
2009-11-16 00:46:33 +00:00
return " author " ;
2007-05-13 12:54:46 +00:00
break ;
case Creator :
2009-11-16 00:46:33 +00:00
return " creator " ;
2007-05-13 12:54:46 +00:00
break ;
case Producer :
2009-11-16 00:46:33 +00:00
return " producer " ;
2007-05-13 12:54:46 +00:00
break ;
case Copyright :
2009-11-16 00:46:33 +00:00
return " copyright " ;
2007-05-13 12:54:46 +00:00
break ;
case Pages :
2009-11-16 00:46:33 +00:00
return " pages " ;
2007-05-13 12:54:46 +00:00
break ;
case CreationDate :
2009-11-16 00:46:33 +00:00
return " creationDate " ;
2007-05-13 12:54:46 +00:00
break ;
case ModificationDate :
2009-11-16 00:46:33 +00:00
return " modificationDate " ;
2007-05-13 12:54:46 +00:00
break ;
case MimeType :
2009-11-16 00:46:33 +00:00
return " mimeType " ;
2007-05-13 12:54:46 +00:00
break ;
case Category :
2009-11-16 00:46:33 +00:00
return " category " ;
2007-05-13 12:54:46 +00:00
break ;
case Keywords :
2009-11-16 00:46:33 +00:00
return " keywords " ;
break ;
case FilePath :
return " filePath " ;
break ;
case DocumentSize :
return " documentSize " ;
break ;
case PagesSize :
return " pageSize " ;
2007-05-13 12:54:46 +00:00
break ;
default :
2009-11-16 00:46:33 +00:00
return QString ( ) ;
2007-05-13 12:54:46 +00:00
break ;
}
}
2009-11-16 00:46:33 +00:00
QString DocumentInfo : : getKeyTitle ( Key key ) //const
2005-01-02 22:37:52 +00:00
{
2009-11-16 00:46:33 +00:00
switch ( key ) {
case Title :
return i18n ( " Title " ) ;
break ;
case Subject :
return i18n ( " Subject " ) ;
break ;
case Description :
return i18n ( " Description " ) ;
break ;
case Author :
return i18n ( " Author " ) ;
break ;
case Creator :
return i18n ( " Creator " ) ;
break ;
case Producer :
return i18n ( " Producer " ) ;
break ;
case Copyright :
return i18n ( " Copyright " ) ;
break ;
case Pages :
return i18n ( " Pages " ) ;
break ;
case CreationDate :
return i18n ( " Created " ) ;
break ;
case ModificationDate :
return i18n ( " Modified " ) ;
break ;
case MimeType :
return i18n ( " Mime Type " ) ;
break ;
case Category :
return i18n ( " Category " ) ;
break ;
case Keywords :
return i18n ( " Keywords " ) ;
break ;
case FilePath :
return i18n ( " File Path " ) ;
break ;
case DocumentSize :
return i18n ( " File Size " ) ;
break ;
case PagesSize :
return i18n ( " Page Size " ) ;
break ;
default :
return QString ( ) ;
break ;
}
2005-01-02 22:37:52 +00:00
}
2005-01-09 23:37:07 +00:00
2005-01-03 15:51:05 +00:00
/** DocumentSynopsis **/
DocumentSynopsis : : DocumentSynopsis ( )
: QDomDocument ( " DocumentSynopsis " )
{
// void implementation, only subclassed for naming
}
2006-09-20 11:44:58 +00:00
DocumentSynopsis : : DocumentSynopsis ( const QDomDocument & document )
: QDomDocument ( document )
{
}
2005-06-13 15:46:23 +00:00
2006-05-28 16:54:54 +00:00
/** EmbeddedFile **/
EmbeddedFile : : EmbeddedFile ( )
{
}
EmbeddedFile : : ~ EmbeddedFile ( )
{
}
2007-01-02 19:05:49 +00:00
VisiblePageRect : : VisiblePageRect ( int page , const NormalizedRect & rectangle )
: pageNumber ( page ) , rect ( rectangle )
{
}
2009-01-10 11:32:54 +00:00
# undef foreachObserver
# undef foreachObserverD
2014-08-08 22:00:07 +00:00
# include "moc_document.cpp"
2008-05-04 15:10:32 +00:00
/* kate: replace-tabs on; indent-width 4; */