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"
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>
# include <QtGui/QApplication>
2007-08-13 22:25:27 +00:00
# include <QtGui/QLabel>
2007-10-15 23:01:27 +00:00
# include <QtGui/QPrinter>
2007-11-26 21:43:54 +00:00
# include <QtGui/QPrintDialog>
2006-09-21 08:45:36 +00:00
2007-03-11 22:35:14 +00:00
# include <kaboutdata.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"
2007-01-02 17:45:32 +00:00
# include "settings.h"
# 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"
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"
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
int id ;
int page ;
2007-07-15 16:10:48 +00:00
qulonglong memory ;
2004-12-21 12:38:52 +00:00
// public constructor: initialize data
2007-07-15 16:10:48 +00:00
AllocatedPixmap ( int i , int p , qulonglong m ) : id ( i ) , 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 ;
QString metadataFileName ;
} ;
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 ;
bool cachedNoDialogs : 1 ;
2009-08-10 22:28:54 +00:00
bool isCurrentlySearching : 1 ;
2005-02-02 18:18:26 +00:00
QColor cachedColor ;
2005-02-01 18:26:56 +00:00
} ;
2004-09-08 12:41:14 +00:00
# define foreachObserver( cmd ) {\
2008-04-27 21:01:05 +00:00
QMap < int , 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 ) {\
2008-04-27 21:01:05 +00:00
QMap < int , 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
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
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
{
2007-01-02 19:05:49 +00:00
return i18n ( " %1 x %2 in " , 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
{
2007-01-02 19:05:49 +00:00
return i18n ( " %1 x %2 mm " , inchesWidth * 25.4 , inchesHeight * 25.4 ) ;
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
2007-01-02 19:05:49 +00:00
switch ( Settings : : memoryLevel ( ) )
2007-01-02 16:40:22 +00:00
{
2007-01-02 19:05:49 +00:00
case Settings : : EnumMemoryLevel : : Low :
memoryToFree = m_allocatedPixmapsTotalMemory ;
break ;
case Settings : : EnumMemoryLevel : : Normal :
2008-04-27 18:08:14 +00:00
{
qulonglong thirdTotalMemory = getTotalMemory ( ) / 3 ;
2012-06-24 21:53:01 +00:00
qulonglong freeMemory = getFreeMemory ( ) ;
2008-04-27 18:08:14 +00:00
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
case Settings : : EnumMemoryLevel : : Aggressive :
2008-04-27 18:08:14 +00:00
{
2012-06-24 21:53:01 +00:00
qulonglong freeMemory = getFreeMemory ( ) ;
2008-04-27 18:08:14 +00:00
if ( m_allocatedPixmapsTotalMemory > freeMemory ) clipValue = ( m_allocatedPixmapsTotalMemory - freeMemory ) / 2 ;
}
break ;
2012-03-08 23:12:20 +00:00
case Settings : : EnumMemoryLevel : : Greedy :
{
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 )
{
2007-01-02 19:05:49 +00:00
if ( memoryToFree > 0 )
2007-01-02 16:40:22 +00:00
{
2007-01-02 19:05:49 +00:00
// [MEM] free memory starting from older pixmaps
int pagesFreed = 0 ;
2012-07-01 23:05:02 +00:00
while ( memoryToFree > 0 )
2007-01-02 19:05:49 +00:00
{
2012-07-01 23:05:02 +00:00
AllocatedPixmap * p = searchLowestPriorityUnloadablePixmap ( true ) ;
if ( ! p ) // No pixmap to remove
break ;
kDebug ( ) . nospace ( ) < < " Evicting cache pixmap id= " < < p - > id < < " 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 - > id ) ;
// delete allocation descriptor
delete p ;
}
//p--rintf("freeMemory A:[%d -%d = %d] \n", m_allocatedPixmaps.count() + pagesFreed, pagesFreed, m_allocatedPixmaps.count() );
}
}
/* Returns the next pixmap to evict from cache, or NULL if no suitable pixmap
* is found . If thenRemoveIt is set , the pixmap is removed from
* m_allocatedPixmaps before returning it */
AllocatedPixmap * DocumentPrivate : : searchLowestPriorityUnloadablePixmap ( bool thenRemoveIt )
{
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 ;
const int distance = qAbs ( p - > page - currentViewportPage ) ;
if ( maxDistance < distance & & m_observers . value ( p - > id ) - > canUnloadPixmap ( p - > page ) )
{
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 ;
2008-11-15 00:34:03 +00:00
loadDocumentInfo ( m_xmlFileName ) ;
}
void DocumentPrivate : : loadDocumentInfo ( const QString & fileName )
{
QFile infoFile ( fileName ) ;
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 ;
}
2008-11-09 14:21:20 +00:00
bool DocumentPrivate : : openDocumentInternal ( const KService : : Ptr & offer , bool isstdin , const QString & docFile , const QByteArray & filedata )
{
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 )
return false ;
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 ) ;
bool openOk = false ;
if ( ! isstdin )
{
openOk = m_generator - > loadDocument ( docFile , m_pagesVector ) ;
}
else if ( ! filedata . isEmpty ( ) )
{
if ( m_generator - > hasFeature ( Generator : : ReadRawData ) )
{
openOk = m_generator - > loadDocumentFromData ( filedata , m_pagesVector ) ;
}
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 ( ) ;
openOk = m_generator - > loadDocument ( tmpFileName , m_pagesVector ) ;
}
}
}
QApplication : : restoreOverrideCursor ( ) ;
if ( ! openOk | | m_pagesVector . size ( ) < = 0 )
{
if ( ! catalogName . isEmpty ( ) )
KGlobal : : locale ( ) - > removeCatalog ( catalogName ) ;
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
openOk = false ;
2008-11-09 14:21:20 +00:00
}
return openOk ;
}
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)
2012-05-30 16:38:51 +00:00
KMessageBox : : information ( m_parent - > 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
KMessageBox : : information ( m_parent - > 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
}
}
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)
if ( Settings : : memoryLevel ( ) ! = Settings : : EnumMemoryLevel : : Low & &
m_allocatedPixmapsTotalMemory > 1024 * 1024 )
cleanupPixmapMemory ( ) ;
2005-06-13 17:39:58 +00:00
}
2007-04-14 19:44:07 +00:00
void DocumentPrivate : : sendGeneratorRequest ( )
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 )
{
AllocatedPixmap * pixmapToReplace = searchLowestPriorityUnloadablePixmap ( ) ;
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 )
m_pixmapRequestsStack . pop_back ( ) ;
2005-06-24 16:45:25 +00:00
2007-01-02 19:05:49 +00:00
// request only if page isn't already present or request has invalid id
2008-03-07 15:50:48 +00:00
else if ( ( ! r - > d - > mForce & & r - > page ( ) - > hasPixmap ( r - > id ( ) , r - > width ( ) , r - > height ( ) ) ) | | r - > id ( ) < = 0 | | r - > id ( ) > = MAX_OBSERVER_ID )
2007-01-02 19:05:49 +00:00
{
m_pixmapRequestsStack . pop_back ( ) ;
delete r ;
}
else if ( ( long ) r - > width ( ) * ( long ) r - > height ( ) > 20000000L )
{
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 ;
}
2012-07-02 06:22:51 +00:00
else if ( ! r - > d - > mForce & & r - > d - > isPreload ( ) & & qAbs ( r - > pageNumber ( ) - currentViewportPage ) > = maxDistance )
{
m_pixmapRequestsStack . pop_back ( ) ;
//kDebug() << "Ignoring request that doesn't fit in cache";
delete r ;
}
2007-01-02 19:05:49 +00:00
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
2007-07-15 16:10:48 +00:00
qulonglong 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
{
2007-07-31 10:19:48 +00:00
kDebug ( OkularDebug ) . nospace ( ) < < " sending request id= " < < request - > id ( ) < < " " < < request - > width ( ) < < " x " < < request - > height ( ) < < " @ " < < request - > pageNumber ( ) < < " async == " < < request - > asynchronous ( ) ;
2007-01-02 19:05:49 +00:00
m_pixmapRequestsStack . removeAll ( request ) ;
2006-10-25 15:35:53 +00:00
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
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
QTimer : : singleShot ( 30 , m_parent , SLOT ( sendGeneratorRequest ( ) ) ) ;
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 ;
2008-11-11 18:48:40 +00:00
QMap < int , DocumentObserver * > : : const_iterator it = m_observers . constBegin ( ) , end = m_observers . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; it ! = end ; + + it ) {
( * it ) - > notifyPageChanged ( page , DocumentObserver : : Pixmap | DocumentObserver : : Annotations ) ;
2006-10-25 15:35:53 +00:00
}
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
if ( Settings : : memoryLevel ( ) = = Settings : : 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 ;
2008-11-11 18:48:40 +00:00
QMap < int , 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 ( ) ;
if ( ( * it ) . m_rotation % 2 )
size . transpose ( ) ;
PixmapRequest * p = new PixmapRequest ( it . key ( ) , pageNumber , size . width ( ) , size . height ( ) , 1 , true ) ;
p - > d - > mForce = true ;
requestedPixmaps . push_back ( p ) ;
}
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 ;
}
// 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 ( ) ;
if ( searchStruct - > pagesDone < pageCount )
2007-08-13 22:25:27 +00:00
{
bool 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
{
2012-09-24 22:14:10 +00:00
const QString question = searchStruct - > forward ? i18n ( " End of document reached. \n Continue from the beginning? " ) : i18n ( " Beginning of document reached. \n Continue from the bottom? " ) ;
if ( searchStruct - > noDialogs | | KMessageBox : : questionYesNo ( m_parent - > widget ( ) , question , QString ( ) , KStandardGuiItem : : cont ( ) , KStandardGuiItem : : cancel ( ) ) = = KMessageBox : : Yes )
searchStruct - > currentPage = searchStruct - > forward ? 0 : pageCount - 1 ;
2007-08-13 22:25:27 +00:00
else
doContinue = false ;
}
if ( doContinue )
{
// get page
2012-09-24 22:14:10 +00:00
Page * page = m_pagesVector [ searchStruct - > currentPage ] ;
2007-08-13 22:25:27 +00:00
// request search page if needed
if ( ! page - > hasTextPage ( ) )
m_parent - > requestTextPage ( page - > number ( ) ) ;
// if found a match on the current page, end the loop
2012-09-24 22:14:10 +00:00
searchStruct - > match = page - > findText ( searchStruct - > searchID , searchStruct - > text , searchStruct - > forward ? FromTop : FromBottom , searchStruct - > caseSensitivity ) ;
2007-08-13 22:25:27 +00:00
2012-09-24 22:14:10 +00:00
if ( ! searchStruct - > match )
2008-03-14 13:47:18 +00:00
{
2012-09-24 22:14:10 +00:00
if ( searchStruct - > forward ) searchStruct - > currentPage + + ;
else searchStruct - > currentPage - - ;
searchStruct - > pagesDone + + ;
2008-03-14 13:47:18 +00:00
}
else
{
2012-09-24 22:14:10 +00:00
searchStruct - > pagesDone = 1 ;
2008-03-14 13:47:18 +00:00
}
2007-08-13 22:25:27 +00:00
2012-09-24 22:14:10 +00:00
QMetaObject : : invokeMethod ( m_parent , " doContinueDirectionMatchSearch " , Qt : : QueuedConnection , Q_ARG ( void * , searchStruct ) ) ;
2007-08-13 22:25:27 +00:00
return ;
}
}
}
2012-09-24 22:14:10 +00:00
doProcessSearchMatch ( searchStruct - > match , search , searchStruct - > pagesToNotify , searchStruct - > currentPage , searchStruct - > searchID , searchStruct - > moveViewport , searchStruct - > color ) ;
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 ) ;
// ..move the viewport to show the first of the searched word sequence centered
if ( moveViewport )
{
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 ;
m_parent - > setViewport ( searchViewport , - 1 , true ) ;
}
delete match ;
}
2008-10-11 15:03:46 +00:00
#if 0
2007-08-13 22:25:27 +00:00
else if ( ! noDialogs )
KMessageBox : : information ( m_parent - > widget ( ) , i18n ( " No matches found for '%1'. " , text ) ) ;
2008-10-11 15:03:46 +00:00
# endif
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 pagesToNotify ;
}
void DocumentPrivate : : doContinueAllDocumentSearch ( void * pagesToNotifySet , void * pageMatchesMap , int currentPage , int searchID , const QString & text , int theCaseSensitivity , const QColor & color )
{
QMap < Page * , QVector < RegularAreaRect * > > * pageMatches = static_cast < QMap < Page * , QVector < RegularAreaRect * > > * > ( pageMatchesMap ) ;
Qt : : CaseSensitivity caseSensitivity = static_cast < Qt : : CaseSensitivity > ( theCaseSensitivity ) ;
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 )
lastMatch = page - > findText ( searchID , text , NextResult , caseSensitivity , lastMatch ) ;
else
lastMatch = page - > findText ( searchID , text , FromTop , caseSensitivity ) ;
if ( ! lastMatch )
break ;
// add highligh rect to the matches map
( * pageMatches ) [ page ] . append ( lastMatch ) ;
}
delete lastMatch ;
QMetaObject : : invokeMethod ( m_parent , " doContinueAllDocumentSearch " , Qt : : QueuedConnection , Q_ARG ( void * , pagesToNotifySet ) , Q_ARG ( void * , pageMatches ) , Q_ARG ( int , currentPage + 1 ) , Q_ARG ( int , searchID ) , Q_ARG ( QString , text ) , Q_ARG ( int , caseSensitivity ) , Q_ARG ( QColor , color ) ) ;
}
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 ( ) )
{
it . key ( ) - > d - > setHighlight ( searchID , match , color ) ;
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 ;
}
}
2008-10-19 10:07:48 +00:00
void DocumentPrivate : : doContinueGooglesDocumentSearch ( void * pagesToNotifySet , void * pageMatchesMap , int currentPage , int searchID , const QStringList & words , int theCaseSensitivity , const QColor & color , bool matchAll )
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 ) ;
Qt : : CaseSensitivity caseSensitivity = static_cast < Qt : : CaseSensitivity > ( theCaseSensitivity ) ;
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 ;
color . getHsv ( & baseHue , & baseSat , & baseVal ) ;
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 )
lastMatch = page - > findText ( searchID , word , NextResult , caseSensitivity , lastMatch ) ;
else
lastMatch = page - > findText ( searchID , word , FromTop , caseSensitivity ) ;
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
if ( ! allMatched & & matchAll )
{
QVector < MatchColor > & matches = ( * pageMatches ) [ page ] ;
foreach ( const MatchColor & mc , matches ) delete mc . first ;
pageMatches - > remove ( page ) ;
}
2008-10-19 10:07:48 +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 ) , Q_ARG ( int , caseSensitivity ) , Q_ARG ( QColor , color ) , Q_ARG ( bool , matchAll ) ) ;
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 ;
if ( ( Settings : : renderMode ( ) = = Settings : : EnumRenderMode : : Paper )
& & Settings : : changeColors ( ) )
{
color = Settings : : paperColor ( ) ;
}
else if ( giveDefault )
{
color = Qt : : white ;
}
return color ;
}
else if ( key = = QLatin1String ( " ZoomFactor " ) )
{
return Settings : : zoomFactor ( ) ;
}
2007-12-16 23:36:12 +00:00
else if ( key = = QLatin1String ( " TextAntialias " ) )
{
2008-01-05 15:50:40 +00:00
switch ( Settings : : textAntialias ( ) )
{
case Settings : : EnumTextAntialias : : Enabled :
return true ;
break ;
#if 0
case Settings : : EnumTextAntialias : : UseKDESettings :
// TODO: read the KDE configuration
return true ;
break ;
# endif
case Settings : : EnumTextAntialias : : Disabled :
return false ;
break ;
}
2007-12-16 23:36:12 +00:00
}
else if ( key = = QLatin1String ( " GraphicsAntialias " ) )
{
2008-01-05 15:50:40 +00:00
switch ( Settings : : graphicsAntialias ( ) )
{
case Settings : : EnumGraphicsAntialias : : Enabled :
return true ;
break ;
case Settings : : EnumGraphicsAntialias : : Disabled :
return false ;
break ;
}
2007-12-16 23:36:12 +00:00
}
2009-10-08 21:55:51 +00:00
else if ( key = = QLatin1String ( " TextHinting " ) )
{
switch ( Settings : : textHinting ( ) )
{
case Settings : : EnumTextHinting : : Enabled :
return true ;
break ;
case Settings : : EnumTextHinting : : Disabled :
return false ;
break ;
}
}
2007-09-14 22:16:00 +00:00
return QVariant ( ) ;
}
2006-07-01 22:17:53 +00:00
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 ( ) ) ;
2007-03-24 10:47:22 +00:00
2011-07-31 19:22:04 +00:00
connect ( PageController : : self ( ) , SIGNAL ( rotationFinished ( int , Okular : : Page * ) ) ,
this , SLOT ( rotationFinished ( int , Okular : : Page * ) ) ) ;
connect ( Settings : : self ( ) , SIGNAL ( configChanged ( ) ) , this , SLOT ( _o_configChanged ( ) ) ) ;
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
}
2007-01-02 19:05:49 +00:00
static bool kserviceMoreThan ( const KService : : Ptr & s1 , const KService : : Ptr & s2 )
2005-01-01 15:44:44 +00:00
{
2007-01-02 19:05:49 +00:00
return s1 - > property ( " X-KDE-Priority " ) . toInt ( ) > s2 - > property ( " X-KDE-Priority " ) . toInt ( ) ;
2005-01-01 15:44:44 +00:00
}
2004-11-09 17:20:19 +00:00
2007-01-12 22:49:14 +00:00
bool Document : : openDocument ( const QString & docFile , const KUrl & url , const KMimeType : : Ptr & _mime )
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 ( " - " ) ;
2008-11-09 14:21:20 +00:00
bool loadingMimeByContent = false ;
2007-01-12 22:49:14 +00:00
if ( ! isstdin )
2007-01-02 19:05:49 +00:00
{
2007-01-12 22:49:14 +00:00
if ( mime . count ( ) < = 0 )
return false ;
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 ( ) ;
return false ;
}
// 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
{
2008-08-05 09:15:24 +00:00
QString fn = url . fileName ( ) ;
2007-07-10 23:49:37 +00:00
document_size = fileReadTest . size ( ) ;
fn = QString : : number ( document_size ) + ' . ' + fn + " .xml " ;
2007-04-21 23:07:44 +00:00
QString newokular = " okular/docdata/ " + fn ;
QString newokularfile = KStandardDirs : : locateLocal ( " data " , newokular ) ;
2007-09-10 17:20:58 +00:00
if ( ! QFile : : exists ( newokularfile ) )
2007-04-21 23:07:44 +00:00
{
2007-09-10 17:20:58 +00:00
QString oldkpdf = " kpdf/ " + fn ;
QString oldkpdffile = KStandardDirs : : locateLocal ( " data " , oldkpdf ) ;
if ( QFile : : exists ( oldkpdffile ) )
{
// ### copy or move?
if ( ! QFile : : copy ( oldkpdffile , newokularfile ) )
return false ;
}
2007-04-21 23:07:44 +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 " ) )
return false ;
2007-07-10 23:49:37 +00:00
document_size = filedata . size ( ) ;
2008-11-09 14:21:20 +00:00
loadingMimeByContent = 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 ) ;
2008-11-09 14:21:20 +00:00
if ( offers . isEmpty ( ) & & ! isstdin )
{
KMimeType : : Ptr newmime = KMimeType : : findByFileContent ( docFile ) ;
loadingMimeByContent = 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 ) ;
}
}
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 ( ) < < " '. " ;
2007-01-02 22:37:55 +00:00
return false ;
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
qStableSort ( offers . begin ( ) , offers . end ( ) , kserviceMoreThan ) ;
2006-10-15 19:37:14 +00:00
2007-01-28 15:46:10 +00:00
if ( Settings : : 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 ( ) ;
}
2007-05-24 22:52:29 +00:00
ChooseEngineDialog choose ( list , mime , widget ( ) ) ;
2007-01-28 15:46:10 +00:00
if ( choose . exec ( ) = = QDialog : : Rejected )
2007-01-02 19:05:49 +00:00
return false ;
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
bool openOk = d - > openDocumentInternal ( offer , isstdin , docFile , filedata ) ;
if ( ! openOk & & ! loadingMimeByContent )
2007-01-12 22:49:14 +00:00
{
2008-11-09 14:21:20 +00:00
KMimeType : : Ptr newmime = KMimeType : : findByFileContent ( docFile ) ;
loadingMimeByContent = 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 ( ) ;
openOk = d - > openDocumentInternal ( offer , isstdin , docFile , filedata ) ;
2007-01-12 22:49:14 +00:00
}
}
}
2008-11-09 14:21:20 +00:00
if ( ! openOk )
2007-01-02 19:05:49 +00:00
{
2008-11-09 14:21:20 +00:00
return false ;
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 ( ) ;
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 )
{
d - > loadDocumentInfo ( d - > m_archiveData - > metadataFileName ) ;
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 ) ;
}
}
2007-01-02 19:05:49 +00:00
return true ;
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 ;
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 ( ) ) ;
2007-11-25 12:49:30 +00:00
if ( ! genIt . value ( ) . catalogName . isEmpty ( ) & & ! genIt . value ( ) . config )
2007-07-14 13:47:11 +00:00
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 ( ) ;
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 ( ) ;
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
{
2007-01-02 19:05:49 +00:00
// keep the pointer to the observer in a map
2007-02-12 14:15:51 +00:00
d - > m_observers . insert ( pObserver - > observerId ( ) , 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
if ( d - > m_observers . contains ( pObserver - > observerId ( ) ) )
2005-01-20 17:33:05 +00:00
{
2007-01-02 19:05:49 +00:00
// free observer's pixmap data
int observerId = pObserver - > observerId ( ) ;
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 ) - > deletePixmap ( observerId ) ;
// [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 ;
if ( p - > id = = observerId )
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
d - > m_observers . remove ( observerId ) ;
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
if ( Settings : : memoryLevel ( ) = = Settings : : 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
2007-03-30 17:46:50 +00:00
QWidget * Document : : widget ( ) const
{
2008-09-21 22:44:42 +00:00
return d - > m_widget ;
2007-03-30 17:46:50 +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 ) ;
if ( info - > get ( keyString ) . isEmpty ( ) ) {
info - > set ( keyString , QString : : number ( this - > pages ( ) ) ,
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
2007-01-02 19:05:49 +00:00
void Document : : setVisiblePageRects ( const QVector < VisiblePageRect * > & visiblePageRects , int excludeId )
{
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
2008-11-11 18:48:40 +00:00
QMap < int , DocumentObserver * > : : const_iterator it = d - > m_observers . constBegin ( ) , end = d - > m_observers . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; it ! = end ; + + it )
if ( it . key ( ) ! = excludeId )
( * it ) - > notifyVisibleRectsChanged ( ) ;
}
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
if ( KAuthorized : : authorize ( " skip_drm " ) & & ! Okular : : Settings : : obeyDRM ( ) )
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
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 ;
2009-10-27 23:38:13 +00:00
if ( ! d - > m_generator | | d - > m_closingLoop )
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
int requesterID = requests . first ( ) - > id ( ) ;
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
{
2008-03-07 15:50:48 +00:00
if ( ( * sIt ) - > id ( ) = = requesterID
& & ( 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
bool threadingDisabled = ! Settings : : enableThreading ( ) ;
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 ;
2007-07-31 10:19:48 +00:00
kDebug ( OkularDebug ) . nospace ( ) < < " request id= " < < request - > id ( ) < < " " < < 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
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
if ( request - > asynchronous ( ) & & threadingDisabled )
2007-09-30 21:44:31 +00:00
request - > d - > mAsynchronous = false ;
2004-12-10 16:04:45 +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>
// all handling of requests put into sendGeneratorRequest
2007-01-24 15:06:45 +00:00
// if ( generator->canRequestPixmap() )
2007-01-02 19:05:49 +00:00
d - > sendGeneratorRequest ( ) ;
}
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 )
{
2012-05-13 22:50:41 +00:00
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( d - > m_generator ) ;
AnnotationProxy * proxy = iface ? iface - > annotationProxy ( ) : 0 ;
2007-01-02 19:05:49 +00:00
// find out the page to attach annotation
Page * kp = d - > m_pagesVector [ page ] ;
if ( ! d - > m_generator | | ! kp )
return ;
2006-07-09 14:38:35 +00:00
2007-07-17 18:10:25 +00:00
// the annotation belongs already to a page
if ( annotation - > d_ptr - > m_page )
return ;
2007-01-02 19:05:49 +00:00
// add annotation to the page
kp - > addAnnotation ( annotation ) ;
2004-12-10 16:04:45 +00:00
2012-05-13 22:50:41 +00:00
// tell the annotation proxy
if ( proxy & & proxy - > supports ( AnnotationProxy : : Addition ) )
proxy - > notifyAddition ( annotation , page ) ;
2007-01-02 19:05:49 +00:00
// notify observers about the change
2012-05-23 21:43:44 +00:00
d - > notifyAnnotationChanges ( page ) ;
2012-05-13 22:50:41 +00:00
if ( annotation - > flags ( ) & Annotation : : ExternallyDrawn )
{
// Redraw everything, including ExternallyDrawn annotations
d - > refreshPixmaps ( page ) ;
}
2012-05-14 13:51:58 +00:00
d - > warnLimitedAnnotSupport ( ) ;
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 ;
}
}
2012-05-13 22:50:41 +00:00
void Document : : modifyPageAnnotation ( int page , Annotation * annotation )
2006-11-17 22:15:15 +00:00
{
2012-05-13 22:50:41 +00:00
modifyPageAnnotation ( page , annotation , true ) ;
}
void Document : : modifyPageAnnotation ( int page , Annotation * annotation , bool appearanceChanged )
{
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( d - > m_generator ) ;
AnnotationProxy * proxy = iface ? iface - > annotationProxy ( ) : 0 ;
2007-03-10 05:38:23 +00:00
2007-01-02 19:05:49 +00:00
// find out the page
Page * kp = d - > m_pagesVector [ page ] ;
if ( ! d - > m_generator | | ! kp )
2006-11-17 22:15:15 +00:00
return ;
2007-03-10 05:38:23 +00:00
2012-05-13 22:50:41 +00:00
// tell the annotation proxy
if ( proxy & & proxy - > supports ( AnnotationProxy : : Modification ) )
proxy - > notifyModification ( annotation , page , appearanceChanged ) ;
2007-01-02 19:05:49 +00:00
// notify observers about the change
2012-05-23 21:43:44 +00:00
d - > notifyAnnotationChanges ( page ) ;
2012-05-13 22:50:41 +00:00
if ( appearanceChanged & & ( annotation - > flags ( ) & Annotation : : ExternallyDrawn ) )
{
2012-05-13 18:10:55 +00:00
/* 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 ( d - > m_annotationBeingMoved )
return ;
else // First time: take note
d - > m_annotationBeingMoved = true ;
}
else
{
d - > m_annotationBeingMoved = false ;
}
2012-05-13 22:50:41 +00:00
// Redraw everything, including ExternallyDrawn annotations
d - > refreshPixmaps ( page ) ;
}
2012-05-14 13:51:58 +00:00
// If the user is moving the annotation, don't steal the focus
if ( ( annotation - > flags ( ) & Annotation : : BeingMoved ) = = 0 )
d - > warnLimitedAnnotSupport ( ) ;
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 )
{
2012-05-13 22:50:41 +00:00
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( d - > m_generator ) ;
AnnotationProxy * proxy = iface ? iface - > annotationProxy ( ) : 0 ;
bool isExternallyDrawn ;
2007-01-02 19:05:49 +00:00
// find out the page
Page * kp = d - > m_pagesVector [ page ] ;
if ( ! d - > m_generator | | ! kp )
2006-11-18 15:16:16 +00:00
return ;
2012-05-13 22:50:41 +00:00
if ( annotation - > flags ( ) & Annotation : : ExternallyDrawn )
isExternallyDrawn = true ;
else
isExternallyDrawn = false ;
2007-01-02 19:05:49 +00:00
// try to remove the annotation
2012-05-13 22:50:41 +00:00
if ( canRemovePageAnnotation ( annotation ) )
2006-11-17 22:15:15 +00:00
{
2012-05-13 22:50:41 +00:00
// tell the annotation proxy
if ( proxy & & proxy - > supports ( AnnotationProxy : : Removal ) )
proxy - > notifyRemoval ( annotation , page ) ;
kp - > removeAnnotation ( annotation ) ; // Also destroys the object
2007-01-02 19:05:49 +00:00
// in case of success, notify observers about the change
2012-05-23 21:43:44 +00:00
d - > notifyAnnotationChanges ( page ) ;
2012-05-13 22:50:41 +00:00
if ( isExternallyDrawn )
{
// Redraw everything, including ExternallyDrawn annotations
d - > refreshPixmaps ( page ) ;
}
2006-11-17 22:15:15 +00:00
}
2012-05-14 13:51:58 +00:00
d - > warnLimitedAnnotSupport ( ) ;
2007-01-02 19:05:49 +00:00
}
2006-11-17 22:15:15 +00:00
2007-05-26 19:25:18 +00:00
void Document : : removePageAnnotations ( int page , const QList < Annotation * > & annotations )
2007-01-02 19:05:49 +00:00
{
2012-05-13 22:50:41 +00:00
Okular : : SaveInterface * iface = qobject_cast < Okular : : SaveInterface * > ( d - > m_generator ) ;
AnnotationProxy * proxy = iface ? iface - > annotationProxy ( ) : 0 ;
bool refreshNeeded = false ;
2007-01-02 19:05:49 +00:00
// find out the page
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
bool changed = false ;
foreach ( Annotation * annotation , annotations )
{
2012-05-13 22:50:41 +00:00
bool isExternallyDrawn ;
if ( annotation - > flags ( ) & Annotation : : ExternallyDrawn )
isExternallyDrawn = true ;
else
isExternallyDrawn = false ;
if ( canRemovePageAnnotation ( annotation ) )
2007-01-02 19:05:49 +00:00
{
2012-05-13 22:50:41 +00:00
if ( isExternallyDrawn )
refreshNeeded = true ;
// tell the annotation proxy
if ( proxy & & proxy - > supports ( AnnotationProxy : : Removal ) )
proxy - > notifyRemoval ( annotation , page ) ;
kp - > removeAnnotation ( annotation ) ; // Also destroys the object
2007-01-02 19:05:49 +00:00
changed = true ;
}
}
if ( changed )
{
// in case we removed even only one annotation, notify observers about the change
2012-05-23 21:43:44 +00:00
d - > notifyAnnotationChanges ( page ) ;
2012-05-13 22:50:41 +00:00
if ( refreshNeeded )
{
// Redraw everything, including ExternallyDrawn annotations
d - > refreshPixmaps ( page ) ;
}
2007-01-02 19:05:49 +00:00
}
2012-05-14 13:51:58 +00:00
d - > warnLimitedAnnotSupport ( ) ;
}
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
}
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 ) ) ;
}
*/
void Document : : setViewportPage ( int page , int excludeId , bool smoothMove )
{
// 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
setViewport ( DocumentViewport ( page ) , excludeId , smoothMove ) ;
}
void Document : : setViewport ( const DocumentViewport & viewport , int excludeId , bool smoothMove )
{
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
2008-11-11 18:48:40 +00:00
QMap < int , DocumentObserver * > : : const_iterator it = d - > m_observers . constBegin ( ) , end = d - > m_observers . constEnd ( ) ;
2007-01-02 19:05:49 +00:00
for ( ; it ! = end ; + + it )
2012-08-16 15:37:39 +00:00
{
2007-01-02 19:05:49 +00:00
if ( it . key ( ) ! = excludeId )
( * it ) - > notifyViewportChanged ( smoothMove ) ;
2012-08-16 15:37:39 +00:00
if ( currentPageChanged )
( * it ) - > notifyCurrentPageChanged ( oldPageNumber , currentViewportPage ) ;
}
2007-01-02 16:11:40 +00:00
}
2007-07-08 14:25:08 +00:00
void Document : : setZoom ( int factor , int excludeId )
{
// notify change to all other (different from id) observers
2008-11-11 18:48:40 +00:00
QMap < int , DocumentObserver * > : : const_iterator it = d - > m_observers . constBegin ( ) , end = d - > m_observers . constEnd ( ) ;
2007-07-08 14:25:08 +00:00
for ( ; it ! = end ; + + it )
if ( it . key ( ) ! = excludeId )
( * it ) - > notifyZoom ( factor ) ;
}
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 ( ) )
{
// restore previous viewport and notify it to observers
- - d - > m_viewportIterator ;
foreachObserver ( notifyViewportChanged ( true ) ) ;
}
}
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 ( ) )
{
// restore next viewport and notify it to observers
+ + d - > m_viewportIterator ;
foreachObserver ( notifyViewportChanged ( true ) ) ;
}
}
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 ,
2007-01-02 19:05:49 +00:00
SearchType type , bool moveViewport , const QColor & color , bool noDialogs )
{
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 ;
}
if ( ! noDialogs )
{
2009-02-15 00:38:24 +00:00
#if 0
2007-08-13 22:25:27 +00:00
KDialog * searchDialog = new KDialog ( widget ( ) ) ;
searchDialog - > setCaption ( i18n ( " Search in progress... " ) ) ;
searchDialog - > setButtons ( KDialog : : Cancel ) ;
QLabel * searchLabel = new QLabel ( i18n ( " Searching for %1 " , text ) , searchDialog ) ;
searchDialog - > setMainWidget ( searchLabel ) ;
QTimer : : singleShot ( 500 , searchDialog , SLOT ( show ( ) ) ) ;
2011-07-31 19:22:04 +00:00
connect ( this , SIGNAL ( searchFinished ( int , Okular : : Document : : SearchStatus ) ) , searchDialog , SLOT ( deleteLater ( ) ) ) ;
connect ( searchDialog , SIGNAL ( finished ( ) ) , this , SLOT ( cancelSearch ( ) ) ) ;
2009-02-15 00:38:24 +00:00
# endif
2007-08-13 22:25:27 +00:00
}
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
}
if ( d - > m_lastSearchID ! = searchID )
{
resetSearch ( d - > m_lastSearchID ) ;
}
d - > m_lastSearchID = searchID ;
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 - > cachedNoDialogs = noDialogs ;
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
QMetaObject : : invokeMethod ( this , " doContinueAllDocumentSearch " , Qt : : QueuedConnection , Q_ARG ( void * , pagesToNotify ) , Q_ARG ( void * , pageMatches ) , Q_ARG ( int , 0 ) , Q_ARG ( int , searchID ) , Q_ARG ( QString , text ) , Q_ARG ( int , caseSensitivity ) , Q_ARG ( QColor , color ) ) ;
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
}
2012-09-24 22:14:10 +00:00
DoContinueDirectionMatchSearchStruct * searchStruct = new DoContinueDirectionMatchSearchStruct ( ) ;
searchStruct - > forward = forward ;
searchStruct - > pagesToNotify = pagesToNotify ;
searchStruct - > match = match ;
searchStruct - > currentPage = currentPage ;
searchStruct - > searchID = searchID ;
searchStruct - > text = text ;
searchStruct - > caseSensitivity = caseSensitivity ;
searchStruct - > moveViewport = moveViewport ;
searchStruct - > color = color ;
searchStruct - > noDialogs = noDialogs ;
searchStruct - > pagesDone = pagesDone ;
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 )
{
bool matchAll = type = = GoogleAll ;
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
2008-10-19 10:07:48 +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 ) , Q_ARG ( int , caseSensitivity ) , Q_ARG ( QColor , color ) , Q_ARG ( bool , matchAll ) ) ;
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 ,
p - > cachedType , p - > cachedViewportMove , p - > cachedColor ,
p - > cachedNoDialogs ) ;
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 ,
type , p - > cachedViewportMove , p - > cachedColor ,
p - > cachedNoDialogs ) ;
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
{
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
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
2009-05-13 14:24:30 +00:00
setViewport ( nextViewport , - 1 , 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
2008-04-11 21:16:43 +00:00
KMessageBox : : information ( 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
2008-04-11 21:16:43 +00:00
KMessageBox : : information ( 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
2007-03-30 17:46:50 +00:00
KMessageBox : : information ( 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!
2008-06-05 20:22:46 +00:00
new KRun ( realUrl , 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 ;
}
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
2007-02-03 23:09:40 +00:00
QHash < int , QString > : : const_iterator it = editors . constFind ( Settings : : 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
p = Settings : : externalEditorCommand ( ) ;
// 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 " ) ;
2010-04-14 23:07:27 +00:00
case Generator : : NoPrintError :
return QString ( ) ;
case Generator : : UnknownPrintError :
return QString ( ) ;
}
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 ;
if ( d - > m_generator )
{
QMetaObject : : invokeMethod ( d - > m_generator , " requestFontData " , Qt : : DirectConnection , Q_ARG ( Okular : : FontInfo , font ) , Q_ARG ( QByteArray * , & result ) ) ;
}
return result ;
}
2008-11-15 14:15:31 +00:00
bool Document : : openDocumentArchive ( const QString & docFile , const KUrl & url )
{
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 " ) )
2008-11-15 14:15:31 +00:00
return false ;
KZip okularArchive ( docFile ) ;
if ( ! okularArchive . open ( QIODevice : : ReadOnly ) )
return false ;
const KArchiveDirectory * mainDir = okularArchive . directory ( ) ;
const KArchiveEntry * mainEntry = mainDir - > entry ( " content.xml " ) ;
if ( ! mainEntry | | ! mainEntry - > isFile ( ) )
return false ;
std : : auto_ptr < QIODevice > mainEntryDevice ( static_cast < const KZipFileEntry * > ( mainEntry ) - > createDevice ( ) ) ;
QDomDocument doc ;
if ( ! doc . setContent ( mainEntryDevice . get ( ) ) )
return false ;
mainEntryDevice . reset ( ) ;
QDomElement root = doc . documentElement ( ) ;
if ( root . tagName ( ) ! = " OkularArchive " )
return false ;
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 ( ) )
return false ;
const KArchiveEntry * docEntry = mainDir - > entry ( documentFileName ) ;
if ( ! docEntry | | ! docEntry - > isFile ( ) )
return false ;
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 ( ) )
return false ;
QString tempFileName = archiveData - > document . fileName ( ) ;
{
std : : auto_ptr < QIODevice > docEntryDevice ( static_cast < const KZipFileEntry * > ( docEntry ) - > createDevice ( ) ) ;
copyQIODevice ( docEntryDevice . get ( ) , & archiveData - > document ) ;
archiveData - > document . close ( ) ;
}
std : : auto_ptr < KTemporaryFile > tempMetadataFileName ;
const KArchiveEntry * metadataEntry = mainDir - > entry ( metadataFileName ) ;
if ( metadataEntry & & metadataEntry - > isFile ( ) )
{
std : : auto_ptr < QIODevice > metadataEntryDevice ( static_cast < const KZipFileEntry * > ( metadataEntry ) - > createDevice ( ) ) ;
tempMetadataFileName . reset ( new KTemporaryFile ( ) ) ;
tempMetadataFileName - > setSuffix ( " .xml " ) ;
tempMetadataFileName - > setAutoRemove ( false ) ;
if ( tempMetadataFileName - > open ( ) )
{
copyQIODevice ( metadataEntryDevice . get ( ) , tempMetadataFileName . get ( ) ) ;
archiveData - > metadataFileName = tempMetadataFileName - > fileName ( ) ;
tempMetadataFileName - > close ( ) ;
}
}
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 ;
2008-11-15 14:15:31 +00:00
bool ret = openDocument ( tempFileName , url , docMime ) ;
if ( ret )
{
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 ) ) ;
}
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 )
if ( ( * aIt ) - > page = = req - > pageNumber ( ) & & ( * aIt ) - > id = = req - > id ( ) )
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
2007-09-14 15:29:16 +00:00
QMap < int , DocumentObserver * > : : const_iterator itObserver = m_observers . constFind ( req - > id ( ) ) ;
if ( itObserver ! = m_observers . constEnd ( ) )
2007-05-17 16:52:44 +00:00
{
// [MEM] 1.2 append memory allocation descriptor to the FIFO
2007-07-15 16:10:48 +00:00
qulonglong memoryBytes = 4 * req - > width ( ) * req - > height ( ) ;
2007-05-17 16:52:44 +00:00
AllocatedPixmap * memoryPage = new AllocatedPixmap ( req - > id ( ) , 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
2007-02-03 23:09:40 +00:00
itObserver . value ( ) - > notifyPageChanged ( req - > pageNumber ( ) , DocumentObserver : : Pixmap ) ;
2007-05-17 16:52:44 +00:00
}
# ifndef NDEBUG
else
2007-11-25 12:18:10 +00:00
kWarning ( OkularDebug ) < < " Receiving a done request for the defunct observer " < < req - > id ( ) ;
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 )
2007-09-14 15:29:16 +00:00
sendGeneratorRequest ( ) ;
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
switch ( Settings : : memoryLevel ( ) )
{
case Settings : : EnumMemoryLevel : : Low :
m_maxAllocatedTextPages = multipliers * 2 ;
break ;
case Settings : : EnumMemoryLevel : : Normal :
m_maxAllocatedTextPages = multipliers * 50 ;
break ;
case Settings : : EnumMemoryLevel : : Aggressive :
m_maxAllocatedTextPages = multipliers * 250 ;
break ;
2012-03-08 23:12:20 +00:00
case Settings : : EnumMemoryLevel : : Greedy :
m_maxAllocatedTextPages = multipliers * 1250 ;
break ;
2008-05-04 15:10:32 +00:00
}
}
void DocumentPrivate : : textGenerationDone ( Page * page )
{
if ( ! m_generator | | m_closingLoop ) return ;
// 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
2004-12-22 18:21:36 +00:00
# include "document.moc"
2008-05-04 15:10:32 +00:00
/* kate: replace-tabs on; indent-width 4; */