• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdegraphics API Reference
  • KDE Home
  • Contact Us
 

okular

  • sources
  • kde-4.12
  • kdegraphics
  • okular
  • core
document.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2004-2005 by Enrico Ros <eros.kde@email.it> *
3  * Copyright (C) 2004-2008 by Albert Astals Cid <aacid@kde.org> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  ***************************************************************************/
10 
11 #include "document.h"
12 #include "document_p.h"
13 #include "documentcommands_p.h"
14 
15 #include <limits.h>
16 #ifdef Q_OS_WIN
17 #define _WIN32_WINNT 0x0500
18 #include <windows.h>
19 #elif defined(Q_OS_FREEBSD)
20 #include <sys/types.h>
21 #include <sys/sysctl.h>
22 #include <vm/vm_param.h>
23 #endif
24 
25 // qt/kde/system includes
26 #include <QtCore/QtAlgorithms>
27 #include <QtCore/QDir>
28 #include <QtCore/QFile>
29 #include <QtCore/QFileInfo>
30 #include <QtCore/QMap>
31 #include <QtCore/QTextStream>
32 #include <QtCore/QTimer>
33 #include <QtGui/QApplication>
34 #include <QtGui/QLabel>
35 #include <QtGui/QPrinter>
36 #include <QtGui/QPrintDialog>
37 #include <QUndoCommand>
38 
39 #include <kaboutdata.h>
40 #include <kauthorized.h>
41 #include <kcomponentdata.h>
42 #include <kconfigdialog.h>
43 #include <kdebug.h>
44 #include <klibloader.h>
45 #include <klocale.h>
46 #include <kmacroexpander.h>
47 #include <kmessagebox.h>
48 #include <kmimetypetrader.h>
49 #include <kprocess.h>
50 #include <krun.h>
51 #include <kshell.h>
52 #include <kstandarddirs.h>
53 #include <ktemporaryfile.h>
54 #include <ktoolinvocation.h>
55 #include <kzip.h>
56 
57 // local includes
58 #include "action.h"
59 #include "annotations.h"
60 #include "annotations_p.h"
61 #include "audioplayer.h"
62 #include "audioplayer_p.h"
63 #include "bookmarkmanager.h"
64 #include "chooseenginedialog_p.h"
65 #include "debug_p.h"
66 #include "generator_p.h"
67 #include "interfaces/configinterface.h"
68 #include "interfaces/guiinterface.h"
69 #include "interfaces/printinterface.h"
70 #include "interfaces/saveinterface.h"
71 #include "observer.h"
72 #include "misc.h"
73 #include "page.h"
74 #include "page_p.h"
75 #include "pagecontroller_p.h"
76 #include "scripter.h"
77 #include "settings_core.h"
78 #include "sourcereference.h"
79 #include "sourcereference_p.h"
80 #include "texteditors_p.h"
81 #include "tile.h"
82 #include "tilesmanager_p.h"
83 #include "utils_p.h"
84 #include "view.h"
85 #include "view_p.h"
86 #include "form.h"
87 
88 #include <memory>
89 
90 #include <config-okular.h>
91 
92 using namespace Okular;
93 
94 struct AllocatedPixmap
95 {
96  // owner of the page
97  DocumentObserver *observer;
98  int page;
99  qulonglong memory;
100  // public constructor: initialize data
101  AllocatedPixmap( DocumentObserver *o, int p, qulonglong m ) : observer( o ), page( p ), memory( m ) {}
102 };
103 
104 struct ArchiveData
105 {
106  ArchiveData()
107  {
108  }
109 
110  KTemporaryFile document;
111  QString metadataFileName;
112 };
113 
114 struct RunningSearch
115 {
116  // store search properties
117  int continueOnPage;
118  RegularAreaRect continueOnMatch;
119  QSet< int > highlightedPages;
120 
121  // fields related to previous searches (used for 'continueSearch')
122  QString cachedString;
123  Document::SearchType cachedType;
124  Qt::CaseSensitivity cachedCaseSensitivity;
125  bool cachedViewportMove : 1;
126  bool cachedNoDialogs : 1;
127  bool isCurrentlySearching : 1;
128  QColor cachedColor;
129 };
130 
131 #define foreachObserver( cmd ) {\
132  QSet< DocumentObserver * >::const_iterator it=d->m_observers.constBegin(), end=d->m_observers.constEnd();\
133  for ( ; it != end ; ++ it ) { (*it)-> cmd ; } }
134 
135 #define foreachObserverD( cmd ) {\
136  QSet< DocumentObserver * >::const_iterator it = m_observers.constBegin(), end = m_observers.constEnd();\
137  for ( ; it != end ; ++ it ) { (*it)-> cmd ; } }
138 
139 #define OKULAR_HISTORY_MAXSTEPS 100
140 #define OKULAR_HISTORY_SAVEDSTEPS 10
141 
142 /***** Document ******/
143 
144 QString DocumentPrivate::pagesSizeString() const
145 {
146  if (m_generator)
147  {
148  if (m_generator->pagesSizeMetric() != Generator::None)
149  {
150  QSizeF size = m_parent->allPagesSize();
151  if (size.isValid()) return localizedSize(size);
152  else return QString();
153  }
154  else return QString();
155  }
156  else return QString();
157 }
158 
159 QString DocumentPrivate::namePaperSize(double inchesWidth, double inchesHeight) const
160 {
161  // Account for small deviations in paper sizes
162  static const double marginFactor = 0.03;
163  static const double lowerBoundFactor = 1.0 - marginFactor;
164  static const double upperBoundFactor = 1.0 + marginFactor;
165 
166  const QPrinter::Orientation orientation = inchesWidth > inchesHeight ? QPrinter::Landscape : QPrinter::Portrait;
167  // enforce portrait mode for further tests
168  if (inchesWidth > inchesHeight)
169  qSwap(inchesWidth, inchesHeight);
170 
171  // Use QPrinter to find which of the predefined paper sizes
172  // matches best the given paper width and height
173  QPrinter dummyPrinter;
174  QPrinter::PaperSize paperSize = QPrinter::Custom;
175  for (int i = 0; i < (int)QPrinter::NPaperSize; ++i)
176  {
177  const QPrinter::PaperSize ps = (QPrinter::PaperSize)i;
178  dummyPrinter.setPaperSize(ps);
179  const QSizeF definedPaperSize = dummyPrinter.paperSize(QPrinter::Inch);
180 
181  if (inchesWidth > definedPaperSize.width() * lowerBoundFactor && inchesWidth < definedPaperSize.width() * upperBoundFactor
182  && inchesHeight > definedPaperSize.height() * lowerBoundFactor && inchesHeight < definedPaperSize.height() * upperBoundFactor)
183  {
184  paperSize = ps;
185  break;
186  }
187  }
188 
189  // Handle all paper sizes defined in QPrinter,
190  // return string depending if paper's orientation is landscape or portrait
191  switch (paperSize) {
192  case QPrinter::A0:
193  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A0") : i18nc("paper size", "portrait DIN/ISO A0");
194  case QPrinter::A1:
195  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A1") : i18nc("paper size", "portrait DIN/ISO A1");
196  case QPrinter::A2:
197  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A2") : i18nc("paper size", "portrait DIN/ISO A2");
198  case QPrinter::A3:
199  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A3") : i18nc("paper size", "portrait DIN/ISO A3");
200  case QPrinter::A4:
201  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A4") : i18nc("paper size", "portrait DIN/ISO A4");
202  case QPrinter::A5:
203  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A5") : i18nc("paper size", "portrait DIN/ISO A5");
204  case QPrinter::A6:
205  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A6") : i18nc("paper size", "portrait DIN/ISO A6");
206  case QPrinter::A7:
207  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A7") : i18nc("paper size", "portrait DIN/ISO A7");
208  case QPrinter::A8:
209  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A8") : i18nc("paper size", "portrait DIN/ISO A8");
210  case QPrinter::A9:
211  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO A9") : i18nc("paper size", "portrait DIN/ISO A9");
212  case QPrinter::B0:
213  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B0") : i18nc("paper size", "portrait DIN/ISO B0");
214  case QPrinter::B1:
215  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B1") : i18nc("paper size", "portrait DIN/ISO B1");
216  case QPrinter::B2:
217  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B2") : i18nc("paper size", "portrait DIN/ISO B2");
218  case QPrinter::B3:
219  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B3") : i18nc("paper size", "portrait DIN/ISO B3");
220  case QPrinter::B4:
221  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B4") : i18nc("paper size", "portrait DIN/ISO B4");
222  case QPrinter::B5:
223  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B5") : i18nc("paper size", "portrait DIN/ISO B5");
224  case QPrinter::B6:
225  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B6") : i18nc("paper size", "portrait DIN/ISO B6");
226  case QPrinter::B7:
227  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B7") : i18nc("paper size", "portrait DIN/ISO B7");
228  case QPrinter::B8:
229  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B8") : i18nc("paper size", "portrait DIN/ISO B8");
230  case QPrinter::B9:
231  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B9") : i18nc("paper size", "portrait DIN/ISO B9");
232  case QPrinter::B10:
233  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DIN/ISO B10") : i18nc("paper size", "portrait DIN/ISO B10");
234  case QPrinter::Letter:
235  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape letter") : i18nc("paper size", "portrait letter");
236  case QPrinter::Legal:
237  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape legal") : i18nc("paper size", "portrait legal");
238  case QPrinter::Executive:
239  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape executive") : i18nc("paper size", "portrait executive");
240  case QPrinter::C5E:
241  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape C5E") : i18nc("paper size", "portrait C5E");
242  case QPrinter::Comm10E:
243  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape Comm10E") : i18nc("paper size", "portrait Comm10E");
244  case QPrinter::DLE:
245  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape DLE") : i18nc("paper size", "portrait DLE");
246  case QPrinter::Folio:
247  return orientation == QPrinter::Landscape ? i18nc("paper size", "landscape folio") : i18nc("paper size", "portrait folio");
248  case QPrinter::Tabloid:
249  case QPrinter::Ledger:
251  return orientation == QPrinter::Landscape ? i18nc("paper size", "ledger") : i18nc("paper size", "tabloid");
252  case QPrinter::Custom:
253  return orientation == QPrinter::Landscape ? i18nc("paper size", "unknown landscape paper size") : i18nc("paper size", "unknown portrait paper size");
254  }
255 
256  kWarning() << "PaperSize" << paperSize << "has not been covered";
257  return QString();
258 }
259 
260 QString DocumentPrivate::localizedSize(const QSizeF &size) const
261 {
262  double inchesWidth = 0, inchesHeight = 0;
263  switch (m_generator->pagesSizeMetric())
264  {
265  case Generator::Points:
266  inchesWidth = size.width() / 72.0;
267  inchesHeight = size.height() / 72.0;
268  break;
269 
270  case Generator::None:
271  break;
272  }
273  if (KGlobal::locale()->measureSystem() == KLocale::Imperial)
274  {
275  return i18nc("%1 is width, %2 is height, %3 is paper size name", "%1 x %2 in (%3)", inchesWidth, inchesHeight, namePaperSize(inchesWidth, inchesHeight));
276  }
277  else
278  {
279  return i18nc("%1 is width, %2 is height, %3 is paper size name", "%1 x %2 mm (%3)", QString::number(inchesWidth * 25.4, 'd', 0), QString::number(inchesHeight * 25.4, 'd', 0), namePaperSize(inchesWidth, inchesHeight));
280  }
281 }
282 
283 qulonglong DocumentPrivate::calculateMemoryToFree()
284 {
285  // [MEM] choose memory parameters based on configuration profile
286  qulonglong clipValue = 0;
287  qulonglong memoryToFree = 0;
288 
289  switch ( SettingsCore::memoryLevel() )
290  {
291  case SettingsCore::EnumMemoryLevel::Low:
292  memoryToFree = m_allocatedPixmapsTotalMemory;
293  break;
294 
295  case SettingsCore::EnumMemoryLevel::Normal:
296  {
297  qulonglong thirdTotalMemory = getTotalMemory() / 3;
298  qulonglong freeMemory = getFreeMemory();
299  if (m_allocatedPixmapsTotalMemory > thirdTotalMemory) memoryToFree = m_allocatedPixmapsTotalMemory - thirdTotalMemory;
300  if (m_allocatedPixmapsTotalMemory > freeMemory) clipValue = (m_allocatedPixmapsTotalMemory - freeMemory) / 2;
301  }
302  break;
303 
304  case SettingsCore::EnumMemoryLevel::Aggressive:
305  {
306  qulonglong freeMemory = getFreeMemory();
307  if (m_allocatedPixmapsTotalMemory > freeMemory) clipValue = (m_allocatedPixmapsTotalMemory - freeMemory) / 2;
308  }
309  break;
310  case SettingsCore::EnumMemoryLevel::Greedy:
311  {
312  qulonglong freeSwap;
313  qulonglong freeMemory = getFreeMemory( &freeSwap );
314  const qulonglong memoryLimit = qMin( qMax( freeMemory, getTotalMemory()/2 ), freeMemory+freeSwap );
315  if (m_allocatedPixmapsTotalMemory > memoryLimit) clipValue = (m_allocatedPixmapsTotalMemory - memoryLimit) / 2;
316  }
317  break;
318  }
319 
320  if ( clipValue > memoryToFree )
321  memoryToFree = clipValue;
322 
323  return memoryToFree;
324 }
325 
326 void DocumentPrivate::cleanupPixmapMemory()
327 {
328  cleanupPixmapMemory( calculateMemoryToFree() );
329 }
330 
331 void DocumentPrivate::cleanupPixmapMemory( qulonglong memoryToFree )
332 {
333  if ( memoryToFree > 0 )
334  {
335  const int currentViewportPage = (*m_viewportIterator).pageNumber;
336 
337  // Create a QMap of visible rects, indexed by page number
338  QMap< int, VisiblePageRect * > visibleRects;
339  QVector< Okular::VisiblePageRect * >::const_iterator vIt = m_pageRects.constBegin(), vEnd = m_pageRects.constEnd();
340  for ( ; vIt != vEnd; ++vIt )
341  visibleRects.insert( (*vIt)->pageNumber, (*vIt) );
342 
343  // Free memory starting from pages that are farthest from the current one
344  int pagesFreed = 0;
345  while ( memoryToFree > 0 )
346  {
347  AllocatedPixmap * p = searchLowestPriorityPixmap( true, true );
348  if ( !p ) // No pixmap to remove
349  break;
350 
351  kDebug().nospace() << "Evicting cache pixmap observer=" << p->observer << " page=" << p->page;
352 
353  // m_allocatedPixmapsTotalMemory can't underflow because we always add or remove
354  // the memory used by the AllocatedPixmap so at most it can reach zero
355  m_allocatedPixmapsTotalMemory -= p->memory;
356  // Make sure memoryToFree does not underflow
357  if ( p->memory > memoryToFree )
358  memoryToFree = 0;
359  else
360  memoryToFree -= p->memory;
361  pagesFreed++;
362  // delete pixmap
363  m_pagesVector.at( p->page )->deletePixmap( p->observer );
364  // delete allocation descriptor
365  delete p;
366  }
367 
368  // If we're still on low memory, try to free individual tiles
369 
370  // Store pages that weren't completely removed
371  QLinkedList< AllocatedPixmap * > pixmapsToKeep;
372  while ( memoryToFree > 0 )
373  {
374  AllocatedPixmap * p = searchLowestPriorityPixmap( false, true, m_tiledObserver );
375  if ( !p ) // No pixmap to remove
376  break;
377 
378  TilesManager *tilesManager = m_pagesVector.at( p->page )->d->tilesManager();
379  if ( tilesManager && tilesManager->totalMemory() > 0 )
380  {
381  qulonglong memoryDiff = p->memory;
382  NormalizedRect visibleRect;
383  if ( visibleRects.contains( p->page ) )
384  visibleRect = visibleRects[ p->page ]->rect;
385 
386  // Free non visible tiles
387  tilesManager->cleanupPixmapMemory( memoryToFree, visibleRect, currentViewportPage );
388 
389  p->memory = tilesManager->totalMemory();
390  memoryDiff -= p->memory;
391  memoryToFree = (memoryDiff < memoryToFree) ? (memoryToFree - memoryDiff) : 0;
392  m_allocatedPixmapsTotalMemory -= memoryDiff;
393 
394  if ( p->memory > 0 )
395  pixmapsToKeep.append( p );
396  else
397  delete p;
398  }
399  else
400  pixmapsToKeep.append( p );
401  }
402 
403  m_allocatedPixmaps += pixmapsToKeep;
404  //p--rintf("freeMemory A:[%d -%d = %d] \n", m_allocatedPixmaps.count() + pagesFreed, pagesFreed, m_allocatedPixmaps.count() );
405  }
406 }
407 
408 /* Returns the next pixmap to evict from cache, or NULL if no suitable pixmap
409  * if found. If unloadableOnly is set, only unloadable pixmaps are returned. If
410  * thenRemoveIt is set, the pixmap is removed from m_allocatedPixmaps before
411  * returning it
412  */
413 AllocatedPixmap * DocumentPrivate::searchLowestPriorityPixmap( bool unloadableOnly, bool thenRemoveIt, DocumentObserver *observer )
414 {
415  QLinkedList< AllocatedPixmap * >::iterator pIt = m_allocatedPixmaps.begin();
416  QLinkedList< AllocatedPixmap * >::iterator pEnd = m_allocatedPixmaps.end();
417  QLinkedList< AllocatedPixmap * >::iterator farthestPixmap = pEnd;
418  const int currentViewportPage = (*m_viewportIterator).pageNumber;
419 
420  /* Find the pixmap that is farthest from the current viewport */
421  int maxDistance = -1;
422  while ( pIt != pEnd )
423  {
424  const AllocatedPixmap * p = *pIt;
425  // Filter by observer
426  if ( observer == 0 || p->observer == observer )
427  {
428  const int distance = qAbs( p->page - currentViewportPage );
429  if ( maxDistance < distance && ( !unloadableOnly || p->observer->canUnloadPixmap( p->page ) ) )
430  {
431  maxDistance = distance;
432  farthestPixmap = pIt;
433  }
434  }
435  ++pIt;
436  }
437 
438  /* No pixmap to remove */
439  if ( farthestPixmap == pEnd )
440  return 0;
441 
442  AllocatedPixmap * selectedPixmap = *farthestPixmap;
443  if ( thenRemoveIt )
444  m_allocatedPixmaps.erase( farthestPixmap );
445  return selectedPixmap;
446 }
447 
448 qulonglong DocumentPrivate::getTotalMemory()
449 {
450  static qulonglong cachedValue = 0;
451  if ( cachedValue )
452  return cachedValue;
453 
454 #if defined(Q_OS_LINUX)
455  // if /proc/meminfo doesn't exist, return 128MB
456  QFile memFile( "/proc/meminfo" );
457  if ( !memFile.open( QIODevice::ReadOnly ) )
458  return (cachedValue = 134217728);
459 
460  QTextStream readStream( &memFile );
461  while ( true )
462  {
463  QString entry = readStream.readLine();
464  if ( entry.isNull() ) break;
465  if ( entry.startsWith( "MemTotal:" ) )
466  return (cachedValue = (Q_UINT64_C(1024) * entry.section( ' ', -2, -2 ).toULongLong()));
467  }
468 #elif defined(Q_OS_FREEBSD)
469  qulonglong physmem;
470  int mib[] = {CTL_HW, HW_PHYSMEM};
471  size_t len = sizeof( physmem );
472  if ( sysctl( mib, 2, &physmem, &len, NULL, 0 ) == 0 )
473  return (cachedValue = physmem);
474 #elif defined(Q_OS_WIN)
475  MEMORYSTATUSEX stat;
476  stat.dwLength = sizeof(stat);
477  GlobalMemoryStatusEx (&stat);
478 
479  return ( cachedValue = stat.ullTotalPhys );
480 #endif
481  return (cachedValue = 134217728);
482 }
483 
484 qulonglong DocumentPrivate::getFreeMemory( qulonglong *freeSwap )
485 {
486  static QTime lastUpdate = QTime::currentTime().addSecs(-3);
487  static qulonglong cachedValue = 0;
488  static qulonglong cachedFreeSwap = 0;
489 
490  if ( qAbs( lastUpdate.secsTo( QTime::currentTime() ) ) <= 2 )
491  {
492  if (freeSwap)
493  *freeSwap = cachedFreeSwap;
494  return cachedValue;
495  }
496 
497  /* Initialize the returned free swap value to 0. It is overwritten if the
498  * actual value is available */
499  if (freeSwap)
500  *freeSwap = 0;
501 
502 #if defined(Q_OS_LINUX)
503  // if /proc/meminfo doesn't exist, return MEMORY FULL
504  QFile memFile( "/proc/meminfo" );
505  if ( !memFile.open( QIODevice::ReadOnly ) )
506  return 0;
507 
508  // read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers'
509  // and 'Cached' fields. consider swapped memory as used memory.
510  qulonglong memoryFree = 0;
511  QString entry;
512  QTextStream readStream( &memFile );
513  static const int nElems = 5;
514  QString names[nElems] = { "MemFree:", "Buffers:", "Cached:", "SwapFree:", "SwapTotal:" };
515  qulonglong values[nElems] = { 0, 0, 0, 0, 0 };
516  bool foundValues[nElems] = { false, false, false, false, false };
517  while ( true )
518  {
519  entry = readStream.readLine();
520  if ( entry.isNull() ) break;
521  for ( int i = 0; i < nElems; ++i )
522  {
523  if ( entry.startsWith( names[i] ) )
524  {
525  values[i] = entry.section( ' ', -2, -2 ).toULongLong( &foundValues[i] );
526  }
527  }
528  }
529  memFile.close();
530  bool found = true;
531  for ( int i = 0; found && i < nElems; ++i )
532  found = found && foundValues[i];
533  if ( found )
534  {
535  /* MemFree + Buffers + Cached - SwapUsed =
536  * = MemFree + Buffers + Cached - (SwapTotal - SwapFree) =
537  * = MemFree + Buffers + Cached + SwapFree - SwapTotal */
538  memoryFree = values[0] + values[1] + values[2] + values[3];
539  if ( values[4] > memoryFree )
540  memoryFree = 0;
541  else
542  memoryFree -= values[4];
543  }
544  else
545  {
546  return 0;
547  }
548 
549  lastUpdate = QTime::currentTime();
550 
551  if (freeSwap)
552  *freeSwap = ( cachedFreeSwap = (Q_UINT64_C(1024) * values[3]) );
553  return ( cachedValue = (Q_UINT64_C(1024) * memoryFree) );
554 #elif defined(Q_OS_FREEBSD)
555  qulonglong cache, inact, free, psize;
556  size_t cachelen, inactlen, freelen, psizelen;
557  cachelen = sizeof( cache );
558  inactlen = sizeof( inact );
559  freelen = sizeof( free );
560  psizelen = sizeof( psize );
561  // sum up inactive, cached and free memory
562  if ( sysctlbyname( "vm.stats.vm.v_cache_count", &cache, &cachelen, NULL, 0 ) == 0 &&
563  sysctlbyname( "vm.stats.vm.v_inactive_count", &inact, &inactlen, NULL, 0 ) == 0 &&
564  sysctlbyname( "vm.stats.vm.v_free_count", &free, &freelen, NULL, 0 ) == 0 &&
565  sysctlbyname( "vm.stats.vm.v_page_size", &psize, &psizelen, NULL, 0 ) == 0 )
566  {
567  lastUpdate = QTime::currentTime();
568  return (cachedValue = (cache + inact + free) * psize);
569  }
570  else
571  {
572  return 0;
573  }
574 #elif defined(Q_OS_WIN)
575  MEMORYSTATUSEX stat;
576  stat.dwLength = sizeof(stat);
577  GlobalMemoryStatusEx (&stat);
578 
579  lastUpdate = QTime::currentTime();
580 
581  if (freeSwap)
582  *freeSwap = ( cachedFreeSwap = stat.ullAvailPageFile );
583  return ( cachedValue = stat.ullAvailPhys );
584 #else
585  // tell the memory is full.. will act as in LOW profile
586  return 0;
587 #endif
588 }
589 
590 void DocumentPrivate::loadDocumentInfo()
591 // note: load data and stores it internally (document or pages). observers
592 // are still uninitialized at this point so don't access them
593 {
594  //kDebug(OkularDebug).nospace() << "Using '" << d->m_xmlFileName << "' as document info file.";
595  if ( m_xmlFileName.isEmpty() )
596  return;
597 
598  loadDocumentInfo( m_xmlFileName );
599 }
600 
601 void DocumentPrivate::loadDocumentInfo( const QString &fileName )
602 {
603  QFile infoFile( fileName );
604  if ( !infoFile.exists() || !infoFile.open( QIODevice::ReadOnly ) )
605  return;
606 
607  // Load DOM from XML file
608  QDomDocument doc( "documentInfo" );
609  if ( !doc.setContent( &infoFile ) )
610  {
611  kDebug(OkularDebug) << "Can't load XML pair! Check for broken xml.";
612  infoFile.close();
613  return;
614  }
615  infoFile.close();
616 
617  QDomElement root = doc.documentElement();
618  if ( root.tagName() != "documentInfo" )
619  return;
620 
621  KUrl documentUrl( root.attribute( "url" ) );
622 
623  // Parse the DOM tree
624  QDomNode topLevelNode = root.firstChild();
625  while ( topLevelNode.isElement() )
626  {
627  QString catName = topLevelNode.toElement().tagName();
628 
629  // Restore page attributes (bookmark, annotations, ...) from the DOM
630  if ( catName == "pageList" )
631  {
632  QDomNode pageNode = topLevelNode.firstChild();
633  while ( pageNode.isElement() )
634  {
635  QDomElement pageElement = pageNode.toElement();
636  if ( pageElement.hasAttribute( "number" ) )
637  {
638  // get page number (node's attribute)
639  bool ok;
640  int pageNumber = pageElement.attribute( "number" ).toInt( &ok );
641 
642  // pass the domElement to the right page, to read config data from
643  if ( ok && pageNumber >= 0 && pageNumber < (int)m_pagesVector.count() )
644  m_pagesVector[ pageNumber ]->d->restoreLocalContents( pageElement );
645  }
646  pageNode = pageNode.nextSibling();
647  }
648  }
649 
650  // Restore 'general info' from the DOM
651  else if ( catName == "generalInfo" )
652  {
653  QDomNode infoNode = topLevelNode.firstChild();
654  while ( infoNode.isElement() )
655  {
656  QDomElement infoElement = infoNode.toElement();
657 
658  // restore viewports history
659  if ( infoElement.tagName() == "history" )
660  {
661  // clear history
662  m_viewportHistory.clear();
663  // append old viewports
664  QDomNode historyNode = infoNode.firstChild();
665  while ( historyNode.isElement() )
666  {
667  QDomElement historyElement = historyNode.toElement();
668  if ( historyElement.hasAttribute( "viewport" ) )
669  {
670  QString vpString = historyElement.attribute( "viewport" );
671  m_viewportIterator = m_viewportHistory.insert( m_viewportHistory.end(),
672  DocumentViewport( vpString ) );
673  }
674  historyNode = historyNode.nextSibling();
675  }
676  // consistancy check
677  if ( m_viewportHistory.isEmpty() )
678  m_viewportIterator = m_viewportHistory.insert( m_viewportHistory.end(), DocumentViewport() );
679  }
680  else if ( infoElement.tagName() == "rotation" )
681  {
682  QString str = infoElement.text();
683  bool ok = true;
684  int newrotation = !str.isEmpty() ? ( str.toInt( &ok ) % 4 ) : 0;
685  if ( ok && newrotation != 0 )
686  {
687  setRotationInternal( newrotation, false );
688  }
689  }
690  else if ( infoElement.tagName() == "views" )
691  {
692  QDomNode viewNode = infoNode.firstChild();
693  while ( viewNode.isElement() )
694  {
695  QDomElement viewElement = viewNode.toElement();
696  if ( viewElement.tagName() == "view" )
697  {
698  const QString viewName = viewElement.attribute( "name" );
699  Q_FOREACH ( View * view, m_views )
700  {
701  if ( view->name() == viewName )
702  {
703  loadViewsInfo( view, viewElement );
704  break;
705  }
706  }
707  }
708  viewNode = viewNode.nextSibling();
709  }
710  }
711  infoNode = infoNode.nextSibling();
712  }
713  }
714 
715  topLevelNode = topLevelNode.nextSibling();
716  } // </documentInfo>
717 }
718 
719 void DocumentPrivate::loadViewsInfo( View *view, const QDomElement &e )
720 {
721  QDomNode viewNode = e.firstChild();
722  while ( viewNode.isElement() )
723  {
724  QDomElement viewElement = viewNode.toElement();
725 
726  if ( viewElement.tagName() == "zoom" )
727  {
728  const QString valueString = viewElement.attribute( "value" );
729  bool newzoom_ok = true;
730  const double newzoom = !valueString.isEmpty() ? valueString.toDouble( &newzoom_ok ) : 1.0;
731  if ( newzoom_ok && newzoom != 0
732  && view->supportsCapability( View::Zoom )
733  && ( view->capabilityFlags( View::Zoom ) & ( View::CapabilityRead | View::CapabilitySerializable ) ) )
734  {
735  view->setCapability( View::Zoom, newzoom );
736  }
737  const QString modeString = viewElement.attribute( "mode" );
738  bool newmode_ok = true;
739  const int newmode = !modeString.isEmpty() ? modeString.toInt( &newmode_ok ) : 2;
740  if ( newmode_ok
741  && view->supportsCapability( View::ZoomModality )
742  && ( view->capabilityFlags( View::ZoomModality ) & ( View::CapabilityRead | View::CapabilitySerializable ) ) )
743  {
744  view->setCapability( View::ZoomModality, newmode );
745  }
746  }
747 
748  viewNode = viewNode.nextSibling();
749  }
750 }
751 
752 void DocumentPrivate::saveViewsInfo( View *view, QDomElement &e ) const
753 {
754  if ( view->supportsCapability( View::Zoom )
755  && ( view->capabilityFlags( View::Zoom ) & ( View::CapabilityRead | View::CapabilitySerializable ) )
756  && view->supportsCapability( View::ZoomModality )
757  && ( view->capabilityFlags( View::ZoomModality ) & ( View::CapabilityRead | View::CapabilitySerializable ) ) )
758  {
759  QDomElement zoomEl = e.ownerDocument().createElement( "zoom" );
760  e.appendChild( zoomEl );
761  bool ok = true;
762  const double zoom = view->capability( View::Zoom ).toDouble( &ok );
763  if ( ok && zoom != 0 )
764  {
765  zoomEl.setAttribute( "value", QString::number(zoom) );
766  }
767  const int mode = view->capability( View::ZoomModality ).toInt( &ok );
768  if ( ok )
769  {
770  zoomEl.setAttribute( "mode", mode );
771  }
772  }
773 }
774 
775 QString DocumentPrivate::giveAbsolutePath( const QString & fileName ) const
776 {
777  if ( !QDir::isRelativePath( fileName ) )
778  return fileName;
779 
780  if ( !m_url.isValid() )
781  return QString();
782 
783  return m_url.upUrl().url() + fileName;
784 }
785 
786 bool DocumentPrivate::openRelativeFile( const QString & fileName )
787 {
788  QString absFileName = giveAbsolutePath( fileName );
789  if ( absFileName.isEmpty() )
790  return false;
791 
792  kDebug(OkularDebug).nospace() << "openDocument: '" << absFileName << "'";
793 
794  emit m_parent->openUrl( absFileName );
795  return true;
796 }
797 
798 Generator * DocumentPrivate::loadGeneratorLibrary( const KService::Ptr &service )
799 {
800  KPluginFactory *factory = KPluginLoader( service->library() ).factory();
801  if ( !factory )
802  {
803  kWarning(OkularDebug).nospace() << "Invalid plugin factory for " << service->library() << "!";
804  return 0;
805  }
806  Generator * generator = factory->create< Okular::Generator >( service->pluginKeyword(), 0 );
807  GeneratorInfo info( factory->componentData() );
808  info.generator = generator;
809  if ( info.data.isValid() && info.data.aboutData() )
810  info.catalogName = info.data.aboutData()->catalogName();
811  m_loadedGenerators.insert( service->name(), info );
812  return generator;
813 }
814 
815 void DocumentPrivate::loadAllGeneratorLibraries()
816 {
817  if ( m_generatorsLoaded )
818  return;
819 
820  m_generatorsLoaded = true;
821 
822  QString constraint("([X-KDE-Priority] > 0) and (exist Library)") ;
823  KService::List offers = KServiceTypeTrader::self()->query( "okular/Generator", constraint );
824  loadServiceList( offers );
825 }
826 
827 void DocumentPrivate::loadServiceList( const KService::List& offers )
828 {
829  int count = offers.count();
830  if ( count <= 0 )
831  return;
832 
833  for ( int i = 0; i < count; ++i )
834  {
835  QString propName = offers.at(i)->name();
836  // don't load already loaded generators
837  QHash< QString, GeneratorInfo >::const_iterator genIt = m_loadedGenerators.constFind( propName );
838  if ( !m_loadedGenerators.isEmpty() && genIt != m_loadedGenerators.constEnd() )
839  continue;
840 
841  Generator * g = loadGeneratorLibrary( offers.at(i) );
842  (void)g;
843  }
844 }
845 
846 void DocumentPrivate::unloadGenerator( const GeneratorInfo& info )
847 {
848  delete info.generator;
849 }
850 
851 void DocumentPrivate::cacheExportFormats()
852 {
853  if ( m_exportCached )
854  return;
855 
856  const ExportFormat::List formats = m_generator->exportFormats();
857  for ( int i = 0; i < formats.count(); ++i )
858  {
859  if ( formats.at( i ).mimeType()->name() == QLatin1String( "text/plain" ) )
860  m_exportToText = formats.at( i );
861  else
862  m_exportFormats.append( formats.at( i ) );
863  }
864 
865  m_exportCached = true;
866 }
867 
868 ConfigInterface* DocumentPrivate::generatorConfig( GeneratorInfo& info )
869 {
870  if ( info.configChecked )
871  return info.config;
872 
873  info.config = qobject_cast< Okular::ConfigInterface * >( info.generator );
874  info.configChecked = true;
875  return info.config;
876 }
877 
878 SaveInterface* DocumentPrivate::generatorSave( GeneratorInfo& info )
879 {
880  if ( info.saveChecked )
881  return info.save;
882 
883  info.save = qobject_cast< Okular::SaveInterface * >( info.generator );
884  info.saveChecked = true;
885  return info.save;
886 }
887 
888 bool DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool isstdin, const QString& docFile, const QByteArray& filedata )
889 {
890  QString propName = offer->name();
891  QHash< QString, GeneratorInfo >::const_iterator genIt = m_loadedGenerators.constFind( propName );
892  QString catalogName;
893  if ( genIt != m_loadedGenerators.constEnd() )
894  {
895  m_generator = genIt.value().generator;
896  catalogName = genIt.value().catalogName;
897  }
898  else
899  {
900  m_generator = loadGeneratorLibrary( offer );
901  if ( !m_generator )
902  return false;
903  genIt = m_loadedGenerators.constFind( propName );
904  Q_ASSERT( genIt != m_loadedGenerators.constEnd() );
905  catalogName = genIt.value().catalogName;
906  }
907  Q_ASSERT_X( m_generator, "Document::load()", "null generator?!" );
908 
909  if ( !catalogName.isEmpty() )
910  KGlobal::locale()->insertCatalog( catalogName );
911 
912  m_generator->d_func()->m_document = this;
913 
914  // connect error reporting signals
915  QObject::connect( m_generator, SIGNAL(error(QString,int)), m_parent, SIGNAL(error(QString,int)) );
916  QObject::connect( m_generator, SIGNAL(warning(QString,int)), m_parent, SIGNAL(warning(QString,int)) );
917  QObject::connect( m_generator, SIGNAL(notice(QString,int)), m_parent, SIGNAL(notice(QString,int)) );
918 
919  QApplication::setOverrideCursor( Qt::WaitCursor );
920  bool openOk = false;
921  if ( !isstdin )
922  {
923  openOk = m_generator->loadDocument( docFile, m_pagesVector );
924  }
925  else if ( !filedata.isEmpty() )
926  {
927  if ( m_generator->hasFeature( Generator::ReadRawData ) )
928  {
929  openOk = m_generator->loadDocumentFromData( filedata, m_pagesVector );
930  }
931  else
932  {
933  m_tempFile = new KTemporaryFile();
934  if ( !m_tempFile->open() )
935  {
936  delete m_tempFile;
937  m_tempFile = 0;
938  }
939  else
940  {
941  m_tempFile->write( filedata );
942  QString tmpFileName = m_tempFile->fileName();
943  m_tempFile->close();
944  openOk = m_generator->loadDocument( tmpFileName, m_pagesVector );
945  }
946  }
947  }
948 
949  QApplication::restoreOverrideCursor();
950  if ( !openOk || m_pagesVector.size() <= 0 )
951  {
952  if ( !catalogName.isEmpty() )
953  KGlobal::locale()->removeCatalog( catalogName );
954 
955  m_generator->d_func()->m_document = 0;
956  QObject::disconnect( m_generator, 0, m_parent, 0 );
957  m_generator = 0;
958 
959  qDeleteAll( m_pagesVector );
960  m_pagesVector.clear();
961  delete m_tempFile;
962  m_tempFile = 0;
963 
964  // TODO: emit a message telling the document is empty
965 
966  openOk = false;
967  }
968 
969  return openOk;
970 }
971 
972 bool DocumentPrivate::savePageDocumentInfo( KTemporaryFile *infoFile, int what ) const
973 {
974  if ( infoFile->open() )
975  {
976  // 1. Create DOM
977  QDomDocument doc( "documentInfo" );
978  QDomProcessingInstruction xmlPi = doc.createProcessingInstruction(
979  QString::fromLatin1( "xml" ), QString::fromLatin1( "version=\"1.0\" encoding=\"utf-8\"" ) );
980  doc.appendChild( xmlPi );
981  QDomElement root = doc.createElement( "documentInfo" );
982  doc.appendChild( root );
983 
984  // 2.1. Save page attributes (bookmark state, annotations, ... ) to DOM
985  QDomElement pageList = doc.createElement( "pageList" );
986  root.appendChild( pageList );
987  // <page list><page number='x'>.... </page> save pages that hold data
988  QVector< Page * >::const_iterator pIt = m_pagesVector.constBegin(), pEnd = m_pagesVector.constEnd();
989  for ( ; pIt != pEnd; ++pIt )
990  (*pIt)->d->saveLocalContents( pageList, doc, PageItems( what ) );
991 
992  // 3. Save DOM to XML file
993  QString xml = doc.toString();
994  QTextStream os( infoFile );
995  os.setCodec( "UTF-8" );
996  os << xml;
997  return true;
998  }
999  return false;
1000 }
1001 
1002 DocumentViewport DocumentPrivate::nextDocumentViewport() const
1003 {
1004  DocumentViewport ret = m_nextDocumentViewport;
1005  if ( !m_nextDocumentDestination.isEmpty() && m_generator )
1006  {
1007  DocumentViewport vp( m_generator->metaData( "NamedViewport", m_nextDocumentDestination ).toString() );
1008  if ( vp.isValid() )
1009  {
1010  ret = vp;
1011  }
1012  }
1013  return ret;
1014 }
1015 
1016 void DocumentPrivate::warnLimitedAnnotSupport()
1017 {
1018  if ( !m_showWarningLimitedAnnotSupport )
1019  return;
1020  m_showWarningLimitedAnnotSupport = false; // Show the warning once
1021 
1022  if ( m_annotationsNeedSaveAs )
1023  {
1024  // Shown if the user is editing annotations in a file whose metadata is
1025  // not stored locally (.okular archives belong to this category)
1026  KMessageBox::information( m_parent->widget(), i18n("Your annotation changes will not be saved automatically. Use File -> Save As...\nor your changes will be lost once the document is closed"), QString(), "annotNeedSaveAs" );
1027  }
1028  else if ( !canAddAnnotationsNatively() )
1029  {
1030  // If the generator doesn't support native annotations
1031  KMessageBox::information( m_parent->widget(), i18n("Your annotations are saved internally by Okular.\nYou can export the annotated document using File -> Export As -> Document Archive"), QString(), "annotExportAsArchive" );
1032  }
1033 }
1034 
1035 void DocumentPrivate::performAddPageAnnotation( int page, Annotation * annotation )
1036 {
1037  Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
1038  AnnotationProxy *proxy = iface ? iface->annotationProxy() : 0;
1039 
1040  // find out the page to attach annotation
1041  Page * kp = m_pagesVector[ page ];
1042  if ( !m_generator || !kp )
1043  return;
1044 
1045  // the annotation belongs already to a page
1046  if ( annotation->d_ptr->m_page )
1047  return;
1048 
1049  // add annotation to the page
1050  kp->addAnnotation( annotation );
1051 
1052  // tell the annotation proxy
1053  if ( proxy && proxy->supports(AnnotationProxy::Addition) )
1054  proxy->notifyAddition( annotation, page );
1055 
1056  // notify observers about the change
1057  notifyAnnotationChanges( page );
1058 
1059  if ( annotation->flags() & Annotation::ExternallyDrawn )
1060  {
1061  // Redraw everything, including ExternallyDrawn annotations
1062  refreshPixmaps( page );
1063  }
1064 
1065  warnLimitedAnnotSupport();
1066 }
1067 
1068 void DocumentPrivate::performRemovePageAnnotation( int page, Annotation * annotation )
1069 {
1070  Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
1071  AnnotationProxy *proxy = iface ? iface->annotationProxy() : 0;
1072  bool isExternallyDrawn;
1073 
1074  // find out the page
1075  Page * kp = m_pagesVector[ page ];
1076  if ( !m_generator || !kp )
1077  return;
1078 
1079  if ( annotation->flags() & Annotation::ExternallyDrawn )
1080  isExternallyDrawn = true;
1081  else
1082  isExternallyDrawn = false;
1083 
1084  // try to remove the annotation
1085  if ( m_parent->canRemovePageAnnotation( annotation ) )
1086  {
1087  // tell the annotation proxy
1088  if ( proxy && proxy->supports(AnnotationProxy::Removal) )
1089  proxy->notifyRemoval( annotation, page );
1090 
1091  kp->removeAnnotation( annotation ); // Also destroys the object
1092 
1093  // in case of success, notify observers about the change
1094  notifyAnnotationChanges( page );
1095 
1096  if ( isExternallyDrawn )
1097  {
1098  // Redraw everything, including ExternallyDrawn annotations
1099  refreshPixmaps( page );
1100  }
1101  }
1102 
1103  warnLimitedAnnotSupport();
1104 }
1105 
1106 void DocumentPrivate::performModifyPageAnnotation( int page, Annotation * annotation, bool appearanceChanged )
1107 {
1108  Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
1109  AnnotationProxy *proxy = iface ? iface->annotationProxy() : 0;
1110 
1111  // find out the page
1112  Page * kp = m_pagesVector[ page ];
1113  if ( !m_generator || !kp )
1114  return;
1115 
1116  // tell the annotation proxy
1117  if ( proxy && proxy->supports(AnnotationProxy::Modification) )
1118  {
1119  proxy->notifyModification( annotation, page, appearanceChanged );
1120  }
1121 
1122  // notify observers about the change
1123  notifyAnnotationChanges( page );
1124  if ( appearanceChanged && (annotation->flags() & Annotation::ExternallyDrawn) )
1125  {
1126  /* When an annotation is being moved, the generator will not render it.
1127  * Therefore there's no need to refresh pixmaps after the first time */
1128  if ( annotation->flags() & Annotation::BeingMoved )
1129  {
1130  if ( m_annotationBeingMoved )
1131  return;
1132  else // First time: take note
1133  m_annotationBeingMoved = true;
1134  }
1135  else
1136  {
1137  m_annotationBeingMoved = false;
1138  }
1139 
1140  // Redraw everything, including ExternallyDrawn annotations
1141  kDebug(OkularDebug) << "Refreshing Pixmaps";
1142  refreshPixmaps( page );
1143  }
1144 
1145  // If the user is moving the annotation, don't steal the focus
1146  if ( (annotation->flags() & Annotation::BeingMoved) == 0 )
1147  warnLimitedAnnotSupport();
1148 }
1149 
1150 void DocumentPrivate::performSetAnnotationContents( const QString & newContents, Annotation *annot, int pageNumber )
1151 {
1152  bool appearanceChanged = false;
1153 
1154  // Check if appearanceChanged should be true
1155  switch ( annot->subType() )
1156  {
1157  // If it's an in-place TextAnnotation, set the inplace text
1158  case Okular::Annotation::AText:
1159  {
1160  Okular::TextAnnotation * txtann = static_cast< Okular::TextAnnotation * >( annot );
1161  if ( txtann->textType() == Okular::TextAnnotation::InPlace )
1162  {
1163  appearanceChanged = true;
1164  }
1165  break;
1166  }
1167  // If it's a LineAnnotation, check if caption text is visible
1168  case Okular::Annotation::ALine:
1169  {
1170  Okular::LineAnnotation * lineann = static_cast< Okular::LineAnnotation * >( annot );
1171  if ( lineann->showCaption() )
1172  appearanceChanged = true;
1173  break;
1174  }
1175  default:
1176  break;
1177  }
1178 
1179  // Set contents
1180  annot->setContents( newContents );
1181 
1182  // Tell the document the annotation has been modified
1183  performModifyPageAnnotation( pageNumber, annot, appearanceChanged );
1184 }
1185 
1186 void DocumentPrivate::saveDocumentInfo() const
1187 {
1188  if ( m_xmlFileName.isEmpty() )
1189  return;
1190 
1191  QFile infoFile( m_xmlFileName );
1192  if (infoFile.open( QIODevice::WriteOnly | QIODevice::Truncate) )
1193  {
1194  // 1. Create DOM
1195  QDomDocument doc( "documentInfo" );
1196  QDomProcessingInstruction xmlPi = doc.createProcessingInstruction(
1197  QString::fromLatin1( "xml" ), QString::fromLatin1( "version=\"1.0\" encoding=\"utf-8\"" ) );
1198  doc.appendChild( xmlPi );
1199  QDomElement root = doc.createElement( "documentInfo" );
1200  root.setAttribute( "url", m_url.pathOrUrl() );
1201  doc.appendChild( root );
1202 
1203  // 2.1. Save page attributes (bookmark state, annotations, ... ) to DOM
1204  QDomElement pageList = doc.createElement( "pageList" );
1205  root.appendChild( pageList );
1206  PageItems saveWhat = AllPageItems;
1207  if ( m_annotationsNeedSaveAs )
1208  {
1209  /* In this case, if the user makes a modification, he's requested to
1210  * save to a new document. Therefore, if there are existing local
1211  * annotations, we save them back unmodified in the original
1212  * document's metadata, so that it appears that it was not changed */
1213  saveWhat |= OriginalAnnotationPageItems;
1214  }
1215  // <page list><page number='x'>.... </page> save pages that hold data
1216  QVector< Page * >::const_iterator pIt = m_pagesVector.constBegin(), pEnd = m_pagesVector.constEnd();
1217  for ( ; pIt != pEnd; ++pIt )
1218  (*pIt)->d->saveLocalContents( pageList, doc, saveWhat );
1219 
1220  // 2.2. Save document info (current viewport, history, ... ) to DOM
1221  QDomElement generalInfo = doc.createElement( "generalInfo" );
1222  root.appendChild( generalInfo );
1223  // create rotation node
1224  if ( m_rotation != Rotation0 )
1225  {
1226  QDomElement rotationNode = doc.createElement( "rotation" );
1227  generalInfo.appendChild( rotationNode );
1228  rotationNode.appendChild( doc.createTextNode( QString::number( (int)m_rotation ) ) );
1229  }
1230  // <general info><history> ... </history> save history up to OKULAR_HISTORY_SAVEDSTEPS viewports
1231  QLinkedList< DocumentViewport >::const_iterator backIterator = m_viewportIterator;
1232  if ( backIterator != m_viewportHistory.constEnd() )
1233  {
1234  // go back up to OKULAR_HISTORY_SAVEDSTEPS steps from the current viewportIterator
1235  int backSteps = OKULAR_HISTORY_SAVEDSTEPS;
1236  while ( backSteps-- && backIterator != m_viewportHistory.constBegin() )
1237  --backIterator;
1238 
1239  // create history root node
1240  QDomElement historyNode = doc.createElement( "history" );
1241  generalInfo.appendChild( historyNode );
1242 
1243  // add old[backIterator] and present[viewportIterator] items
1244  QLinkedList< DocumentViewport >::const_iterator endIt = m_viewportIterator;
1245  ++endIt;
1246  while ( backIterator != endIt )
1247  {
1248  QString name = (backIterator == m_viewportIterator) ? "current" : "oldPage";
1249  QDomElement historyEntry = doc.createElement( name );
1250  historyEntry.setAttribute( "viewport", (*backIterator).toString() );
1251  historyNode.appendChild( historyEntry );
1252  ++backIterator;
1253  }
1254  }
1255  // create views root node
1256  QDomElement viewsNode = doc.createElement( "views" );
1257  generalInfo.appendChild( viewsNode );
1258  Q_FOREACH ( View * view, m_views )
1259  {
1260  QDomElement viewEntry = doc.createElement( "view" );
1261  viewEntry.setAttribute( "name", view->name() );
1262  viewsNode.appendChild( viewEntry );
1263  saveViewsInfo( view, viewEntry );
1264  }
1265 
1266  // 3. Save DOM to XML file
1267  QString xml = doc.toString();
1268  QTextStream os( &infoFile );
1269  os.setCodec( "UTF-8" );
1270  os << xml;
1271  }
1272  infoFile.close();
1273 }
1274 
1275 void DocumentPrivate::slotTimedMemoryCheck()
1276 {
1277  // [MEM] clean memory (for 'free mem dependant' profiles only)
1278  if ( SettingsCore::memoryLevel() != SettingsCore::EnumMemoryLevel::Low &&
1279  m_allocatedPixmapsTotalMemory > 1024*1024 )
1280  cleanupPixmapMemory();
1281 }
1282 
1283 void DocumentPrivate::sendGeneratorPixmapRequest()
1284 {
1285  /* If the pixmap cache will have to be cleaned in order to make room for the
1286  * next request, get the distance from the current viewport of the page
1287  * whose pixmap will be removed. We will ignore preload requests for pages
1288  * that are at the same distance or farther */
1289  const qulonglong memoryToFree = calculateMemoryToFree();
1290  const int currentViewportPage = (*m_viewportIterator).pageNumber;
1291  int maxDistance = INT_MAX; // Default: No maximum
1292  if ( memoryToFree )
1293  {
1294  AllocatedPixmap *pixmapToReplace = searchLowestPriorityPixmap( true );
1295  if ( pixmapToReplace )
1296  maxDistance = qAbs( pixmapToReplace->page - currentViewportPage );
1297  }
1298 
1299  // find a request
1300  PixmapRequest * request = 0;
1301  m_pixmapRequestsMutex.lock();
1302  while ( !m_pixmapRequestsStack.isEmpty() && !request )
1303  {
1304  PixmapRequest * r = m_pixmapRequestsStack.last();
1305  if (!r)
1306  {
1307  m_pixmapRequestsStack.pop_back();
1308  continue;
1309  }
1310 
1311  QRect requestRect = r->isTile() ? r->normalizedRect().geometry( r->width(), r->height() ) : QRect( 0, 0, r->width(), r->height() );
1312  TilesManager *tilesManager = ( r->observer() == m_tiledObserver ) ? r->page()->d->tilesManager() : 0;
1313 
1314  // If it's a preload but the generator is not threaded no point in trying to preload
1315  if ( r->preload() && !m_generator->hasFeature( Generator::Threaded ) )
1316  {
1317  m_pixmapRequestsStack.pop_back();
1318  delete r;
1319  }
1320  // request only if page isn't already present and request has valid id
1321  // request only if page isn't already present and request has valid id
1322  else if ( ( !r->d->mForce && r->page()->hasPixmap( r->observer(), r->width(), r->height(), r->normalizedRect() ) ) || !m_observers.contains(r->observer()) )
1323  {
1324  m_pixmapRequestsStack.pop_back();
1325  delete r;
1326  }
1327  else if ( !r->d->mForce && r->preload() && qAbs( r->pageNumber() - currentViewportPage ) >= maxDistance )
1328  {
1329  m_pixmapRequestsStack.pop_back();
1330  //kDebug() << "Ignoring request that doesn't fit in cache";
1331  delete r;
1332  }
1333  // Ignore requests for pixmaps that are already being generated
1334  else if ( tilesManager && tilesManager->isRequesting( r->normalizedRect(), r->width(), r->height() ) )
1335  {
1336  m_pixmapRequestsStack.pop_back();
1337  delete r;
1338  }
1339  // If the requested area is above 8000000 pixels, switch on the tile manager
1340  else if ( !tilesManager && r->observer() == m_tiledObserver && m_generator->hasFeature( Generator::TiledRendering ) && (long)r->width() * (long)r->height() > 8000000L )
1341  {
1342  // if the image is too big. start using tiles
1343  kDebug(OkularDebug).nospace() << "Start using tiles on page " << r->pageNumber()
1344  << " (" << r->width() << "x" << r->height() << " px);";
1345 
1346  // fill the tiles manager with the last rendered pixmap
1347  const QPixmap *pixmap = r->page()->_o_nearestPixmap( r->observer(), r->width(), r->height() );
1348  if ( pixmap )
1349  {
1350  tilesManager = new TilesManager( r->pageNumber(), pixmap->width(), pixmap->height(), r->page()->rotation() );
1351  tilesManager->setPixmap( pixmap, NormalizedRect( 0, 0, 1, 1 ) );
1352  tilesManager->setSize( r->width(), r->height() );
1353  }
1354  else
1355  {
1356  // create new tiles manager
1357  tilesManager = new TilesManager( r->pageNumber(), r->width(), r->height(), r->page()->rotation() );
1358  }
1359  tilesManager->setRequest( r->normalizedRect(), r->width(), r->height() );
1360  r->page()->deletePixmap( r->observer() );
1361  r->page()->d->setTilesManager( tilesManager );
1362  r->setTile( true );
1363 
1364  // Change normalizedRect to the smallest rect that contains all
1365  // visible tiles.
1366  if ( !r->normalizedRect().isNull() )
1367  {
1368  NormalizedRect tilesRect;
1369  const QList<Tile> tiles = tilesManager->tilesAt( r->normalizedRect(), TilesManager::TerminalTile );
1370  QList<Tile>::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd();
1371  while ( tIt != tEnd )
1372  {
1373  Tile tile = *tIt;
1374  if ( tilesRect.isNull() )
1375  tilesRect = tile.rect();
1376  else
1377  tilesRect |= tile.rect();
1378 
1379  ++tIt;
1380  }
1381 
1382  r->setNormalizedRect( tilesRect );
1383  request = r;
1384  }
1385  else
1386  {
1387  // Discard request if normalizedRect is null. This happens in
1388  // preload requests issued by PageView if the requested page is
1389  // not visible and the user has just switched from a non-tiled
1390  // zoom level to a tiled one
1391  m_pixmapRequestsStack.pop_back();
1392  delete r;
1393  }
1394  }
1395  // If the requested area is below 6000000 pixels, switch off the tile manager
1396  else if ( tilesManager && (long)r->width() * (long)r->height() < 6000000L )
1397  {
1398  kDebug(OkularDebug).nospace() << "Stop using tiles on page " << r->pageNumber()
1399  << " (" << r->width() << "x" << r->height() << " px);";
1400 
1401  // page is too small. stop using tiles.
1402  r->page()->deletePixmap( r->observer() );
1403  r->setTile( false );
1404 
1405  request = r;
1406  }
1407  else if ( (long)requestRect.width() * (long)requestRect.height() > 20000000L )
1408  {
1409  m_pixmapRequestsStack.pop_back();
1410  if ( !m_warnedOutOfMemory )
1411  {
1412  kWarning(OkularDebug).nospace() << "Running out of memory on page " << r->pageNumber()
1413  << " (" << r->width() << "x" << r->height() << " px);";
1414  kWarning(OkularDebug) << "this message will be reported only once.";
1415  m_warnedOutOfMemory = true;
1416  }
1417  delete r;
1418  }
1419  else
1420  {
1421  request = r;
1422  }
1423  }
1424 
1425  // if no request found (or already generated), return
1426  if ( !request )
1427  {
1428  m_pixmapRequestsMutex.unlock();
1429  return;
1430  }
1431 
1432  // [MEM] preventive memory freeing
1433  qulonglong pixmapBytes = 0;
1434  TilesManager * tm = ( request->observer() == m_tiledObserver ) ? request->page()->d->tilesManager() : 0;
1435  if ( tm )
1436  pixmapBytes = tm->totalMemory();
1437  else
1438  pixmapBytes = 4 * request->width() * request->height();
1439 
1440  if ( pixmapBytes > (1024 * 1024) )
1441  cleanupPixmapMemory( memoryToFree /* previously calculated value */ );
1442 
1443  // submit the request to the generator
1444  if ( m_generator->canGeneratePixmap() )
1445  {
1446  QRect requestRect = !request->isTile() ? QRect(0, 0, request->width(), request->height() ) : request->normalizedRect().geometry( request->width(), request->height() );
1447  kDebug(OkularDebug).nospace() << "sending request observer=" << request->observer() << " " <<requestRect.width() << "x" << requestRect.height() << "@" << request->pageNumber() << " async == " << request->asynchronous() << " isTile == " << request->isTile();
1448  m_pixmapRequestsStack.removeAll ( request );
1449 
1450  if ( tm )
1451  tm->setRequest( request->normalizedRect(), request->width(), request->height() );
1452 
1453  if ( (int)m_rotation % 2 )
1454  request->d->swap();
1455 
1456  if ( m_rotation != Rotation0 && !request->normalizedRect().isNull() )
1457  request->setNormalizedRect( TilesManager::fromRotatedRect(
1458  request->normalizedRect(), m_rotation ) );
1459 
1460  // we always have to unlock _before_ the generatePixmap() because
1461  // a sync generation would end with requestDone() -> deadlock, and
1462  // we can not really know if the generator can do async requests
1463  m_executingPixmapRequests.push_back( request );
1464  m_pixmapRequestsMutex.unlock();
1465  m_generator->generatePixmap( request );
1466  }
1467  else
1468  {
1469  m_pixmapRequestsMutex.unlock();
1470  // pino (7/4/2006): set the polling interval from 10 to 30
1471  QTimer::singleShot( 30, m_parent, SLOT(sendGeneratorPixmapRequest()) );
1472  }
1473 }
1474 
1475 void DocumentPrivate::rotationFinished( int page, Okular::Page *okularPage )
1476 {
1477  Okular::Page *wantedPage = m_pagesVector.value( page, 0 );
1478  if ( !wantedPage || wantedPage != okularPage )
1479  return;
1480 
1481  foreach(DocumentObserver *o, m_observers)
1482  o->notifyPageChanged( page, DocumentObserver::Pixmap | DocumentObserver::Annotations );
1483 }
1484 
1485 void DocumentPrivate::fontReadingProgress( int page )
1486 {
1487  emit m_parent->fontReadingProgress( page );
1488 
1489  if ( page >= (int)m_parent->pages() - 1 )
1490  {
1491  emit m_parent->fontReadingEnded();
1492  m_fontThread = 0;
1493  m_fontsCached = true;
1494  }
1495 }
1496 
1497 void DocumentPrivate::fontReadingGotFont( const Okular::FontInfo& font )
1498 {
1499  // TODO try to avoid duplicate fonts
1500  m_fontsCache.append( font );
1501 
1502  emit m_parent->gotFont( font );
1503 }
1504 
1505 void DocumentPrivate::slotGeneratorConfigChanged( const QString& )
1506 {
1507  if ( !m_generator )
1508  return;
1509 
1510  // reparse generator config and if something changed clear Pages
1511  bool configchanged = false;
1512  QHash< QString, GeneratorInfo >::iterator it = m_loadedGenerators.begin(), itEnd = m_loadedGenerators.end();
1513  for ( ; it != itEnd; ++it )
1514  {
1515  Okular::ConfigInterface * iface = generatorConfig( it.value() );
1516  if ( iface )
1517  {
1518  bool it_changed = iface->reparseConfig();
1519  if ( it_changed && ( m_generator == it.value().generator ) )
1520  configchanged = true;
1521  }
1522  }
1523  if ( configchanged )
1524  {
1525  // invalidate pixmaps
1526  QVector<Page*>::const_iterator it = m_pagesVector.constBegin(), end = m_pagesVector.constEnd();
1527  for ( ; it != end; ++it ) {
1528  (*it)->deletePixmaps();
1529  }
1530 
1531  // [MEM] remove allocation descriptors
1532  qDeleteAll( m_allocatedPixmaps );
1533  m_allocatedPixmaps.clear();
1534  m_allocatedPixmapsTotalMemory = 0;
1535 
1536  // send reload signals to observers
1537  foreachObserverD( notifyContentsCleared( DocumentObserver::Pixmap ) );
1538  }
1539 
1540  // free memory if in 'low' profile
1541  if ( SettingsCore::memoryLevel() == SettingsCore::EnumMemoryLevel::Low &&
1542  !m_allocatedPixmaps.isEmpty() && !m_pagesVector.isEmpty() )
1543  cleanupPixmapMemory();
1544 }
1545 
1546 void DocumentPrivate::refreshPixmaps( int pageNumber )
1547 {
1548  Page* page = m_pagesVector.value( pageNumber, 0 );
1549  if ( !page )
1550  return;
1551 
1552  QLinkedList< Okular::PixmapRequest * > requestedPixmaps;
1553  QMap< DocumentObserver*, PagePrivate::PixmapObject >::ConstIterator it = page->d->m_pixmaps.constBegin(), itEnd = page->d->m_pixmaps.constEnd();
1554  for ( ; it != itEnd; ++it )
1555  {
1556  QSize size = (*it).m_pixmap->size();
1557  PixmapRequest * p = new PixmapRequest( it.key(), pageNumber, size.width(), size.height(), 1, PixmapRequest::Asynchronous );
1558  p->d->mForce = true;
1559  requestedPixmaps.push_back( p );
1560  }
1561 
1562  TilesManager *tilesManager = page->d->tilesManager();
1563  if ( tilesManager )
1564  {
1565  tilesManager->markDirty();
1566 
1567  PixmapRequest * p = new PixmapRequest( m_tiledObserver, pageNumber, tilesManager->width(), tilesManager->height(), 1, PixmapRequest::Asynchronous );
1568 
1569  NormalizedRect tilesRect;
1570 
1571  // Get the visible page rect
1572  NormalizedRect visibleRect;
1573  QVector< Okular::VisiblePageRect * >::const_iterator vIt = m_pageRects.constBegin(), vEnd = m_pageRects.constEnd();
1574  for ( ; vIt != vEnd; ++vIt )
1575  {
1576  if ( (*vIt)->pageNumber == pageNumber )
1577  {
1578  visibleRect = (*vIt)->rect;
1579  break;
1580  }
1581  }
1582 
1583  if ( !visibleRect.isNull() )
1584  {
1585  p->setNormalizedRect( visibleRect );
1586  p->setTile( true );
1587  p->d->mForce = true;
1588  requestedPixmaps.push_back( p );
1589  }
1590  else
1591  {
1592  delete p;
1593  }
1594  }
1595  if ( !requestedPixmaps.isEmpty() )
1596  m_parent->requestPixmaps( requestedPixmaps, Okular::Document::NoOption );
1597 }
1598 
1599 void DocumentPrivate::_o_configChanged()
1600 {
1601  // free text pages if needed
1602  calculateMaxTextPages();
1603  while (m_allocatedTextPagesFifo.count() > m_maxAllocatedTextPages)
1604  {
1605  int pageToKick = m_allocatedTextPagesFifo.takeFirst();
1606  m_pagesVector.at(pageToKick)->setTextPage( 0 ); // deletes the textpage
1607  }
1608 }
1609 
1610 void DocumentPrivate::doContinueDirectionMatchSearch(void *doContinueDirectionMatchSearchStruct)
1611 {
1612  DoContinueDirectionMatchSearchStruct *searchStruct = static_cast<DoContinueDirectionMatchSearchStruct *>(doContinueDirectionMatchSearchStruct);
1613  RunningSearch *search = m_searches.value(searchStruct->searchID);
1614 
1615  if ((m_searchCancelled && !searchStruct->match) || !search)
1616  {
1617  // if the user cancelled but he just got a match, give him the match!
1618  QApplication::restoreOverrideCursor();
1619 
1620  if (search) search->isCurrentlySearching = false;
1621 
1622  emit m_parent->searchFinished( searchStruct->searchID, Document::SearchCancelled );
1623  delete searchStruct->pagesToNotify;
1624  delete searchStruct;
1625  return;
1626  }
1627 
1628  bool doContinue = false;
1629  // if no match found, loop through the whole doc, starting from currentPage
1630  if ( !searchStruct->match )
1631  {
1632  const int pageCount = m_pagesVector.count();
1633  if (searchStruct->pagesDone < pageCount)
1634  {
1635  doContinue = true;
1636  if ( searchStruct->currentPage >= pageCount || searchStruct->currentPage < 0 )
1637  {
1638  const QString question = searchStruct->forward ? i18n("End of document reached.\nContinue from the beginning?") : i18n("Beginning of document reached.\nContinue from the bottom?");
1639  if ( searchStruct->noDialogs || KMessageBox::questionYesNo(m_parent->widget(), question, QString(), KStandardGuiItem::cont(), KStandardGuiItem::cancel()) == KMessageBox::Yes )
1640  searchStruct->currentPage = searchStruct->forward ? 0 : pageCount - 1;
1641  else
1642  doContinue = false;
1643  }
1644  }
1645  }
1646 
1647  if (doContinue)
1648  {
1649  // get page
1650  Page * page = m_pagesVector[ searchStruct->currentPage ];
1651  // request search page if needed
1652  if ( !page->hasTextPage() )
1653  m_parent->requestTextPage( page->number() );
1654 
1655  // if found a match on the current page, end the loop
1656  searchStruct->match = page->findText( searchStruct->searchID, searchStruct->text, searchStruct->forward ? FromTop : FromBottom, searchStruct->caseSensitivity );
1657 
1658  if ( !searchStruct->match )
1659  {
1660  if (searchStruct->forward) searchStruct->currentPage++;
1661  else searchStruct->currentPage--;
1662  searchStruct->pagesDone++;
1663  }
1664  else
1665  {
1666  searchStruct->pagesDone = 1;
1667  }
1668 
1669  // Both of the previous if branches need to call doContinueDirectionMatchSearch
1670  QMetaObject::invokeMethod(m_parent, "doContinueDirectionMatchSearch", Qt::QueuedConnection, Q_ARG(void *, searchStruct));
1671  }
1672  else
1673  {
1674  doProcessSearchMatch( searchStruct->match, search, searchStruct->pagesToNotify, searchStruct->currentPage, searchStruct->searchID, searchStruct->moveViewport, searchStruct->color );
1675  delete searchStruct;
1676  }
1677 }
1678 
1679 void DocumentPrivate::doProcessSearchMatch( RegularAreaRect *match, RunningSearch *search, QSet< int > *pagesToNotify, int currentPage, int searchID, bool moveViewport, const QColor & color )
1680 {
1681  // reset cursor to previous shape
1682  QApplication::restoreOverrideCursor();
1683 
1684  bool foundAMatch = false;
1685 
1686  search->isCurrentlySearching = false;
1687 
1688  // if a match has been found..
1689  if ( match )
1690  {
1691  // update the RunningSearch structure adding this match..
1692  foundAMatch = true;
1693  search->continueOnPage = currentPage;
1694  search->continueOnMatch = *match;
1695  search->highlightedPages.insert( currentPage );
1696  // ..add highlight to the page..
1697  m_pagesVector[ currentPage ]->d->setHighlight( searchID, match, color );
1698 
1699  // ..queue page for notifying changes..
1700  pagesToNotify->insert( currentPage );
1701 
1702  // ..move the viewport to show the first of the searched word sequence centered
1703  if ( moveViewport )
1704  {
1705  DocumentViewport searchViewport( currentPage );
1706  searchViewport.rePos.enabled = true;
1707  searchViewport.rePos.normalizedX = (match->first().left + match->first().right) / 2.0;
1708  searchViewport.rePos.normalizedY = (match->first().top + match->first().bottom) / 2.0;
1709  m_parent->setViewport( searchViewport, 0, true );
1710  }
1711  delete match;
1712  }
1713 #if 0
1714  else if ( !noDialogs )
1715  KMessageBox::information( m_parent->widget(), i18n( "No matches found for '%1'.", text ) );
1716 #endif
1717 
1718  // notify observers about highlights changes
1719  foreach(int pageNumber, *pagesToNotify)
1720  foreach(DocumentObserver *observer, m_observers)
1721  observer->notifyPageChanged( pageNumber, DocumentObserver::Highlights );
1722 
1723  if (foundAMatch) emit m_parent->searchFinished( searchID, Document::MatchFound );
1724  else emit m_parent->searchFinished( searchID, Document::NoMatchFound );
1725 
1726  delete pagesToNotify;
1727 }
1728 
1729 void DocumentPrivate::doContinueAllDocumentSearch(void *pagesToNotifySet, void *pageMatchesMap, int currentPage, int searchID, const QString & text, int theCaseSensitivity, const QColor & color)
1730 {
1731  QMap< Page *, QVector<RegularAreaRect *> > *pageMatches = static_cast< QMap< Page *, QVector<RegularAreaRect *> > * >(pageMatchesMap);
1732  Qt::CaseSensitivity caseSensitivity = static_cast<Qt::CaseSensitivity>(theCaseSensitivity);
1733  QSet< int > *pagesToNotify = static_cast< QSet< int > * >( pagesToNotifySet );
1734  RunningSearch *search = m_searches.value(searchID);
1735 
1736  if (m_searchCancelled || !search)
1737  {
1738  typedef QVector<RegularAreaRect *> MatchesVector;
1739 
1740  QApplication::restoreOverrideCursor();
1741 
1742  if (search) search->isCurrentlySearching = false;
1743 
1744  emit m_parent->searchFinished( searchID, Document::SearchCancelled );
1745  foreach(const MatchesVector &mv, *pageMatches) qDeleteAll(mv);
1746  delete pageMatches;
1747  delete pagesToNotify;
1748  return;
1749  }
1750 
1751  if (currentPage < m_pagesVector.count())
1752  {
1753  // get page (from the first to the last)
1754  Page *page = m_pagesVector.at(currentPage);
1755  int pageNumber = page->number(); // redundant? is it == currentPage ?
1756 
1757  // request search page if needed
1758  if ( !page->hasTextPage() )
1759  m_parent->requestTextPage( pageNumber );
1760 
1761  // loop on a page adding highlights for all found items
1762  RegularAreaRect * lastMatch = 0;
1763  while ( 1 )
1764  {
1765  if ( lastMatch )
1766  lastMatch = page->findText( searchID, text, NextResult, caseSensitivity, lastMatch );
1767  else
1768  lastMatch = page->findText( searchID, text, FromTop, caseSensitivity );
1769 
1770  if ( !lastMatch )
1771  break;
1772 
1773  // add highligh rect to the matches map
1774  (*pageMatches)[page].append(lastMatch);
1775  }
1776  delete lastMatch;
1777 
1778  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));
1779  }
1780  else
1781  {
1782  // reset cursor to previous shape
1783  QApplication::restoreOverrideCursor();
1784 
1785  search->isCurrentlySearching = false;
1786  bool foundAMatch = pageMatches->count() != 0;
1787  QMap< Page *, QVector<RegularAreaRect *> >::const_iterator it, itEnd;
1788  it = pageMatches->constBegin();
1789  itEnd = pageMatches->constEnd();
1790  for ( ; it != itEnd; ++it)
1791  {
1792  foreach(RegularAreaRect *match, it.value())
1793  {
1794  it.key()->d->setHighlight( searchID, match, color );
1795  delete match;
1796  }
1797  search->highlightedPages.insert( it.key()->number() );
1798  pagesToNotify->insert( it.key()->number() );
1799  }
1800 
1801  foreach(DocumentObserver *observer, m_observers)
1802  observer->notifySetup( m_pagesVector, 0 );
1803 
1804  // notify observers about highlights changes
1805  foreach(int pageNumber, *pagesToNotify)
1806  foreach(DocumentObserver *observer, m_observers)
1807  observer->notifyPageChanged( pageNumber, DocumentObserver::Highlights );
1808 
1809  if (foundAMatch) emit m_parent->searchFinished(searchID, Document::MatchFound );
1810  else emit m_parent->searchFinished( searchID, Document::NoMatchFound );
1811 
1812  delete pageMatches;
1813  delete pagesToNotify;
1814  }
1815 }
1816 
1817 void DocumentPrivate::doContinueGooglesDocumentSearch(void *pagesToNotifySet, void *pageMatchesMap, int currentPage, int searchID, const QStringList & words, int theCaseSensitivity, const QColor & color, bool matchAll)
1818 {
1819  typedef QPair<RegularAreaRect *, QColor> MatchColor;
1820  QMap< Page *, QVector<MatchColor> > *pageMatches = static_cast< QMap< Page *, QVector<MatchColor> > * >(pageMatchesMap);
1821  Qt::CaseSensitivity caseSensitivity = static_cast<Qt::CaseSensitivity>(theCaseSensitivity);
1822  QSet< int > *pagesToNotify = static_cast< QSet< int > * >( pagesToNotifySet );
1823  RunningSearch *search = m_searches.value(searchID);
1824 
1825  if (m_searchCancelled || !search)
1826  {
1827  typedef QVector<MatchColor> MatchesVector;
1828 
1829  QApplication::restoreOverrideCursor();
1830 
1831  if (search) search->isCurrentlySearching = false;
1832 
1833  emit m_parent->searchFinished( searchID, Document::SearchCancelled );
1834 
1835  foreach(const MatchesVector &mv, *pageMatches)
1836  {
1837  foreach(const MatchColor &mc, mv) delete mc.first;
1838  }
1839  delete pageMatches;
1840  delete pagesToNotify;
1841  return;
1842  }
1843 
1844  const int wordCount = words.count();
1845  const int hueStep = (wordCount > 1) ? (60 / (wordCount - 1)) : 60;
1846  int baseHue, baseSat, baseVal;
1847  color.getHsv( &baseHue, &baseSat, &baseVal );
1848 
1849  if (currentPage < m_pagesVector.count())
1850  {
1851  // get page (from the first to the last)
1852  Page *page = m_pagesVector.at(currentPage);
1853  int pageNumber = page->number(); // redundant? is it == currentPage ?
1854 
1855  // request search page if needed
1856  if ( !page->hasTextPage() )
1857  m_parent->requestTextPage( pageNumber );
1858 
1859  // loop on a page adding highlights for all found items
1860  bool allMatched = wordCount > 0,
1861  anyMatched = false;
1862  for ( int w = 0; w < wordCount; w++ )
1863  {
1864  const QString &word = words[ w ];
1865  int newHue = baseHue - w * hueStep;
1866  if ( newHue < 0 )
1867  newHue += 360;
1868  QColor wordColor = QColor::fromHsv( newHue, baseSat, baseVal );
1869  RegularAreaRect * lastMatch = 0;
1870  // add all highlights for current word
1871  bool wordMatched = false;
1872  while ( 1 )
1873  {
1874  if ( lastMatch )
1875  lastMatch = page->findText( searchID, word, NextResult, caseSensitivity, lastMatch );
1876  else
1877  lastMatch = page->findText( searchID, word, FromTop, caseSensitivity);
1878 
1879  if ( !lastMatch )
1880  break;
1881 
1882  // add highligh rect to the matches map
1883  (*pageMatches)[page].append(MatchColor(lastMatch, wordColor));
1884  wordMatched = true;
1885  }
1886  allMatched = allMatched && wordMatched;
1887  anyMatched = anyMatched || wordMatched;
1888  }
1889 
1890  // if not all words are present in page, remove partial highlights
1891  if ( !allMatched && matchAll )
1892  {
1893  QVector<MatchColor> &matches = (*pageMatches)[page];
1894  foreach(const MatchColor &mc, matches) delete mc.first;
1895  pageMatches->remove(page);
1896  }
1897 
1898  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));
1899  }
1900  else
1901  {
1902  // reset cursor to previous shape
1903  QApplication::restoreOverrideCursor();
1904 
1905  search->isCurrentlySearching = false;
1906  bool foundAMatch = pageMatches->count() != 0;
1907  QMap< Page *, QVector<MatchColor> >::const_iterator it, itEnd;
1908  it = pageMatches->constBegin();
1909  itEnd = pageMatches->constEnd();
1910  for ( ; it != itEnd; ++it)
1911  {
1912  foreach(const MatchColor &mc, it.value())
1913  {
1914  it.key()->d->setHighlight( searchID, mc.first, mc.second );
1915  delete mc.first;
1916  }
1917  search->highlightedPages.insert( it.key()->number() );
1918  pagesToNotify->insert( it.key()->number() );
1919  }
1920 
1921  // send page lists to update observers (since some filter on bookmarks)
1922  foreach(DocumentObserver *observer, m_observers)
1923  observer->notifySetup( m_pagesVector, 0 );
1924 
1925  // notify observers about highlights changes
1926  foreach(int pageNumber, *pagesToNotify)
1927  foreach(DocumentObserver *observer, m_observers)
1928  observer->notifyPageChanged( pageNumber, DocumentObserver::Highlights );
1929 
1930  if (foundAMatch) emit m_parent->searchFinished( searchID, Document::MatchFound );
1931  else emit m_parent->searchFinished( searchID, Document::NoMatchFound );
1932 
1933  delete pageMatches;
1934  delete pagesToNotify;
1935  }
1936 }
1937 
1938 QVariant DocumentPrivate::documentMetaData( const QString &key, const QVariant &option ) const
1939 {
1940  if ( key == QLatin1String( "PaperColor" ) )
1941  {
1942  bool giveDefault = option.toBool();
1943  // load paper color from Settings, or use the default color (white)
1944  // if we were told to do so
1945  QColor color;
1946  if ( ( SettingsCore::renderMode() == SettingsCore::EnumRenderMode::Paper )
1947  && SettingsCore::changeColors() )
1948  {
1949  color = SettingsCore::paperColor();
1950  }
1951  else if ( giveDefault )
1952  {
1953  color = Qt::white;
1954  }
1955  return color;
1956  }
1957  else if ( key == QLatin1String( "TextAntialias" ) )
1958  {
1959  switch ( SettingsCore::textAntialias() )
1960  {
1961  case SettingsCore::EnumTextAntialias::Enabled:
1962  return true;
1963  break;
1964 #if 0
1965  case Settings::EnumTextAntialias::UseKDESettings:
1966  // TODO: read the KDE configuration
1967  return true;
1968  break;
1969 #endif
1970  case SettingsCore::EnumTextAntialias::Disabled:
1971  return false;
1972  break;
1973  }
1974  }
1975  else if ( key == QLatin1String( "GraphicsAntialias" ) )
1976  {
1977  switch ( SettingsCore::graphicsAntialias() )
1978  {
1979  case SettingsCore::EnumGraphicsAntialias::Enabled:
1980  return true;
1981  break;
1982  case SettingsCore::EnumGraphicsAntialias::Disabled:
1983  return false;
1984  break;
1985  }
1986  }
1987  else if ( key == QLatin1String( "TextHinting" ) )
1988  {
1989  switch ( SettingsCore::textHinting() )
1990  {
1991  case SettingsCore::EnumTextHinting::Enabled:
1992  return true;
1993  break;
1994  case SettingsCore::EnumTextHinting::Disabled:
1995  return false;
1996  break;
1997  }
1998  }
1999  return QVariant();
2000 };
2001 
2002 Document::Document( QWidget *widget )
2003  : QObject( 0 ), d( new DocumentPrivate( this ) )
2004 {
2005  d->m_widget = widget;
2006  d->m_bookmarkManager = new BookmarkManager( d );
2007  d->m_viewportIterator = d->m_viewportHistory.insert( d->m_viewportHistory.end(), DocumentViewport() );
2008  d->m_undoStack = new QUndoStack(this);
2009  d->m_tiledObserver = 0;
2010 
2011  connect( SettingsCore::self(), SIGNAL(configChanged()), this, SLOT(_o_configChanged()) );
2012  connect( d->m_undoStack, SIGNAL( canUndoChanged(bool) ), this, SIGNAL( canUndoChanged(bool)));
2013  connect( d->m_undoStack, SIGNAL( canRedoChanged(bool) ), this, SIGNAL( canRedoChanged(bool) ) );
2014 
2015  qRegisterMetaType<Okular::FontInfo>();
2016 }
2017 
2018 Document::~Document()
2019 {
2020  // delete generator, pages, and related stuff
2021  closeDocument();
2022 
2023  QSet< View * >::const_iterator viewIt = d->m_views.constBegin(), viewEnd = d->m_views.constEnd();
2024  for ( ; viewIt != viewEnd; ++viewIt )
2025  {
2026  View *v = *viewIt;
2027  v->d_func()->document = 0;
2028  }
2029 
2030  // delete the bookmark manager
2031  delete d->m_bookmarkManager;
2032 
2033  // delete the loaded generators
2034  QHash< QString, GeneratorInfo >::const_iterator it = d->m_loadedGenerators.constBegin(), itEnd = d->m_loadedGenerators.constEnd();
2035  for ( ; it != itEnd; ++it )
2036  d->unloadGenerator( it.value() );
2037  d->m_loadedGenerators.clear();
2038 
2039  // delete the private structure
2040  delete d;
2041 }
2042 
2043 class kMimeTypeMoreThan {
2044 public:
2045  kMimeTypeMoreThan( const KMimeType::Ptr &mime ) : _mime( mime ) {}
2046  bool operator()( const KService::Ptr &s1, const KService::Ptr &s2 )
2047  {
2048  const QString mimeName = _mime->name();
2049  if (s1->mimeTypes().contains( mimeName ) && !s2->mimeTypes().contains( mimeName ))
2050  return true;
2051  else if (s2->mimeTypes().contains( mimeName ) && !s1->mimeTypes().contains( mimeName ))
2052  return false;
2053  return s1->property( "X-KDE-Priority" ).toInt() > s2->property( "X-KDE-Priority" ).toInt();
2054  }
2055 
2056 private:
2057  const KMimeType::Ptr &_mime;
2058 };
2059 
2060 bool Document::openDocument( const QString & docFile, const KUrl& url, const KMimeType::Ptr &_mime )
2061 {
2062  KMimeType::Ptr mime = _mime;
2063  QByteArray filedata;
2064  qint64 document_size = -1;
2065  bool isstdin = url.fileName( KUrl::ObeyTrailingSlash ) == QLatin1String( "-" );
2066  bool triedMimeFromFileContent = false;
2067  if ( !isstdin )
2068  {
2069  if ( mime.count() <= 0 )
2070  return false;
2071 
2072  // docFile is always local so we can use QFileInfo on it
2073  QFileInfo fileReadTest( docFile );
2074  if ( fileReadTest.isFile() && !fileReadTest.isReadable() )
2075  {
2076  d->m_docFileName.clear();
2077  return false;
2078  }
2079  // determine the related "xml document-info" filename
2080  d->m_url = url;
2081  d->m_docFileName = docFile;
2082  if ( url.isLocalFile() && !d->m_archiveData )
2083  {
2084  QString fn = url.fileName();
2085  document_size = fileReadTest.size();
2086  fn = QString::number( document_size ) + '.' + fn + ".xml";
2087  QString newokular = "okular/docdata/" + fn;
2088  QString newokularfile = KStandardDirs::locateLocal( "data", newokular );
2089  if ( !QFile::exists( newokularfile ) )
2090  {
2091  QString oldkpdf = "kpdf/" + fn;
2092  QString oldkpdffile = KStandardDirs::locateLocal( "data", oldkpdf );
2093  if ( QFile::exists( oldkpdffile ) )
2094  {
2095  // ### copy or move?
2096  if ( !QFile::copy( oldkpdffile, newokularfile ) )
2097  return false;
2098  }
2099  }
2100  d->m_xmlFileName = newokularfile;
2101  }
2102  }
2103  else
2104  {
2105  QFile qstdin;
2106  qstdin.open( stdin, QIODevice::ReadOnly );
2107  filedata = qstdin.readAll();
2108  mime = KMimeType::findByContent( filedata );
2109  if ( !mime || mime->name() == QLatin1String( "application/octet-stream" ) )
2110  return false;
2111  document_size = filedata.size();
2112  triedMimeFromFileContent = true;
2113  }
2114 
2115  // 0. load Generator
2116  // request only valid non-disabled plugins suitable for the mimetype
2117  QString constraint("([X-KDE-Priority] > 0) and (exist Library)") ;
2118  KService::List offers = KMimeTypeTrader::self()->query(mime->name(),"okular/Generator",constraint);
2119  if ( offers.isEmpty() && !triedMimeFromFileContent )
2120  {
2121  KMimeType::Ptr newmime = KMimeType::findByFileContent( docFile );
2122  triedMimeFromFileContent = true;
2123  if ( newmime->name() != mime->name() )
2124  {
2125  mime = newmime;
2126  offers = KMimeTypeTrader::self()->query( mime->name(), "okular/Generator", constraint );
2127  }
2128  if ( offers.isEmpty() )
2129  {
2130  // There's still no offers, do a final mime search based on the filename
2131  // We need this because sometimes (e.g. when downloading from a webserver) the mimetype we
2132  // use is the one fed by the server, that may be wrong
2133  newmime = KMimeType::findByUrl( docFile );
2134  if ( newmime->name() != mime->name() )
2135  {
2136  mime = newmime;
2137  offers = KMimeTypeTrader::self()->query( mime->name(), "okular/Generator", constraint );
2138  }
2139  }
2140  }
2141  if (offers.isEmpty())
2142  {
2143  emit error( i18n( "Can not find a plugin which is able to handle the document being passed." ), -1 );
2144  kWarning(OkularDebug).nospace() << "No plugin for mimetype '" << mime->name() << "'.";
2145  return false;
2146  }
2147  int hRank=0;
2148  // best ranked offer search
2149  int offercount = offers.count();
2150  if ( offercount > 1 )
2151  {
2152  // sort the offers: the offers with an higher priority come before
2153  qStableSort( offers.begin(), offers.end(), kMimeTypeMoreThan( mime ) );
2154 
2155  if ( SettingsCore::chooseGenerators() )
2156  {
2157  QStringList list;
2158  for ( int i = 0; i < offercount; ++i )
2159  {
2160  list << offers.at(i)->name();
2161  }
2162 
2163  ChooseEngineDialog choose( list, mime, widget() );
2164 
2165  if ( choose.exec() == QDialog::Rejected )
2166  return false;
2167 
2168  hRank = choose.selectedGenerator();
2169  }
2170  }
2171 
2172  KService::Ptr offer = offers.at( hRank );
2173  // 1. load Document
2174  bool openOk = d->openDocumentInternal( offer, isstdin, docFile, filedata );
2175  if ( !openOk && !triedMimeFromFileContent )
2176  {
2177  KMimeType::Ptr newmime = KMimeType::findByFileContent( docFile );
2178  triedMimeFromFileContent = true;
2179  if ( newmime->name() != mime->name() )
2180  {
2181  mime = newmime;
2182  offers = KMimeTypeTrader::self()->query( mime->name(), "okular/Generator", constraint );
2183  if ( !offers.isEmpty() )
2184  {
2185  offer = offers.first();
2186  openOk = d->openDocumentInternal( offer, isstdin, docFile, filedata );
2187  }
2188  }
2189  }
2190  if ( !openOk )
2191  {
2192  return false;
2193  }
2194 
2195  d->m_generatorName = offer->name();
2196  d->m_pageController = new PageController();
2197  connect( d->m_pageController, SIGNAL(rotationFinished(int,Okular::Page*)),
2198  this, SLOT(rotationFinished(int,Okular::Page*)) );
2199 
2200  bool containsExternalAnnotations = false;
2201  foreach ( Page * p, d->m_pagesVector )
2202  {
2203  p->d->m_doc = d;
2204  if ( !p->annotations().empty() )
2205  containsExternalAnnotations = true;
2206  }
2207 
2208  // Be quiet while restoring local annotations
2209  d->m_showWarningLimitedAnnotSupport = false;
2210  d->m_annotationsNeedSaveAs = false;
2211 
2212  // 2. load Additional Data (bookmarks, local annotations and metadata) about the document
2213  if ( d->m_archiveData )
2214  {
2215  d->loadDocumentInfo( d->m_archiveData->metadataFileName );
2216  d->m_annotationsNeedSaveAs = true;
2217  }
2218  else
2219  {
2220  d->loadDocumentInfo();
2221  d->m_annotationsNeedSaveAs = ( d->canAddAnnotationsNatively() && containsExternalAnnotations );
2222  }
2223 
2224  d->m_showWarningLimitedAnnotSupport = true;
2225  d->m_bookmarkManager->setUrl( d->m_url );
2226 
2227  // 3. setup observers inernal lists and data
2228  foreachObserver( notifySetup( d->m_pagesVector, DocumentObserver::DocumentChanged ) );
2229 
2230  // 4. set initial page (restoring the page saved in xml if loaded)
2231  DocumentViewport loadedViewport = (*d->m_viewportIterator);
2232  if ( loadedViewport.isValid() )
2233  {
2234  (*d->m_viewportIterator) = DocumentViewport();
2235  if ( loadedViewport.pageNumber >= (int)d->m_pagesVector.size() )
2236  loadedViewport.pageNumber = d->m_pagesVector.size() - 1;
2237  }
2238  else
2239  loadedViewport.pageNumber = 0;
2240  setViewport( loadedViewport );
2241 
2242  // start bookmark saver timer
2243  if ( !d->m_saveBookmarksTimer )
2244  {
2245  d->m_saveBookmarksTimer = new QTimer( this );
2246  connect( d->m_saveBookmarksTimer, SIGNAL(timeout()), this, SLOT(saveDocumentInfo()) );
2247  }
2248  d->m_saveBookmarksTimer->start( 5 * 60 * 1000 );
2249 
2250  // start memory check timer
2251  if ( !d->m_memCheckTimer )
2252  {
2253  d->m_memCheckTimer = new QTimer( this );
2254  connect( d->m_memCheckTimer, SIGNAL(timeout()), this, SLOT(slotTimedMemoryCheck()) );
2255  }
2256  d->m_memCheckTimer->start( 2000 );
2257 
2258  const DocumentViewport nextViewport = d->nextDocumentViewport();
2259  if ( nextViewport.isValid() )
2260  {
2261  setViewport( nextViewport );
2262  d->m_nextDocumentViewport = DocumentViewport();
2263  d->m_nextDocumentDestination = QString();
2264  }
2265 
2266  AudioPlayer::instance()->d->m_currentDocument = isstdin ? KUrl() : d->m_url;
2267  d->m_docSize = document_size;
2268 
2269  const QStringList docScripts = d->m_generator->metaData( "DocumentScripts", "JavaScript" ).toStringList();
2270  if ( !docScripts.isEmpty() )
2271  {
2272  d->m_scripter = new Scripter( d );
2273  Q_FOREACH ( const QString &docscript, docScripts )
2274  {
2275  d->m_scripter->execute( JavaScript, docscript );
2276  }
2277  }
2278 
2279  return true;
2280 }
2281 
2282 
2283 KXMLGUIClient* Document::guiClient()
2284 {
2285  if ( d->m_generator )
2286  {
2287  Okular::GuiInterface * iface = qobject_cast< Okular::GuiInterface * >( d->m_generator );
2288  if ( iface )
2289  return iface->guiClient();
2290  }
2291  return 0;
2292 }
2293 
2294 void Document::closeDocument()
2295 {
2296  // check if there's anything to close...
2297  if ( !d->m_generator )
2298  return;
2299 
2300  delete d->m_pageController;
2301  d->m_pageController = 0;
2302 
2303  delete d->m_scripter;
2304  d->m_scripter = 0;
2305 
2306  // remove requests left in queue
2307  d->m_pixmapRequestsMutex.lock();
2308  QLinkedList< PixmapRequest * >::const_iterator sIt = d->m_pixmapRequestsStack.constBegin();
2309  QLinkedList< PixmapRequest * >::const_iterator sEnd = d->m_pixmapRequestsStack.constEnd();
2310  for ( ; sIt != sEnd; ++sIt )
2311  delete *sIt;
2312  d->m_pixmapRequestsStack.clear();
2313  d->m_pixmapRequestsMutex.unlock();
2314 
2315  QEventLoop loop;
2316  bool startEventLoop = false;
2317  do
2318  {
2319  d->m_pixmapRequestsMutex.lock();
2320  startEventLoop = !d->m_executingPixmapRequests.isEmpty();
2321  d->m_pixmapRequestsMutex.unlock();
2322  if ( startEventLoop )
2323  {
2324  d->m_closingLoop = &loop;
2325  loop.exec();
2326  d->m_closingLoop = 0;
2327  }
2328  }
2329  while ( startEventLoop );
2330 
2331  if ( d->m_fontThread )
2332  {
2333  disconnect( d->m_fontThread, 0, this, 0 );
2334  d->m_fontThread->stopExtraction();
2335  d->m_fontThread->wait();
2336  d->m_fontThread = 0;
2337  }
2338 
2339  // stop any audio playback
2340  AudioPlayer::instance()->stopPlaybacks();
2341 
2342  // close the current document and save document info if a document is still opened
2343  if ( d->m_generator && d->m_pagesVector.size() > 0 )
2344  {
2345  d->saveDocumentInfo();
2346  d->m_generator->closeDocument();
2347  }
2348 
2349  // stop timers
2350  if ( d->m_memCheckTimer )
2351  d->m_memCheckTimer->stop();
2352  if ( d->m_saveBookmarksTimer )
2353  d->m_saveBookmarksTimer->stop();
2354 
2355  if ( d->m_generator )
2356  {
2357  // disconnect the generator from this document ...
2358  d->m_generator->d_func()->m_document = 0;
2359  // .. and this document from the generator signals
2360  disconnect( d->m_generator, 0, this, 0 );
2361 
2362  QHash< QString, GeneratorInfo >::const_iterator genIt = d->m_loadedGenerators.constFind( d->m_generatorName );
2363  Q_ASSERT( genIt != d->m_loadedGenerators.constEnd() );
2364  if ( !genIt.value().catalogName.isEmpty() && !genIt.value().config )
2365  KGlobal::locale()->removeCatalog( genIt.value().catalogName );
2366  }
2367  d->m_generator = 0;
2368  d->m_generatorName = QString();
2369  d->m_url = KUrl();
2370  d->m_docFileName = QString();
2371  d->m_xmlFileName = QString();
2372  delete d->m_tempFile;
2373  d->m_tempFile = 0;
2374  delete d->m_archiveData;
2375  d->m_archiveData = 0;
2376  d->m_docSize = -1;
2377  d->m_exportCached = false;
2378  d->m_exportFormats.clear();
2379  d->m_exportToText = ExportFormat();
2380  d->m_fontsCached = false;
2381  d->m_fontsCache.clear();
2382  d->m_rotation = Rotation0;
2383 
2384  // send an empty list to observers (to free their data)
2385  foreachObserver( notifySetup( QVector< Page * >(), DocumentObserver::DocumentChanged ) );
2386 
2387  // delete pages and clear 'd->m_pagesVector' container
2388  QVector< Page * >::const_iterator pIt = d->m_pagesVector.constBegin();
2389  QVector< Page * >::const_iterator pEnd = d->m_pagesVector.constEnd();
2390  for ( ; pIt != pEnd; ++pIt )
2391  delete *pIt;
2392  d->m_pagesVector.clear();
2393 
2394  // clear 'memory allocation' descriptors
2395  qDeleteAll( d->m_allocatedPixmaps );
2396  d->m_allocatedPixmaps.clear();
2397 
2398  // clear 'running searches' descriptors
2399  QMap< int, RunningSearch * >::const_iterator rIt = d->m_searches.constBegin();
2400  QMap< int, RunningSearch * >::const_iterator rEnd = d->m_searches.constEnd();
2401  for ( ; rIt != rEnd; ++rIt )
2402  delete *rIt;
2403  d->m_searches.clear();
2404 
2405  // clear the visible areas and notify the observers
2406  QVector< VisiblePageRect * >::const_iterator vIt = d->m_pageRects.constBegin();
2407  QVector< VisiblePageRect * >::const_iterator vEnd = d->m_pageRects.constEnd();
2408  for ( ; vIt != vEnd; ++vIt )
2409  delete *vIt;
2410  d->m_pageRects.clear();
2411  foreachObserver( notifyVisibleRectsChanged() );
2412 
2413  // reset internal variables
2414 
2415  d->m_viewportHistory.clear();
2416  d->m_viewportHistory.append( DocumentViewport() );
2417  d->m_viewportIterator = d->m_viewportHistory.begin();
2418  d->m_allocatedPixmapsTotalMemory = 0;
2419  d->m_allocatedTextPagesFifo.clear();
2420  d->m_pageSize = PageSize();
2421  d->m_pageSizes.clear();
2422 
2423  delete d->m_documentInfo;
2424  d->m_documentInfo = 0;
2425 
2426  AudioPlayer::instance()->d->m_currentDocument = KUrl();
2427 
2428  d->m_undoStack->clear();
2429 }
2430 
2431 void Document::addObserver( DocumentObserver * pObserver )
2432 {
2433  Q_ASSERT( !d->m_observers.contains( pObserver ) );
2434  d->m_observers << pObserver;
2435 
2436  // if the observer is added while a document is already opened, tell it
2437  if ( !d->m_pagesVector.isEmpty() )
2438  {
2439  pObserver->notifySetup( d->m_pagesVector, DocumentObserver::DocumentChanged );
2440  pObserver->notifyViewportChanged( false /*disables smoothMove*/ );
2441  }
2442 }
2443 
2444 void Document::removeObserver( DocumentObserver * pObserver )
2445 {
2446  // remove observer from the map. it won't receive notifications anymore
2447  if ( d->m_observers.contains( pObserver ) )
2448  {
2449  // free observer's pixmap data
2450  QVector<Page*>::const_iterator it = d->m_pagesVector.constBegin(), end = d->m_pagesVector.constEnd();
2451  for ( ; it != end; ++it )
2452  (*it)->deletePixmap( pObserver );
2453 
2454  // [MEM] free observer's allocation descriptors
2455  QLinkedList< AllocatedPixmap * >::iterator aIt = d->m_allocatedPixmaps.begin();
2456  QLinkedList< AllocatedPixmap * >::iterator aEnd = d->m_allocatedPixmaps.end();
2457  while ( aIt != aEnd )
2458  {
2459  AllocatedPixmap * p = *aIt;
2460  if ( p->observer == pObserver )
2461  {
2462  aIt = d->m_allocatedPixmaps.erase( aIt );
2463  delete p;
2464  }
2465  else
2466  ++aIt;
2467  }
2468 
2469  // delete observer entry from the map
2470  d->m_observers.remove( pObserver );
2471  }
2472 }
2473 
2474 void Document::reparseConfig()
2475 {
2476  // reparse generator config and if something changed clear Pages
2477  bool configchanged = false;
2478  if ( d->m_generator )
2479  {
2480  Okular::ConfigInterface * iface = qobject_cast< Okular::ConfigInterface * >( d->m_generator );
2481  if ( iface )
2482  configchanged = iface->reparseConfig();
2483  }
2484  if ( configchanged )
2485  {
2486  // invalidate pixmaps
2487  QVector<Page*>::const_iterator it = d->m_pagesVector.constBegin(), end = d->m_pagesVector.constEnd();
2488  for ( ; it != end; ++it ) {
2489  (*it)->deletePixmaps();
2490  }
2491 
2492  // [MEM] remove allocation descriptors
2493  qDeleteAll( d->m_allocatedPixmaps );
2494  d->m_allocatedPixmaps.clear();
2495  d->m_allocatedPixmapsTotalMemory = 0;
2496 
2497  // send reload signals to observers
2498  foreachObserver( notifyContentsCleared( DocumentObserver::Pixmap ) );
2499  }
2500 
2501  // free memory if in 'low' profile
2502  if ( SettingsCore::memoryLevel() == SettingsCore::EnumMemoryLevel::Low &&
2503  !d->m_allocatedPixmaps.isEmpty() && !d->m_pagesVector.isEmpty() )
2504  d->cleanupPixmapMemory();
2505 }
2506 
2507 
2508 QWidget *Document::widget() const
2509 {
2510  return d->m_widget;
2511 }
2512 
2513 bool Document::isOpened() const
2514 {
2515  return d->m_generator;
2516 }
2517 
2518 bool Document::canConfigurePrinter( ) const
2519 {
2520  if ( d->m_generator )
2521  {
2522  Okular::PrintInterface * iface = qobject_cast< Okular::PrintInterface * >( d->m_generator );
2523  return iface ? true : false;
2524  }
2525  else
2526  return 0;
2527 }
2528 
2529 const DocumentInfo * Document::documentInfo() const
2530 {
2531  if ( d->m_documentInfo )
2532  return d->m_documentInfo;
2533 
2534  if ( d->m_generator )
2535  {
2536  DocumentInfo *info = new DocumentInfo();
2537  const DocumentInfo *tmp = d->m_generator->generateDocumentInfo();
2538  if ( tmp )
2539  *info = *tmp;
2540 
2541  info->set( DocumentInfo::FilePath, currentDocument().prettyUrl() );
2542  const QString pagesSize = d->pagesSizeString();
2543  if ( d->m_docSize != -1 )
2544  {
2545  const QString sizeString = KGlobal::locale()->formatByteSize( d->m_docSize );
2546  info->set( DocumentInfo::DocumentSize, sizeString );
2547  }
2548  if (!pagesSize.isEmpty())
2549  {
2550  info->set( DocumentInfo::PagesSize, pagesSize );
2551  }
2552 
2553  const DocumentInfo::Key keyPages = DocumentInfo::Pages;
2554  const QString keyString = DocumentInfo::getKeyString( keyPages );
2555 
2556  if ( info->get( keyString ).isEmpty() ) {
2557  info->set( keyString, QString::number( this->pages() ),
2558  DocumentInfo::getKeyTitle( keyPages ) );
2559  }
2560 
2561  d->m_documentInfo = info;
2562  return info;
2563  }
2564  else return NULL;
2565 }
2566 
2567 const DocumentSynopsis * Document::documentSynopsis() const
2568 {
2569  return d->m_generator ? d->m_generator->generateDocumentSynopsis() : NULL;
2570 }
2571 
2572 void Document::startFontReading()
2573 {
2574  if ( !d->m_generator || !d->m_generator->hasFeature( Generator::FontInfo ) || d->m_fontThread )
2575  return;
2576 
2577  if ( d->m_fontsCached )
2578  {
2579  // in case we have cached fonts, simulate a reading
2580  // this way the API is the same, and users no need to care about the
2581  // internal caching
2582  for ( int i = 0; i < d->m_fontsCache.count(); ++i )
2583  {
2584  emit gotFont( d->m_fontsCache.at( i ) );
2585  emit fontReadingProgress( i / pages() );
2586  }
2587  emit fontReadingEnded();
2588  return;
2589  }
2590 
2591  d->m_fontThread = new FontExtractionThread( d->m_generator, pages() );
2592  connect( d->m_fontThread, SIGNAL(gotFont(Okular::FontInfo)), this, SLOT(fontReadingGotFont(Okular::FontInfo)) );
2593  connect( d->m_fontThread, SIGNAL(progress(int)), this, SLOT(fontReadingProgress(int)) );
2594 
2595  d->m_fontThread->startExtraction( /*d->m_generator->hasFeature( Generator::Threaded )*/true );
2596 }
2597 
2598 void Document::stopFontReading()
2599 {
2600  if ( !d->m_fontThread )
2601  return;
2602 
2603  disconnect( d->m_fontThread, 0, this, 0 );
2604  d->m_fontThread->stopExtraction();
2605  d->m_fontThread = 0;
2606  d->m_fontsCache.clear();
2607 }
2608 
2609 bool Document::canProvideFontInformation() const
2610 {
2611  return d->m_generator ? d->m_generator->hasFeature( Generator::FontInfo ) : false;
2612 }
2613 
2614 const QList<EmbeddedFile*> *Document::embeddedFiles() const
2615 {
2616  return d->m_generator ? d->m_generator->embeddedFiles() : NULL;
2617 }
2618 
2619 const Page * Document::page( int n ) const
2620 {
2621  return ( n < d->m_pagesVector.count() ) ? d->m_pagesVector.at(n) : 0;
2622 }
2623 
2624 const DocumentViewport & Document::viewport() const
2625 {
2626  return (*d->m_viewportIterator);
2627 }
2628 
2629 const QVector< VisiblePageRect * > & Document::visiblePageRects() const
2630 {
2631  return d->m_pageRects;
2632 }
2633 
2634 void Document::setVisiblePageRects( const QVector< VisiblePageRect * > & visiblePageRects, DocumentObserver *excludeObserver )
2635 {
2636  QVector< VisiblePageRect * >::const_iterator vIt = d->m_pageRects.constBegin();
2637  QVector< VisiblePageRect * >::const_iterator vEnd = d->m_pageRects.constEnd();
2638  for ( ; vIt != vEnd; ++vIt )
2639  delete *vIt;
2640  d->m_pageRects = visiblePageRects;
2641  // notify change to all other (different from id) observers
2642  foreach(DocumentObserver *o, d->m_observers)
2643  if ( o != excludeObserver )
2644  o->notifyVisibleRectsChanged();
2645 }
2646 
2647 uint Document::currentPage() const
2648 {
2649  return (*d->m_viewportIterator).pageNumber;
2650 }
2651 
2652 uint Document::pages() const
2653 {
2654  return d->m_pagesVector.size();
2655 }
2656 
2657 KUrl Document::currentDocument() const
2658 {
2659  return d->m_url;
2660 }
2661 
2662 bool Document::isAllowed( Permission action ) const
2663 {
2664  if ( action == Okular::AllowNotes && !d->m_annotationEditingEnabled )
2665  return false;
2666 
2667 #if !OKULAR_FORCE_DRM
2668  if ( KAuthorized::authorize( "skip_drm" ) && !Okular::SettingsCore::obeyDRM() )
2669  return true;
2670 #endif
2671 
2672  return d->m_generator ? d->m_generator->isAllowed( action ) : false;
2673 }
2674 
2675 bool Document::supportsSearching() const
2676 {
2677  return d->m_generator ? d->m_generator->hasFeature( Generator::TextExtraction ) : false;
2678 }
2679 
2680 bool Document::supportsPageSizes() const
2681 {
2682  return d->m_generator ? d->m_generator->hasFeature( Generator::PageSizes ) : false;
2683 }
2684 
2685 bool Document::supportsTiles() const
2686 {
2687  return d->m_generator ? d->m_generator->hasFeature( Generator::TiledRendering ) : false;
2688 }
2689 
2690 PageSize::List Document::pageSizes() const
2691 {
2692  if ( d->m_generator )
2693  {
2694  if ( d->m_pageSizes.isEmpty() )
2695  d->m_pageSizes = d->m_generator->pageSizes();
2696  return d->m_pageSizes;
2697  }
2698  return PageSize::List();
2699 }
2700 
2701 bool Document::canExportToText() const
2702 {
2703  if ( !d->m_generator )
2704  return false;
2705 
2706  d->cacheExportFormats();
2707  return !d->m_exportToText.isNull();
2708 }
2709 
2710 bool Document::exportToText( const QString& fileName ) const
2711 {
2712  if ( !d->m_generator )
2713  return false;
2714 
2715  d->cacheExportFormats();
2716  if ( d->m_exportToText.isNull() )
2717  return false;
2718 
2719  return d->m_generator->exportTo( fileName, d->m_exportToText );
2720 }
2721 
2722 ExportFormat::List Document::exportFormats() const
2723 {
2724  if ( !d->m_generator )
2725  return ExportFormat::List();
2726 
2727  d->cacheExportFormats();
2728  return d->m_exportFormats;
2729 }
2730 
2731 bool Document::exportTo( const QString& fileName, const ExportFormat& format ) const
2732 {
2733  return d->m_generator ? d->m_generator->exportTo( fileName, format ) : false;
2734 }
2735 
2736 bool Document::historyAtBegin() const
2737 {
2738  return d->m_viewportIterator == d->m_viewportHistory.begin();
2739 }
2740 
2741 bool Document::historyAtEnd() const
2742 {
2743  return d->m_viewportIterator == --(d->m_viewportHistory.end());
2744 }
2745 
2746 QVariant Document::metaData( const QString & key, const QVariant & option ) const
2747 {
2748  return d->m_generator ? d->m_generator->metaData( key, option ) : QVariant();
2749 }
2750 
2751 Rotation Document::rotation() const
2752 {
2753  return d->m_rotation;
2754 }
2755 
2756 QSizeF Document::allPagesSize() const
2757 {
2758  bool allPagesSameSize = true;
2759  QSizeF size;
2760  for (int i = 0; allPagesSameSize && i < d->m_pagesVector.count(); ++i)
2761  {
2762  const Page *p = d->m_pagesVector.at(i);
2763  if (i == 0) size = QSizeF(p->width(), p->height());
2764  else
2765  {
2766  allPagesSameSize = (size == QSizeF(p->width(), p->height()));
2767  }
2768  }
2769  if (allPagesSameSize) return size;
2770  else return QSizeF();
2771 }
2772 
2773 QString Document::pageSizeString(int page) const
2774 {
2775  if (d->m_generator)
2776  {
2777  if (d->m_generator->pagesSizeMetric() != Generator::None)
2778  {
2779  const Page *p = d->m_pagesVector.at( page );
2780  return d->localizedSize(QSizeF(p->width(), p->height()));
2781  }
2782  }
2783  return QString();
2784 }
2785 
2786 void Document::requestPixmaps( const QLinkedList< PixmapRequest * > & requests )
2787 {
2788  requestPixmaps( requests, RemoveAllPrevious );
2789 }
2790 
2791 void Document::requestPixmaps( const QLinkedList< PixmapRequest * > & requests, PixmapRequestFlags reqOptions )
2792 {
2793  if ( requests.isEmpty() )
2794  return;
2795 
2796  if ( !d->m_generator || d->m_closingLoop )
2797  {
2798  // delete requests..
2799  QLinkedList< PixmapRequest * >::const_iterator rIt = requests.constBegin(), rEnd = requests.constEnd();
2800  for ( ; rIt != rEnd; ++rIt )
2801  delete *rIt;
2802  // ..and return
2803  return;
2804  }
2805 
2806  // 1. [CLEAN STACK] remove previous requests of requesterID
2807  // FIXME This assumes all requests come from the same observer, that is true atm but not enforced anywhere
2808  DocumentObserver *requesterObserver = requests.first()->observer();
2809  QSet< int > requestedPages;
2810  {
2811  QLinkedList< PixmapRequest * >::const_iterator rIt = requests.constBegin(), rEnd = requests.constEnd();
2812  for ( ; rIt != rEnd; ++rIt )
2813  requestedPages.insert( (*rIt)->pageNumber() );
2814  }
2815  const bool removeAllPrevious = reqOptions & RemoveAllPrevious;
2816  d->m_pixmapRequestsMutex.lock();
2817  QLinkedList< PixmapRequest * >::iterator sIt = d->m_pixmapRequestsStack.begin(), sEnd = d->m_pixmapRequestsStack.end();
2818  while ( sIt != sEnd )
2819  {
2820  if ( (*sIt)->observer() == requesterObserver
2821  && ( removeAllPrevious || requestedPages.contains( (*sIt)->pageNumber() ) ) )
2822  {
2823  // delete request and remove it from stack
2824  delete *sIt;
2825  sIt = d->m_pixmapRequestsStack.erase( sIt );
2826  }
2827  else
2828  ++sIt;
2829  }
2830 
2831  // 2. [ADD TO STACK] add requests to stack
2832  QLinkedList< PixmapRequest * >::const_iterator rIt = requests.constBegin(), rEnd = requests.constEnd();
2833  for ( ; rIt != rEnd; ++rIt )
2834  {
2835  // set the 'page field' (see PixmapRequest) and check if it is valid
2836  PixmapRequest * request = *rIt;
2837  kDebug(OkularDebug).nospace() << "request observer=" << request->observer() << " " <<request->width() << "x" << request->height() << "@" << request->pageNumber();
2838  if ( d->m_pagesVector.value( request->pageNumber() ) == 0 )
2839  {
2840  // skip requests referencing an invalid page (must not happen)
2841  delete request;
2842  continue;
2843  }
2844 
2845  request->d->mPage = d->m_pagesVector.value( request->pageNumber() );
2846 
2847  if ( request->isTile() )
2848  {
2849  // Change the current request rect so that only invalid tiles are
2850  // requested. Also make sure the rect is tile-aligned.
2851  NormalizedRect tilesRect;
2852  const QList<Tile> tiles = request->page()->d->tilesManager()->tilesAt( request->normalizedRect(), TilesManager::TerminalTile );
2853  QList<Tile>::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd();
2854  while ( tIt != tEnd )
2855  {
2856  const Tile &tile = *tIt;
2857  if ( !tile.isValid() )
2858  {
2859  if ( tilesRect.isNull() )
2860  tilesRect = tile.rect();
2861  else
2862  tilesRect |= tile.rect();
2863  }
2864 
2865  tIt++;
2866  }
2867 
2868  request->setNormalizedRect( tilesRect );
2869  }
2870 
2871  if ( !request->asynchronous() )
2872  request->d->mPriority = 0;
2873 
2874  // add request to the 'stack' at the right place
2875  if ( !request->priority() )
2876  // add priority zero requests to the top of the stack
2877  d->m_pixmapRequestsStack.append( request );
2878  else
2879  {
2880  // insert in stack sorted by priority
2881  sIt = d->m_pixmapRequestsStack.begin();
2882  sEnd = d->m_pixmapRequestsStack.end();
2883  while ( sIt != sEnd && (*sIt)->priority() > request->priority() )
2884  ++sIt;
2885  d->m_pixmapRequestsStack.insert( sIt, request );
2886  }
2887  }
2888  d->m_pixmapRequestsMutex.unlock();
2889 
2890  // 3. [START FIRST GENERATION] if <NO>generator is ready, start a new generation,
2891  // or else (if gen is running) it will be started when the new contents will
2892  //come from generator (in requestDone())</NO>
2893  // all handling of requests put into sendGeneratorPixmapRequest
2894  // if ( generator->canRequestPixmap() )
2895  d->sendGeneratorPixmapRequest();
2896 }
2897 
2898 void Document::requestTextPage( uint page )
2899 {
2900  Page * kp = d->m_pagesVector[ page ];
2901  if ( !d->m_generator || !kp )
2902  return;
2903 
2904  // Memory management for TextPages
2905 
2906  d->m_generator->generateTextPage( kp );
2907 }
2908 
2909 void DocumentPrivate::notifyAnnotationChanges( int page )
2910 {
2911  int flags = DocumentObserver::Annotations;
2912 
2913  if ( m_annotationsNeedSaveAs )
2914  flags |= DocumentObserver::NeedSaveAs;
2915 
2916  foreachObserverD( notifyPageChanged( page, flags ) );
2917 }
2918 
2919 void Document::addPageAnnotation( int page, Annotation * annotation )
2920 {
2921  // Transform annotation's base boundary rectangle into unrotated coordinates
2922  Page *p = d->m_pagesVector[page];
2923  QTransform t = p->d->rotationMatrix();
2924  annotation->d_ptr->baseTransform(t.inverted());
2925  QUndoCommand *uc = new AddAnnotationCommand(this->d, annotation, page);
2926  d->m_undoStack->push(uc);
2927 }
2928 
2929 bool Document::canModifyPageAnnotation( const Annotation * annotation ) const
2930 {
2931  if ( !annotation || ( annotation->flags() & Annotation::DenyWrite ) )
2932  return false;
2933 
2934  if ( !isAllowed(Okular::AllowNotes) )
2935  return false;
2936 
2937  if ( ( annotation->flags() & Annotation::External ) && !d->canModifyExternalAnnotations() )
2938  return false;
2939 
2940  switch ( annotation->subType() )
2941  {
2942  case Annotation::AText:
2943  case Annotation::ALine:
2944  case Annotation::AGeom:
2945  case Annotation::AHighlight:
2946  case Annotation::AStamp:
2947  case Annotation::AInk:
2948  return true;
2949  default:
2950  return false;
2951  }
2952 }
2953 
2954 void Document::prepareToModifyAnnotationProperties( Annotation * annotation )
2955 {
2956  Q_ASSERT(d->m_prevPropsOfAnnotBeingModified.isNull());
2957  if (!d->m_prevPropsOfAnnotBeingModified.isNull())
2958  {
2959  kError(OkularDebug) << "Error: Document::prepareToModifyAnnotationProperties has already been called since last call to Document::modifyPageAnnotationProperties";
2960  return;
2961  }
2962  d->m_prevPropsOfAnnotBeingModified = annotation->getAnnotationPropertiesDomNode();
2963 }
2964 
2965 void Document::modifyPageAnnotationProperties( int page, Annotation * annotation )
2966 {
2967  Q_ASSERT(!d->m_prevPropsOfAnnotBeingModified.isNull());
2968  if (d->m_prevPropsOfAnnotBeingModified.isNull())
2969  {
2970  kError(OkularDebug) << "Error: Document::prepareToModifyAnnotationProperties must be called before Annotation is modified";
2971  return;
2972  }
2973  QDomNode prevProps = d->m_prevPropsOfAnnotBeingModified;
2974  QUndoCommand *uc = new Okular::ModifyAnnotationPropertiesCommand( d,
2975  annotation,
2976  page,
2977  prevProps,
2978  annotation->getAnnotationPropertiesDomNode() );
2979  d->m_undoStack->push( uc );
2980  d->m_prevPropsOfAnnotBeingModified.clear();
2981 }
2982 
2983 void Document::translatePageAnnotation(int page, Annotation* annotation, const NormalizedPoint & delta )
2984 {
2985  int complete = (annotation->flags() & Okular::Annotation::BeingMoved) == 0;
2986  QUndoCommand *uc = new Okular::TranslateAnnotationCommand( d, annotation, page, delta, complete );
2987  d->m_undoStack->push(uc);
2988 }
2989 
2990 void Document::editPageAnnotationContents( int page, Annotation* annotation,
2991  const QString & newContents,
2992  int newCursorPos,
2993  int prevCursorPos,
2994  int prevAnchorPos
2995  )
2996 {
2997  QString prevContents = annotation->contents();
2998  QUndoCommand *uc = new EditAnnotationContentsCommand( d, annotation, page, newContents, newCursorPos,
2999  prevContents, prevCursorPos, prevAnchorPos );
3000  d->m_undoStack->push( uc );
3001 }
3002 
3003 bool Document::canRemovePageAnnotation( const Annotation * annotation ) const
3004 {
3005  if ( !annotation || ( annotation->flags() & Annotation::DenyDelete ) )
3006  return false;
3007 
3008  if ( ( annotation->flags() & Annotation::External ) && !d->canRemoveExternalAnnotations() )
3009  return false;
3010 
3011  switch ( annotation->subType() )
3012  {
3013  case Annotation::AText:
3014  case Annotation::ALine:
3015  case Annotation::AGeom:
3016  case Annotation::AHighlight:
3017  case Annotation::AStamp:
3018  case Annotation::AInk:
3019  return true;
3020  default:
3021  return false;
3022  }
3023 }
3024 
3025 void Document::removePageAnnotation( int page, Annotation * annotation )
3026 {
3027  QUndoCommand *uc = new RemoveAnnotationCommand(this->d, annotation, page);
3028  d->m_undoStack->push(uc);
3029 }
3030 
3031 void Document::removePageAnnotations( int page, const QList<Annotation*> &annotations )
3032 {
3033  d->m_undoStack->beginMacro(i18nc("remove a collection of annotations from the page", "remove annotations"));
3034  foreach(Annotation* annotation, annotations)
3035  {
3036  QUndoCommand *uc = new RemoveAnnotationCommand(this->d, annotation, page);
3037  d->m_undoStack->push(uc);
3038  }
3039  d->m_undoStack->endMacro();
3040 }
3041 
3042 bool DocumentPrivate::canAddAnnotationsNatively() const
3043 {
3044  Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
3045 
3046  if ( iface && iface->supportsOption(Okular::SaveInterface::SaveChanges) &&
3047  iface->annotationProxy() && iface->annotationProxy()->supports(AnnotationProxy::Addition) )
3048  return true;
3049 
3050  return false;
3051 }
3052 
3053 bool DocumentPrivate::canModifyExternalAnnotations() const
3054 {
3055  Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
3056 
3057  if ( iface && iface->supportsOption(Okular::SaveInterface::SaveChanges) &&
3058  iface->annotationProxy() && iface->annotationProxy()->supports(AnnotationProxy::Modification) )
3059  return true;
3060 
3061  return false;
3062 }
3063 
3064 bool DocumentPrivate::canRemoveExternalAnnotations() const
3065 {
3066  Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
3067 
3068  if ( iface && iface->supportsOption(Okular::SaveInterface::SaveChanges) &&
3069  iface->annotationProxy() && iface->annotationProxy()->supports(AnnotationProxy::Removal) )
3070  return true;
3071 
3072  return false;
3073 }
3074 
3075 void Document::setPageTextSelection( int page, RegularAreaRect * rect, const QColor & color )
3076 {
3077  Page * kp = d->m_pagesVector[ page ];
3078  if ( !d->m_generator || !kp )
3079  return;
3080 
3081  // add or remove the selection basing whether rect is null or not
3082  if ( rect )
3083  kp->d->setTextSelections( rect, color );
3084  else
3085  kp->d->deleteTextSelections();
3086 
3087  // notify observers about the change
3088  foreachObserver( notifyPageChanged( page, DocumentObserver::TextSelection ) );
3089 }
3090 
3091 bool Document::canUndo() const
3092 {
3093  return d->m_undoStack->canUndo();
3094 }
3095 
3096 bool Document::canRedo() const
3097 {
3098  return d->m_undoStack->canRedo();
3099 }
3100 
3101 /* REFERENCE IMPLEMENTATION: better calling setViewport from other code
3102 void Document::setNextPage()
3103 {
3104  // advance page and set viewport on observers
3105  if ( (*d->m_viewportIterator).pageNumber < (int)d->m_pagesVector.count() - 1 )
3106  setViewport( DocumentViewport( (*d->m_viewportIterator).pageNumber + 1 ) );
3107 }
3108 
3109 void Document::setPrevPage()
3110 {
3111  // go to previous page and set viewport on observers
3112  if ( (*d->m_viewportIterator).pageNumber > 0 )
3113  setViewport( DocumentViewport( (*d->m_viewportIterator).pageNumber - 1 ) );
3114 }
3115 */
3116 void Document::setViewportPage( int page, DocumentObserver *excludeObserver, bool smoothMove )
3117 {
3118  // clamp page in range [0 ... numPages-1]
3119  if ( page < 0 )
3120  page = 0;
3121  else if ( page > (int)d->m_pagesVector.count() )
3122  page = d->m_pagesVector.count() - 1;
3123 
3124  // make a viewport from the page and broadcast it
3125  setViewport( DocumentViewport( page ), excludeObserver, smoothMove );
3126 }
3127 
3128 void Document::setViewport( const DocumentViewport & viewport, DocumentObserver *excludeObserver, bool smoothMove )
3129 {
3130  if ( !viewport.isValid() )
3131  {
3132  kDebug(OkularDebug) << "invalid viewport:" << viewport.toString();
3133  return;
3134  }
3135  if ( viewport.pageNumber >= int(d->m_pagesVector.count()) )
3136  {
3137  //kDebug(OkularDebug) << "viewport out of document:" << viewport.toString();
3138  return;
3139  }
3140 
3141  // if already broadcasted, don't redo it
3142  DocumentViewport & oldViewport = *d->m_viewportIterator;
3143  // disabled by enrico on 2005-03-18 (less debug output)
3144  //if ( viewport == oldViewport )
3145  // kDebug(OkularDebug) << "setViewport with the same viewport.";
3146 
3147  const int oldPageNumber = oldViewport.pageNumber;
3148 
3149  // set internal viewport taking care of history
3150  if ( oldViewport.pageNumber == viewport.pageNumber || !oldViewport.isValid() )
3151  {
3152  // if page is unchanged save the viewport at current position in queue
3153  oldViewport = viewport;
3154  }
3155  else
3156  {
3157  // remove elements after viewportIterator in queue
3158  d->m_viewportHistory.erase( ++d->m_viewportIterator, d->m_viewportHistory.end() );
3159 
3160  // keep the list to a reasonable size by removing head when needed
3161  if ( d->m_viewportHistory.count() >= OKULAR_HISTORY_MAXSTEPS )
3162  d->m_viewportHistory.pop_front();
3163 
3164  // add the item at the end of the queue
3165  d->m_viewportIterator = d->m_viewportHistory.insert( d->m_viewportHistory.end(), viewport );
3166  }
3167 
3168  const int currentViewportPage = (*d->m_viewportIterator).pageNumber;
3169 
3170  const bool currentPageChanged = (oldPageNumber != currentViewportPage);
3171 
3172  // notify change to all other (different from id) observers
3173  foreach(DocumentObserver *o, d->m_observers)
3174  {
3175  if ( o != excludeObserver )
3176  o->notifyViewportChanged( smoothMove );
3177 
3178  if ( currentPageChanged )
3179  o->notifyCurrentPageChanged( oldPageNumber, currentViewportPage );
3180  }
3181 }
3182 
3183 void Document::setZoom(int factor, DocumentObserver *excludeObserver)
3184 {
3185  // notify change to all other (different from id) observers
3186  foreach(DocumentObserver *o, d->m_observers)
3187  if (o != excludeObserver)
3188  o->notifyZoom( factor );
3189 }
3190 
3191 void Document::setPrevViewport()
3192 // restore viewport from the history
3193 {
3194  if ( d->m_viewportIterator != d->m_viewportHistory.begin() )
3195  {
3196  const int oldViewportPage = (*d->m_viewportIterator).pageNumber;
3197 
3198  // restore previous viewport and notify it to observers
3199  --d->m_viewportIterator;
3200  foreachObserver( notifyViewportChanged( true ) );
3201 
3202  const int currentViewportPage = (*d->m_viewportIterator).pageNumber;
3203  if (oldViewportPage != currentViewportPage)
3204  foreachObserver( notifyCurrentPageChanged( oldViewportPage, currentViewportPage ) );
3205  }
3206 }
3207 
3208 void Document::setNextViewport()
3209 // restore next viewport from the history
3210 {
3211  QLinkedList< DocumentViewport >::const_iterator nextIterator = d->m_viewportIterator;
3212  ++nextIterator;
3213  if ( nextIterator != d->m_viewportHistory.end() )
3214  {
3215  const int oldViewportPage = (*d->m_viewportIterator).pageNumber;
3216 
3217  // restore next viewport and notify it to observers
3218  ++d->m_viewportIterator;
3219  foreachObserver( notifyViewportChanged( true ) );
3220 
3221  const int currentViewportPage = (*d->m_viewportIterator).pageNumber;
3222  if (oldViewportPage != currentViewportPage)
3223  foreachObserver( notifyCurrentPageChanged( oldViewportPage, currentViewportPage ) );
3224  }
3225 }
3226 
3227 void Document::setNextDocumentViewport( const DocumentViewport & viewport )
3228 {
3229  d->m_nextDocumentViewport = viewport;
3230 }
3231 
3232 void Document::setNextDocumentDestination( const QString &namedDestination )
3233 {
3234  d->m_nextDocumentDestination = namedDestination;
3235 }
3236 
3237 void Document::searchText( int searchID, const QString & text, bool fromStart, Qt::CaseSensitivity caseSensitivity,
3238  SearchType type, bool moveViewport, const QColor & color, bool noDialogs )
3239 {
3240  d->m_searchCancelled = false;
3241 
3242  // safety checks: don't perform searches on empty or unsearchable docs
3243  if ( !d->m_generator || !d->m_generator->hasFeature( Generator::TextExtraction ) || d->m_pagesVector.isEmpty() )
3244  {
3245  emit searchFinished( searchID, NoMatchFound );
3246  return;
3247  }
3248 
3249  if ( !noDialogs )
3250  {
3251 #if 0
3252  KDialog *searchDialog = new KDialog(widget());
3253  searchDialog->setCaption( i18n("Search in progress...") );
3254  searchDialog->setButtons( KDialog::Cancel );
3255  QLabel *searchLabel = new QLabel(i18n("Searching for %1", text), searchDialog);
3256  searchDialog->setMainWidget( searchLabel );
3257 
3258  QTimer::singleShot(500, searchDialog, SLOT(show()));
3259  connect(this, SIGNAL(searchFinished(int,Okular::Document::SearchStatus)), searchDialog, SLOT(deleteLater()));
3260  connect(searchDialog, SIGNAL(finished()), this, SLOT(cancelSearch()));
3261 #endif
3262  }
3263 
3264  // if searchID search not recorded, create new descriptor and init params
3265  QMap< int, RunningSearch * >::iterator searchIt = d->m_searches.find( searchID );
3266  if ( searchIt == d->m_searches.end() )
3267  {
3268  RunningSearch * search = new RunningSearch();
3269  search->continueOnPage = -1;
3270  searchIt = d->m_searches.insert( searchID, search );
3271  }
3272  if (d->m_lastSearchID != searchID)
3273  {
3274  resetSearch(d->m_lastSearchID);
3275  }
3276  d->m_lastSearchID = searchID;
3277  RunningSearch * s = *searchIt;
3278 
3279  // update search structure
3280  bool newText = text != s->cachedString;
3281  s->cachedString = text;
3282  s->cachedType = type;
3283  s->cachedCaseSensitivity = caseSensitivity;
3284  s->cachedViewportMove = moveViewport;
3285  s->cachedNoDialogs = noDialogs;
3286  s->cachedColor = color;
3287  s->isCurrentlySearching = true;
3288 
3289  // global data for search
3290  QSet< int > *pagesToNotify = new QSet< int >;
3291 
3292  // remove highlights from pages and queue them for notifying changes
3293  *pagesToNotify += s->highlightedPages;
3294  foreach(int pageNumber, s->highlightedPages)
3295  d->m_pagesVector.at(pageNumber)->d->deleteHighlights( searchID );
3296  s->highlightedPages.clear();
3297 
3298  // set hourglass cursor
3299  QApplication::setOverrideCursor( Qt::WaitCursor );
3300 
3301  // 1. ALLDOC - proces all document marking pages
3302  if ( type == AllDocument )
3303  {
3304  QMap< Page *, QVector<RegularAreaRect *> > *pageMatches = new QMap< Page *, QVector<RegularAreaRect *> >;
3305 
3306  // search and highlight 'text' (as a solid phrase) on all pages
3307  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));
3308  }
3309  // 2. NEXTMATCH - find next matching item (or start from top)
3310  // 3. PREVMATCH - find previous matching item (or start from bottom)
3311  else if ( type == NextMatch || type == PreviousMatch )
3312  {
3313  // find out from where to start/resume search from
3314  const bool forward = type == NextMatch;
3315  const int viewportPage = (*d->m_viewportIterator).pageNumber;
3316  const int fromStartSearchPage = forward ? 0 : d->m_pagesVector.count() - 1;
3317  int currentPage = fromStart ? fromStartSearchPage : ((s->continueOnPage != -1) ? s->continueOnPage : viewportPage);
3318  Page * lastPage = fromStart ? 0 : d->m_pagesVector[ currentPage ];
3319  int pagesDone = 0;
3320 
3321  // continue checking last TextPage first (if it is the current page)
3322  RegularAreaRect * match = 0;
3323  if ( lastPage && lastPage->number() == s->continueOnPage )
3324  {
3325  if ( newText )
3326  match = lastPage->findText( searchID, text, forward ? FromTop : FromBottom, caseSensitivity );
3327  else
3328  match = lastPage->findText( searchID, text, forward ? NextResult : PreviousResult, caseSensitivity, &s->continueOnMatch );
3329  if ( !match )
3330  {
3331  if (forward) currentPage++;
3332  else currentPage--;
3333  pagesDone++;
3334  }
3335  }
3336 
3337  DoContinueDirectionMatchSearchStruct *searchStruct = new DoContinueDirectionMatchSearchStruct();
3338  searchStruct->forward = forward;
3339  searchStruct->pagesToNotify = pagesToNotify;
3340  searchStruct->match = match;
3341  searchStruct->currentPage = currentPage;
3342  searchStruct->searchID = searchID;
3343  searchStruct->text = text;
3344  searchStruct->caseSensitivity = caseSensitivity;
3345  searchStruct->moveViewport = moveViewport;
3346  searchStruct->color = color;
3347  searchStruct->noDialogs = noDialogs;
3348  searchStruct->pagesDone = pagesDone;
3349 
3350  QMetaObject::invokeMethod(this, "doContinueDirectionMatchSearch", Qt::QueuedConnection, Q_ARG(void *, searchStruct));
3351  }
3352  // 4. GOOGLE* - process all document marking pages
3353  else if ( type == GoogleAll || type == GoogleAny )
3354  {
3355  bool matchAll = type == GoogleAll;
3356 
3357  QMap< Page *, QVector< QPair<RegularAreaRect *, QColor> > > *pageMatches = new QMap< Page *, QVector<QPair<RegularAreaRect *, QColor> > >;
3358  const QStringList words = text.split( ' ', QString::SkipEmptyParts );
3359 
3360  // search and highlight every word in 'text' on all pages
3361  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));
3362  }
3363 }
3364 
3365 void Document::continueSearch( int searchID )
3366 {
3367  // check if searchID is present in runningSearches
3368  QMap< int, RunningSearch * >::const_iterator it = d->m_searches.constFind( searchID );
3369  if ( it == d->m_searches.constEnd() )
3370  {
3371  emit searchFinished( searchID, NoMatchFound );
3372  return;
3373  }
3374 
3375  // start search with cached parameters from last search by searchID
3376  RunningSearch * p = *it;
3377  if ( !p->isCurrentlySearching )
3378  searchText( searchID, p->cachedString, false, p->cachedCaseSensitivity,
3379  p->cachedType, p->cachedViewportMove, p->cachedColor,
3380  p->cachedNoDialogs );
3381 }
3382 
3383 void Document::continueSearch( int searchID, SearchType type )
3384 {
3385  // check if searchID is present in runningSearches
3386  QMap< int, RunningSearch * >::const_iterator it = d->m_searches.constFind( searchID );
3387  if ( it == d->m_searches.constEnd() )
3388  {
3389  emit searchFinished( searchID, NoMatchFound );
3390  return;
3391  }
3392 
3393  // start search with cached parameters from last search by searchID
3394  RunningSearch * p = *it;
3395  if ( !p->isCurrentlySearching )
3396  searchText( searchID, p->cachedString, false, p->cachedCaseSensitivity,
3397  type, p->cachedViewportMove, p->cachedColor,
3398  p->cachedNoDialogs );
3399 }
3400 
3401 void Document::resetSearch( int searchID )
3402 {
3403  // if we are closing down, don't bother doing anything
3404  if ( !d->m_generator )
3405  return;
3406 
3407  // check if searchID is present in runningSearches
3408  QMap< int, RunningSearch * >::iterator searchIt = d->m_searches.find( searchID );
3409  if ( searchIt == d->m_searches.end() )
3410  return;
3411 
3412  // get previous parameters for search
3413  RunningSearch * s = *searchIt;
3414 
3415  // unhighlight pages and inform observers about that
3416  foreach(int pageNumber, s->highlightedPages)
3417  {
3418  d->m_pagesVector.at(pageNumber)->d->deleteHighlights( searchID );
3419  foreachObserver( notifyPageChanged( pageNumber, DocumentObserver::Highlights ) );
3420  }
3421 
3422  // send the setup signal too (to update views that filter on matches)
3423  foreachObserver( notifySetup( d->m_pagesVector, 0 ) );
3424 
3425  // remove serch from the runningSearches list and delete it
3426  d->m_searches.erase( searchIt );
3427  delete s;
3428 }
3429 
3430 void Document::cancelSearch()
3431 {
3432  d->m_searchCancelled = true;
3433 }
3434 
3435 void Document::undo()
3436 {
3437  d->m_undoStack->undo();
3438 }
3439 
3440 void Document::redo()
3441 {
3442  d->m_undoStack->redo();
3443 }
3444 
3445 void Document::editFormText( int pageNumber,
3446  Okular::FormFieldText* form,
3447  const QString & newContents,
3448  int newCursorPos,
3449  int prevCursorPos,
3450  int prevAnchorPos )
3451 {
3452  QUndoCommand *uc = new EditFormTextCommand( this, form, pageNumber, newContents, newCursorPos, form->text(), prevCursorPos, prevAnchorPos );
3453  d->m_undoStack->push( uc );
3454 }
3455 
3456 void Document::editFormList( int pageNumber,
3457  FormFieldChoice* form,
3458  const QList< int > & newChoices )
3459 {
3460  const QList< int > prevChoices = form->currentChoices();
3461  QUndoCommand *uc = new EditFormListCommand( this, form, pageNumber, newChoices, prevChoices );
3462  d->m_undoStack->push( uc );
3463 }
3464 
3465 void Document::editFormCombo( int pageNumber,
3466  FormFieldChoice* form,
3467  const QString & newText,
3468  int newCursorPos,
3469  int prevCursorPos,
3470  int prevAnchorPos )
3471 {
3472 
3473  QString prevText;
3474  if ( form->currentChoices().isEmpty() )
3475  {
3476  prevText = form->editChoice();
3477  }
3478  else
3479  {
3480  prevText = form->choices()[form->currentChoices()[0]];
3481  }
3482 
3483  QUndoCommand *uc = new EditFormComboCommand( this, form, pageNumber, newText, newCursorPos, prevText, prevCursorPos, prevAnchorPos );
3484  d->m_undoStack->push( uc );
3485 }
3486 
3487 void Document::editFormButtons( int pageNumber, const QList< FormFieldButton* >& formButtons, const QList< bool >& newButtonStates )
3488 {
3489  QUndoCommand *uc = new EditFormButtonsCommand( this, pageNumber, formButtons, newButtonStates );
3490  d->m_undoStack->push( uc );
3491 }
3492 
3493 BookmarkManager * Document::bookmarkManager() const
3494 {
3495  return d->m_bookmarkManager;
3496 }
3497 
3498 QList<int> Document::bookmarkedPageList() const
3499 {
3500  QList<int> list;
3501  uint docPages = pages();
3502 
3503  //pages are 0-indexed internally, but 1-indexed externally
3504  for ( uint i = 0; i < docPages; i++ )
3505  {
3506  if ( bookmarkManager()->isBookmarked( i ) )
3507  {
3508  list << i + 1;
3509  }
3510  }
3511  return list;
3512 }
3513 
3514 QString Document::bookmarkedPageRange() const
3515 {
3516  // Code formerly in Part::slotPrint()
3517  // range detecting
3518  QString range;
3519  uint docPages = pages();
3520  int startId = -1;
3521  int endId = -1;
3522 
3523  for ( uint i = 0; i < docPages; ++i )
3524  {
3525  if ( bookmarkManager()->isBookmarked( i ) )
3526  {
3527  if ( startId < 0 )
3528  startId = i;
3529  if ( endId < 0 )
3530  endId = startId;
3531  else
3532  ++endId;
3533  }
3534  else if ( startId >= 0 && endId >= 0 )
3535  {
3536  if ( !range.isEmpty() )
3537  range += ',';
3538 
3539  if ( endId - startId > 0 )
3540  range += QString( "%1-%2" ).arg( startId + 1 ).arg( endId + 1 );
3541  else
3542  range += QString::number( startId + 1 );
3543  startId = -1;
3544  endId = -1;
3545  }
3546  }
3547  if ( startId >= 0 && endId >= 0 )
3548  {
3549  if ( !range.isEmpty() )
3550  range += ',';
3551 
3552  if ( endId - startId > 0 )
3553  range += QString( "%1-%2" ).arg( startId + 1 ).arg( endId + 1 );
3554  else
3555  range += QString::number( startId + 1 );
3556  }
3557  return range;
3558 }
3559 
3560 void Document::processAction( const Action * action )
3561 {
3562  if ( !action )
3563  return;
3564 
3565  switch( action->actionType() )
3566  {
3567  case Action::Goto: {
3568  const GotoAction * go = static_cast< const GotoAction * >( action );
3569  d->m_nextDocumentViewport = go->destViewport();
3570  d->m_nextDocumentDestination = go->destinationName();
3571 
3572  // Explanation of why d->m_nextDocumentViewport is needed:
3573  // all openRelativeFile does is launch a signal telling we
3574  // want to open another URL, the problem is that when the file is
3575  // non local, the loading is done assynchronously so you can't
3576  // do a setViewport after the if as it was because you are doing the setViewport
3577  // on the old file and when the new arrives there is no setViewport for it and
3578  // it does not show anything
3579 
3580  // first open filename if link is pointing outside this document
3581  if ( go->isExternal() && !d->openRelativeFile( go->fileName() ) )
3582  {
3583  kWarning(OkularDebug).nospace() << "Action: Error opening '" << go->fileName() << "'.";
3584  return;
3585  }
3586  else
3587  {
3588  const DocumentViewport nextViewport = d->nextDocumentViewport();
3589  // skip local links that point to nowhere (broken ones)
3590  if ( !nextViewport.isValid() )
3591  return;
3592 
3593  setViewport( nextViewport, 0, true );
3594  d->m_nextDocumentViewport = DocumentViewport();
3595  d->m_nextDocumentDestination = QString();
3596  }
3597 
3598  } break;
3599 
3600  case Action::Execute: {
3601  const ExecuteAction * exe = static_cast< const ExecuteAction * >( action );
3602  QString fileName = exe->fileName();
3603  if ( fileName.endsWith( ".pdf" ) || fileName.endsWith( ".PDF" ) )
3604  {
3605  d->openRelativeFile( fileName );
3606  return;
3607  }
3608 
3609  // Albert: the only pdf i have that has that kind of link don't define
3610  // an application and use the fileName as the file to open
3611  fileName = d->giveAbsolutePath( fileName );
3612  KMimeType::Ptr mime = KMimeType::findByPath( fileName );
3613  // Check executables
3614  if ( KRun::isExecutableFile( fileName, mime->name() ) )
3615  {
3616  // Don't have any pdf that uses this code path, just a guess on how it should work
3617  if ( !exe->parameters().isEmpty() )
3618  {
3619  fileName = d->giveAbsolutePath( exe->parameters() );
3620  mime = KMimeType::findByPath( fileName );
3621  if ( KRun::isExecutableFile( fileName, mime->name() ) )
3622  {
3623  // this case is a link pointing to an executable with a parameter
3624  // that also is an executable, possibly a hand-crafted pdf
3625  KMessageBox::information( widget(), i18n("The document is trying to execute an external application and, for your safety, Okular does not allow that.") );
3626  return;
3627  }
3628  }
3629  else
3630  {
3631  // this case is a link pointing to an executable with no parameters
3632  // core developers find unacceptable executing it even after asking the user
3633  KMessageBox::information( widget(), i18n("The document is trying to execute an external application and, for your safety, Okular does not allow that.") );
3634  return;
3635  }
3636  }
3637 
3638  KService::Ptr ptr = KMimeTypeTrader::self()->preferredService( mime->name(), "Application" );
3639  if ( ptr )
3640  {
3641  KUrl::List lst;
3642  lst.append( fileName );
3643  KRun::run( *ptr, lst, 0 );
3644  }
3645  else
3646  KMessageBox::information( widget(), i18n( "No application found for opening file of mimetype %1.", mime->name() ) );
3647  } break;
3648 
3649  case Action::DocAction: {
3650  const DocumentAction * docaction = static_cast< const DocumentAction * >( action );
3651  switch( docaction->documentActionType() )
3652  {
3653  case DocumentAction::PageFirst:
3654  setViewportPage( 0 );
3655  break;
3656  case DocumentAction::PagePrev:
3657  if ( (*d->m_viewportIterator).pageNumber > 0 )
3658  setViewportPage( (*d->m_viewportIterator).pageNumber - 1 );
3659  break;
3660  case DocumentAction::PageNext:
3661  if ( (*d->m_viewportIterator).pageNumber < (int)d->m_pagesVector.count() - 1 )
3662  setViewportPage( (*d->m_viewportIterator).pageNumber + 1 );
3663  break;
3664  case DocumentAction::PageLast:
3665  setViewportPage( d->m_pagesVector.count() - 1 );
3666  break;
3667  case DocumentAction::HistoryBack:
3668  setPrevViewport();
3669  break;
3670  case DocumentAction::HistoryForward:
3671  setNextViewport();
3672  break;
3673  case DocumentAction::Quit:
3674  emit quit();
3675  break;
3676  case DocumentAction::Presentation:
3677  emit linkPresentation();
3678  break;
3679  case DocumentAction::EndPresentation:
3680  emit linkEndPresentation();
3681  break;
3682  case DocumentAction::Find:
3683  emit linkFind();
3684  break;
3685  case DocumentAction::GoToPage:
3686  emit linkGoToPage();
3687  break;
3688  case DocumentAction::Close:
3689  emit close();
3690  break;
3691  }
3692  } break;
3693 
3694  case Action::Browse: {
3695  const BrowseAction * browse = static_cast< const BrowseAction * >( action );
3696  QString lilySource;
3697  int lilyRow = 0, lilyCol = 0;
3698  // if the url is a mailto one, invoke mailer
3699  if ( browse->url().startsWith( "mailto:", Qt::CaseInsensitive ) )
3700  KToolInvocation::invokeMailer( browse->url() );
3701  else if ( extractLilyPondSourceReference( browse->url(), &lilySource, &lilyRow, &lilyCol ) )
3702  {
3703  const SourceReference ref( lilySource, lilyRow, lilyCol );
3704  processSourceReference( &ref );
3705  }
3706  else
3707  {
3708  QString url = browse->url();
3709 
3710  // fix for #100366, documents with relative links that are the form of http:foo.pdf
3711  if (url.indexOf("http:") == 0 && url.indexOf("http://") == -1 && url.right(4) == ".pdf")
3712  {
3713  d->openRelativeFile(url.mid(5));
3714  return;
3715  }
3716 
3717  KUrl realUrl = KUrl( url );
3718 
3719  // handle documents with relative path
3720  if ( d->m_url.isValid() )
3721  {
3722  realUrl = KUrl( d->m_url.upUrl(), url );
3723  }
3724 
3725  // Albert: this is not a leak!
3726  new KRun( realUrl, widget() );
3727  }
3728  } break;
3729 
3730  case Action::Sound: {
3731  const SoundAction * linksound = static_cast< const SoundAction * >( action );
3732  AudioPlayer::instance()->playSound( linksound->sound(), linksound );
3733  } break;
3734 
3735  case Action::Script: {
3736  const ScriptAction * linkscript = static_cast< const ScriptAction * >( action );
3737  if ( !d->m_scripter )
3738  d->m_scripter = new Scripter( d );
3739  d->m_scripter->execute( linkscript->scriptType(), linkscript->script() );
3740  } break;
3741 
3742  case Action::Movie:
3743  emit processMovieAction( static_cast< const MovieAction * >( action ) );
3744  break;
3745  case Action::Rendition: {
3746  const RenditionAction * linkrendition = static_cast< const RenditionAction * >( action );
3747  if ( !linkrendition->script().isEmpty() )
3748  {
3749  if ( !d->m_scripter )
3750  d->m_scripter = new Scripter( d );
3751  d->m_scripter->execute( linkrendition->scriptType(), linkrendition->script() );
3752  }
3753  else
3754  {
3755  emit processRenditionAction( static_cast< const RenditionAction * >( action ) );
3756  }
3757  } break;
3758  }
3759 }
3760 
3761 void Document::processSourceReference( const SourceReference * ref )
3762 {
3763  if ( !ref )
3764  return;
3765 
3766  const KUrl url( d->giveAbsolutePath( ref->fileName() ) );
3767  if ( !url.isLocalFile() )
3768  {
3769  kDebug(OkularDebug) << url.url() << "is not a local file.";
3770  return;
3771  }
3772 
3773  const QString absFileName = url.toLocalFile();
3774  if ( !QFile::exists( absFileName ) )
3775  {
3776  kDebug(OkularDebug) << "No such file:" << absFileName;
3777  return;
3778  }
3779 
3780  bool handled = false;
3781  emit sourceReferenceActivated(absFileName, ref->row(), ref->column(), &handled);
3782  if(handled) {
3783  return;
3784  }
3785 
3786  static QHash< int, QString > editors;
3787  // init the editors table if empty (on first run, usually)
3788  if ( editors.isEmpty() )
3789  {
3790  editors = buildEditorsMap();
3791  }
3792 
3793  QHash< int, QString >::const_iterator it = editors.constFind( SettingsCore::externalEditor() );
3794  QString p;
3795  if ( it != editors.constEnd() )
3796  p = *it;
3797  else
3798  p = SettingsCore::externalEditorCommand();
3799  // custom editor not yet configured
3800  if ( p.isEmpty() )
3801  return;
3802 
3803  // manually append the %f placeholder if not specified
3804  if ( p.indexOf( QLatin1String( "%f" ) ) == -1 )
3805  p.append( QLatin1String( " %f" ) );
3806 
3807  // replacing the placeholders
3808  QHash< QChar, QString > map;
3809  map.insert( 'f', absFileName );
3810  map.insert( 'c', QString::number( ref->column() ) );
3811  map.insert( 'l', QString::number( ref->row() ) );
3812  const QString cmd = KMacroExpander::expandMacrosShellQuote( p, map );
3813  if ( cmd.isEmpty() )
3814  return;
3815  const QStringList args = KShell::splitArgs( cmd );
3816  if ( args.isEmpty() )
3817  return;
3818 
3819  KProcess::startDetached( args );
3820 }
3821 
3822 const SourceReference * Document::dynamicSourceReference( int pageNr, double absX, double absY )
3823 {
3824  const SourceReference * ref = 0;
3825  if ( d->m_generator )
3826  {
3827  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) );
3828  }
3829  return ref;
3830 }
3831 
3832 Document::PrintingType Document::printingSupport() const
3833 {
3834  if ( d->m_generator )
3835  {
3836 
3837  if ( d->m_generator->hasFeature( Generator::PrintNative ) )
3838  {
3839  return NativePrinting;
3840  }
3841 
3842 #ifndef Q_OS_WIN
3843  if ( d->m_generator->hasFeature( Generator::PrintPostscript ) )
3844  {
3845  return PostscriptPrinting;
3846  }
3847 #endif
3848 
3849  }
3850 
3851  return NoPrinting;
3852 }
3853 
3854 bool Document::supportsPrintToFile() const
3855 {
3856  return d->m_generator ? d->m_generator->hasFeature( Generator::PrintToFile ) : false;
3857 }
3858 
3859 bool Document::print( QPrinter &printer )
3860 {
3861  return d->m_generator ? d->m_generator->print( printer ) : false;
3862 }
3863 
3864 QString Document::printError() const
3865 {
3866  Okular::Generator::PrintError err = Generator::UnknownPrintError;
3867  if ( d->m_generator )
3868  {
3869  QMetaObject::invokeMethod( d->m_generator, "printError", Qt::DirectConnection, Q_RETURN_ARG(Okular::Generator::PrintError, err) );
3870  }
3871  Q_ASSERT( err != Generator::NoPrintError );
3872  switch ( err )
3873  {
3874  case Generator::TemporaryFileOpenPrintError:
3875  return i18n( "Could not open a temporary file" );
3876  case Generator::FileConversionPrintError:
3877  return i18n( "Print conversion failed" );
3878  case Generator::PrintingProcessCrashPrintError:
3879  return i18n( "Printing process crashed" );
3880  case Generator::PrintingProcessStartPrintError:
3881  return i18n( "Printing process could not start" );
3882  case Generator::PrintToFilePrintError:
3883  return i18n( "Printing to file failed" );
3884  case Generator::InvalidPrinterStatePrintError:
3885  return i18n( "Printer was in invalid state" );
3886  case Generator::UnableToFindFilePrintError:
3887  return i18n( "Unable to find file to print" );
3888  case Generator::NoFileToPrintError:
3889  return i18n( "There was no file to print" );
3890  case Generator::NoBinaryToPrintError:
3891  return i18n( "Could not find a suitable binary for printing. Make sure CUPS lpr binary is available" );
3892  case Generator::NoPrintError:
3893  return QString();
3894  case Generator::UnknownPrintError:
3895  return QString();
3896  }
3897 
3898  return QString();
3899 }
3900 
3901 QWidget* Document::printConfigurationWidget() const
3902 {
3903  if ( d->m_generator )
3904  {
3905  PrintInterface * iface = qobject_cast< Okular::PrintInterface * >( d->m_generator );
3906  return iface ? iface->printConfigurationWidget() : 0;
3907  }
3908  else
3909  return 0;
3910 }
3911 
3912 void Document::fillConfigDialog( KConfigDialog * dialog )
3913 {
3914  if ( !dialog )
3915  return;
3916 
3917  // ensure that we have all the generators with settings loaded
3918  QString constraint( "([X-KDE-Priority] > 0) and (exist Library) and ([X-KDE-okularHasInternalSettings])" );
3919  KService::List offers = KServiceTypeTrader::self()->query( "okular/Generator", constraint );
3920  d->loadServiceList( offers );
3921 
3922  bool pagesAdded = false;
3923  QHash< QString, GeneratorInfo >::iterator it = d->m_loadedGenerators.begin();
3924  QHash< QString, GeneratorInfo >::iterator itEnd = d->m_loadedGenerators.end();
3925  for ( ; it != itEnd; ++it )
3926  {
3927  Okular::ConfigInterface * iface = d->generatorConfig( it.value() );
3928  if ( iface )
3929  {
3930  iface->addPages( dialog );
3931  pagesAdded = true;
3932  if ( !it.value().catalogName.isEmpty() )
3933  KGlobal::locale()->insertCatalog( it.value().catalogName );
3934  }
3935  }
3936  if ( pagesAdded )
3937  {
3938  connect( dialog, SIGNAL(settingsChanged(QString)),
3939  this, SLOT(slotGeneratorConfigChanged(QString)) );
3940  }
3941 }
3942 
3943 int Document::configurableGenerators() const
3944 {
3945  QString constraint( "([X-KDE-Priority] > 0) and (exist Library) and ([X-KDE-okularHasInternalSettings])" );
3946  KService::List offers = KServiceTypeTrader::self()->query( "okular/Generator", constraint );
3947  return offers.count();
3948 }
3949 
3950 QStringList Document::supportedMimeTypes() const
3951 {
3952  if ( !d->m_supportedMimeTypes.isEmpty() )
3953  return d->m_supportedMimeTypes;
3954 
3955  QString constraint( "(Library == 'okularpart')" );
3956  QLatin1String basePartService( "KParts/ReadOnlyPart" );
3957  KService::List offers = KServiceTypeTrader::self()->query( basePartService, constraint );
3958  KService::List::ConstIterator it = offers.constBegin(), itEnd = offers.constEnd();
3959  for ( ; it != itEnd; ++it )
3960  {
3961  KService::Ptr service = *it;
3962  QStringList mimeTypes = service->serviceTypes();
3963  foreach ( const QString& mimeType, mimeTypes )
3964  if ( mimeType != basePartService )
3965  d->m_supportedMimeTypes.append( mimeType );
3966  }
3967 
3968  return d->m_supportedMimeTypes;
3969 }
3970 
3971 const KComponentData* Document::componentData() const
3972 {
3973  if ( !d->m_generator )
3974  return 0;
3975 
3976  QHash< QString, GeneratorInfo >::const_iterator genIt = d->m_loadedGenerators.constFind( d->m_generatorName );
3977  Q_ASSERT( genIt != d->m_loadedGenerators.constEnd() );
3978  const KComponentData* kcd = &genIt.value().data;
3979 
3980  // empty about data
3981  if ( kcd->isValid() && kcd->aboutData() && kcd->aboutData()->programName().isEmpty() )
3982  return 0;
3983 
3984  return kcd;
3985 }
3986 
3987 bool Document::canSaveChanges() const
3988 {
3989  if ( !d->m_generator )
3990  return false;
3991  Q_ASSERT( !d->m_generatorName.isEmpty() );
3992 
3993  QHash< QString, GeneratorInfo >::iterator genIt = d->m_loadedGenerators.find( d->m_generatorName );
3994  Q_ASSERT( genIt != d->m_loadedGenerators.end() );
3995  SaveInterface* saveIface = d->generatorSave( genIt.value() );
3996  if ( !saveIface )
3997  return false;
3998 
3999  return saveIface->supportsOption( SaveInterface::SaveChanges );
4000 }
4001 
4002 bool Document::canSaveChanges( SaveCapability cap ) const
4003 {
4004  switch ( cap )
4005  {
4006  case SaveFormsCapability:
4007  /* Assume that if the generator supports saving, forms can be saved.
4008  * We have no means to actually query the generator at the moment
4009  * TODO: Add some method to query the generator in SaveInterface */
4010  return canSaveChanges();
4011 
4012  case SaveAnnotationsCapability:
4013  return d->canAddAnnotationsNatively();
4014  }
4015 
4016  return false;
4017 }
4018 
4019 bool Document::saveChanges( const QString &fileName )
4020 {
4021  QString errorText;
4022  return saveChanges( fileName, &errorText );
4023 }
4024 
4025 bool Document::saveChanges( const QString &fileName, QString *errorText )
4026 {
4027  if ( !d->m_generator || fileName.isEmpty() )
4028  return false;
4029  Q_ASSERT( !d->m_generatorName.isEmpty() );
4030 
4031  QHash< QString, GeneratorInfo >::iterator genIt = d->m_loadedGenerators.find( d->m_generatorName );
4032  Q_ASSERT( genIt != d->m_loadedGenerators.end() );
4033  SaveInterface* saveIface = d->generatorSave( genIt.value() );
4034  if ( !saveIface || !saveIface->supportsOption( SaveInterface::SaveChanges ) )
4035  return false;
4036 
4037  return saveIface->save( fileName, SaveInterface::SaveChanges, errorText );
4038 }
4039 
4040 void Document::registerView( View *view )
4041 {
4042  if ( !view )
4043  return;
4044 
4045  Document *viewDoc = view->viewDocument();
4046  if ( viewDoc )
4047  {
4048  // check if already registered for this document
4049  if ( viewDoc == this )
4050  return;
4051 
4052  viewDoc->unregisterView( view );
4053  }
4054 
4055  d->m_views.insert( view );
4056  view->d_func()->document = d;
4057 }
4058 
4059 void Document::unregisterView( View *view )
4060 {
4061  if ( !view )
4062  return;
4063 
4064  Document *viewDoc = view->viewDocument();
4065  if ( !viewDoc || viewDoc != this )
4066  return;
4067 
4068  view->d_func()->document = 0;
4069  d->m_views.remove( view );
4070 }
4071 
4072 QByteArray Document::fontData(const FontInfo &font) const
4073 {
4074  QByteArray result;
4075 
4076  if (d->m_generator)
4077  {
4078  QMetaObject::invokeMethod(d->m_generator, "requestFontData", Qt::DirectConnection, Q_ARG(Okular::FontInfo, font), Q_ARG(QByteArray *, &result));
4079  }
4080 
4081  return result;
4082 }
4083 
4084 bool Document::openDocumentArchive( const QString & docFile, const KUrl & url )
4085 {
4086  const KMimeType::Ptr mime = KMimeType::findByPath( docFile, 0, false /* content too */ );
4087  if ( !mime->is( "application/vnd.kde.okular-archive" ) )
4088  return false;
4089 
4090  KZip okularArchive( docFile );
4091  if ( !okularArchive.open( QIODevice::ReadOnly ) )
4092  return false;
4093 
4094  const KArchiveDirectory * mainDir = okularArchive.directory();
4095  const KArchiveEntry * mainEntry = mainDir->entry( "content.xml" );
4096  if ( !mainEntry || !mainEntry->isFile() )
4097  return false;
4098 
4099  std::auto_ptr< QIODevice > mainEntryDevice( static_cast< const KZipFileEntry * >( mainEntry )->createDevice() );
4100  QDomDocument doc;
4101  if ( !doc.setContent( mainEntryDevice.get() ) )
4102  return false;
4103  mainEntryDevice.reset();
4104 
4105  QDomElement root = doc.documentElement();
4106  if ( root.tagName() != "OkularArchive" )
4107  return false;
4108 
4109  QString documentFileName;
4110  QString metadataFileName;
4111  QDomElement el = root.firstChild().toElement();
4112  for ( ; !el.isNull(); el = el.nextSibling().toElement() )
4113  {
4114  if ( el.tagName() == "Files" )
4115  {
4116  QDomElement fileEl = el.firstChild().toElement();
4117  for ( ; !fileEl.isNull(); fileEl = fileEl.nextSibling().toElement() )
4118  {
4119  if ( fileEl.tagName() == "DocumentFileName" )
4120  documentFileName = fileEl.text();
4121  else if ( fileEl.tagName() == "MetadataFileName" )
4122  metadataFileName = fileEl.text();
4123  }
4124  }
4125  }
4126  if ( documentFileName.isEmpty() )
4127  return false;
4128 
4129  const KArchiveEntry * docEntry = mainDir->entry( documentFileName );
4130  if ( !docEntry || !docEntry->isFile() )
4131  return false;
4132 
4133  std::auto_ptr< ArchiveData > archiveData( new ArchiveData() );
4134  const int dotPos = documentFileName.indexOf( '.' );
4135  if ( dotPos != -1 )
4136  archiveData->document.setSuffix( documentFileName.mid( dotPos ) );
4137  if ( !archiveData->document.open() )
4138  return false;
4139 
4140  QString tempFileName = archiveData->document.fileName();
4141  {
4142  std::auto_ptr< QIODevice > docEntryDevice( static_cast< const KZipFileEntry * >( docEntry )->createDevice() );
4143  copyQIODevice( docEntryDevice.get(), &archiveData->document );
4144  archiveData->document.close();
4145  }
4146 
4147  std::auto_ptr< KTemporaryFile > tempMetadataFileName;
4148  const KArchiveEntry * metadataEntry = mainDir->entry( metadataFileName );
4149  if ( metadataEntry && metadataEntry->isFile() )
4150  {
4151  std::auto_ptr< QIODevice > metadataEntryDevice( static_cast< const KZipFileEntry * >( metadataEntry )->createDevice() );
4152  tempMetadataFileName.reset( new KTemporaryFile() );
4153  tempMetadataFileName->setSuffix( ".xml" );
4154  tempMetadataFileName->setAutoRemove( false );
4155  if ( tempMetadataFileName->open() )
4156  {
4157  copyQIODevice( metadataEntryDevice.get(), tempMetadataFileName.get() );
4158  archiveData->metadataFileName = tempMetadataFileName->fileName();
4159  tempMetadataFileName->close();
4160  }
4161  }
4162 
4163  const KMimeType::Ptr docMime = KMimeType::findByPath( tempFileName, 0, true /* local file */ );
4164  d->m_archiveData = archiveData.get();
4165  d->m_archivedFileName = documentFileName;
4166  bool ret = openDocument( tempFileName, url, docMime );
4167 
4168  if ( ret )
4169  {
4170  archiveData.release();
4171  }
4172  else
4173  {
4174  d->m_archiveData = 0;
4175  }
4176 
4177  return ret;
4178 }
4179 
4180 bool Document::saveDocumentArchive( const QString &fileName )
4181 {
4182  if ( !d->m_generator )
4183  return false;
4184 
4185  /* If we opened an archive, use the name of original file (eg foo.pdf)
4186  * instead of the archive's one (eg foo.okular) */
4187  QString docFileName = d->m_archiveData ? d->m_archivedFileName : d->m_url.fileName();
4188  if ( docFileName == QLatin1String( "-" ) )
4189  return false;
4190 
4191  QString docPath = d->m_docFileName;
4192  const QFileInfo fi( docPath );
4193  if ( fi.isSymLink() )
4194  docPath = fi.symLinkTarget();
4195 
4196  KZip okularArchive( fileName );
4197  if ( !okularArchive.open( QIODevice::WriteOnly ) )
4198  return false;
4199 
4200  const KUser user;
4201 #ifndef Q_OS_WIN
4202  const KUserGroup userGroup( user.gid() );
4203 #else
4204  const KUserGroup userGroup( QString( "" ) );
4205 #endif
4206 
4207  QDomDocument contentDoc( "OkularArchive" );
4208  QDomProcessingInstruction xmlPi = contentDoc.createProcessingInstruction(
4209  QString::fromLatin1( "xml" ), QString::fromLatin1( "version=\"1.0\" encoding=\"utf-8\"" ) );
4210  contentDoc.appendChild( xmlPi );
4211  QDomElement root = contentDoc.createElement( "OkularArchive" );
4212  contentDoc.appendChild( root );
4213 
4214  QDomElement filesNode = contentDoc.createElement( "Files" );
4215  root.appendChild( filesNode );
4216 
4217  QDomElement fileNameNode = contentDoc.createElement( "DocumentFileName" );
4218  filesNode.appendChild( fileNameNode );
4219  fileNameNode.appendChild( contentDoc.createTextNode( docFileName ) );
4220 
4221  QDomElement metadataFileNameNode = contentDoc.createElement( "MetadataFileName" );
4222  filesNode.appendChild( metadataFileNameNode );
4223  metadataFileNameNode.appendChild( contentDoc.createTextNode( "metadata.xml" ) );
4224 
4225  // If the generator can save annotations natively, do it
4226  KTemporaryFile modifiedFile;
4227  bool annotationsSavedNatively = false;
4228  if ( d->canAddAnnotationsNatively() )
4229  {
4230  if ( !modifiedFile.open() )
4231  return false;
4232 
4233  modifiedFile.close(); // We're only interested in the file name
4234 
4235  QString errorText;
4236  if ( saveChanges( modifiedFile.fileName(), &errorText ) )
4237  {
4238  docPath = modifiedFile.fileName(); // Save this instead of the original file
4239  annotationsSavedNatively = true;
4240  }
4241  else
4242  {
4243  kWarning(OkularDebug) << "saveChanges failed: " << errorText;
4244  kDebug(OkularDebug) << "Falling back to saving a copy of the original file";
4245  }
4246  }
4247 
4248  KTemporaryFile metadataFile;
4249  PageItems saveWhat = annotationsSavedNatively ? None : AnnotationPageItems;
4250  if ( !d->savePageDocumentInfo( &metadataFile, saveWhat ) )
4251  return false;
4252 
4253  const QByteArray contentDocXml = contentDoc.toByteArray();
4254  okularArchive.writeFile( "content.xml", user.loginName(), userGroup.name(),
4255  contentDocXml.constData(), contentDocXml.length() );
4256 
4257  okularArchive.addLocalFile( docPath, docFileName );
4258  okularArchive.addLocalFile( metadataFile.fileName(), "metadata.xml" );
4259 
4260  if ( !okularArchive.close() )
4261  return false;
4262 
4263  return true;
4264 }
4265 
4266 QPrinter::Orientation Document::orientation() const
4267 {
4268  double width, height;
4269  int landscape, portrait;
4270  const Okular::Page *currentPage;
4271 
4272  // if some pages are landscape and others are not, the most common wins, as
4273  // QPrinter does not accept a per-page setting
4274  landscape = 0;
4275  portrait = 0;
4276  for (uint i = 0; i < pages(); i++)
4277  {
4278  currentPage = page(i);
4279  width = currentPage->width();
4280  height = currentPage->height();
4281  if (currentPage->orientation() == Okular::Rotation90 || currentPage->orientation() == Okular::Rotation270) qSwap(width, height);
4282  if (width > height) landscape++;
4283  else portrait++;
4284  }
4285  return (landscape > portrait) ? QPrinter::Landscape : QPrinter::Portrait;
4286 }
4287 
4288 void Document::setAnnotationEditingEnabled( bool enable )
4289 {
4290  d->m_annotationEditingEnabled = enable;
4291  foreachObserver( notifySetup( d->m_pagesVector, 0 ) );
4292 }
4293 
4294 void DocumentPrivate::requestDone( PixmapRequest * req )
4295 {
4296  if ( !req )
4297  return;
4298 
4299  if ( !m_generator || m_closingLoop )
4300  {
4301  m_pixmapRequestsMutex.lock();
4302  m_executingPixmapRequests.removeAll( req );
4303  m_pixmapRequestsMutex.unlock();
4304  delete req;
4305  if ( m_closingLoop )
4306  m_closingLoop->exit();
4307  return;
4308  }
4309 
4310 #ifndef NDEBUG
4311  if ( !m_generator->canGeneratePixmap() )
4312  kDebug(OkularDebug) << "requestDone with generator not in READY state.";
4313 #endif
4314 
4315  // [MEM] 1.1 find and remove a previous entry for the same page and id
4316  QLinkedList< AllocatedPixmap * >::iterator aIt = m_allocatedPixmaps.begin();
4317  QLinkedList< AllocatedPixmap * >::iterator aEnd = m_allocatedPixmaps.end();
4318  for ( ; aIt != aEnd; ++aIt )
4319  if ( (*aIt)->page == req->pageNumber() && (*aIt)->observer == req->observer() )
4320  {
4321  AllocatedPixmap * p = *aIt;
4322  m_allocatedPixmaps.erase( aIt );
4323  m_allocatedPixmapsTotalMemory -= p->memory;
4324  delete p;
4325  break;
4326  }
4327 
4328  DocumentObserver *observer = req->observer();
4329  if ( m_observers.contains(observer) )
4330  {
4331  // [MEM] 1.2 append memory allocation descriptor to the FIFO
4332  qulonglong memoryBytes = 0;
4333  const TilesManager *tm = ( req->observer() == m_tiledObserver ) ? req->page()->d->tilesManager() : 0;
4334  if ( tm )
4335  memoryBytes = tm->totalMemory();
4336  else
4337  memoryBytes = 4 * req->width() * req->height();
4338 
4339  AllocatedPixmap * memoryPage = new AllocatedPixmap( req->observer(), req->pageNumber(), memoryBytes );
4340  m_allocatedPixmaps.append( memoryPage );
4341  m_allocatedPixmapsTotalMemory += memoryBytes;
4342 
4343  // 2. notify an observer that its pixmap changed
4344  observer->notifyPageChanged( req->pageNumber(), DocumentObserver::Pixmap );
4345  }
4346 #ifndef NDEBUG
4347  else
4348  kWarning(OkularDebug) << "Receiving a done request for the defunct observer" << observer;
4349 #endif
4350 
4351  // 3. delete request
4352  m_pixmapRequestsMutex.lock();
4353  m_executingPixmapRequests.removeAll( req );
4354  m_pixmapRequestsMutex.unlock();
4355  delete req;
4356 
4357  // 4. start a new generation if some is pending
4358  m_pixmapRequestsMutex.lock();
4359  bool hasPixmaps = !m_pixmapRequestsStack.isEmpty();
4360  m_pixmapRequestsMutex.unlock();
4361  if ( hasPixmaps )
4362  sendGeneratorPixmapRequest();
4363 }
4364 
4365 void DocumentPrivate::setPageBoundingBox( int page, const NormalizedRect& boundingBox )
4366 {
4367  Page * kp = m_pagesVector[ page ];
4368  if ( !m_generator || !kp )
4369  return;
4370 
4371  if ( kp->boundingBox() == boundingBox )
4372  return;
4373  kp->setBoundingBox( boundingBox );
4374 
4375  // notify observers about the change
4376  foreachObserverD( notifyPageChanged( page, DocumentObserver::BoundingBox ) );
4377 
4378  // 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.
4379  // TODO: Crop computation should also consider annotations, actions, etc. to make sure they're not cropped away.
4380  // TODO: Help compute bounding box for generators that create a QPixmap without a QImage, like text and plucker.
4381  // TODO: Don't compute the bounding box if no one needs it (e.g., Trim Borders is off).
4382 
4383 }
4384 
4385 void DocumentPrivate::calculateMaxTextPages()
4386 {
4387  int multipliers = qMax(1, qRound(getTotalMemory() / 536870912.0)); // 512 MB
4388  switch (SettingsCore::memoryLevel())
4389  {
4390  case SettingsCore::EnumMemoryLevel::Low:
4391  m_maxAllocatedTextPages = multipliers * 2;
4392  break;
4393 
4394  case SettingsCore::EnumMemoryLevel::Normal:
4395  m_maxAllocatedTextPages = multipliers * 50;
4396  break;
4397 
4398  case SettingsCore::EnumMemoryLevel::Aggressive:
4399  m_maxAllocatedTextPages = multipliers * 250;
4400  break;
4401 
4402  case SettingsCore::EnumMemoryLevel::Greedy:
4403  m_maxAllocatedTextPages = multipliers * 1250;
4404  break;
4405  }
4406 }
4407 
4408 void DocumentPrivate::textGenerationDone( Page *page )
4409 {
4410  if ( !m_generator || m_closingLoop ) return;
4411 
4412  // 1. If we reached the cache limit, delete the first text page from the fifo
4413  if (m_allocatedTextPagesFifo.size() == m_maxAllocatedTextPages)
4414  {
4415  int pageToKick = m_allocatedTextPagesFifo.takeFirst();
4416  if (pageToKick != page->number()) // this should never happen but better be safe than sorry
4417  {
4418  m_pagesVector.at(pageToKick)->setTextPage( 0 ); // deletes the textpage
4419  }
4420  }
4421 
4422  // 2. Add the page to the fifo of generated text pages
4423  m_allocatedTextPagesFifo.append( page->number() );
4424 }
4425 
4426 void Document::setRotation( int r )
4427 {
4428  d->setRotationInternal( r, true );
4429 }
4430 
4431 void DocumentPrivate::setRotationInternal( int r, bool notify )
4432 {
4433  Rotation rotation = (Rotation)r;
4434  if ( !m_generator || ( m_rotation == rotation ) )
4435  return;
4436 
4437  // tell the pages to rotate
4438  QVector< Okular::Page * >::const_iterator pIt = m_pagesVector.constBegin();
4439  QVector< Okular::Page * >::const_iterator pEnd = m_pagesVector.constEnd();
4440  for ( ; pIt != pEnd; ++pIt )
4441  (*pIt)->d->rotateAt( rotation );
4442  if ( notify )
4443  {
4444  // notify the generator that the current rotation has changed
4445  m_generator->rotationChanged( rotation, m_rotation );
4446  }
4447  // set the new rotation
4448  m_rotation = rotation;
4449 
4450  if ( notify )
4451  {
4452  foreachObserverD( notifySetup( m_pagesVector, DocumentObserver::NewLayoutForPages ) );
4453  foreachObserverD( notifyContentsCleared( DocumentObserver::Pixmap | DocumentObserver::Highlights | DocumentObserver::Annotations ) );
4454  }
4455  kDebug(OkularDebug) << "Rotated:" << r;
4456 }
4457 
4458 void Document::setPageSize( const PageSize &size )
4459 {
4460  if ( !d->m_generator || !d->m_generator->hasFeature( Generator::PageSizes ) )
4461  return;
4462 
4463  if ( d->m_pageSizes.isEmpty() )
4464  d->m_pageSizes = d->m_generator->pageSizes();
4465  int sizeid = d->m_pageSizes.indexOf( size );
4466  if ( sizeid == -1 )
4467  return;
4468 
4469  // tell the pages to change size
4470  QVector< Okular::Page * >::const_iterator pIt = d->m_pagesVector.constBegin();
4471  QVector< Okular::Page * >::const_iterator pEnd = d->m_pagesVector.constEnd();
4472  for ( ; pIt != pEnd; ++pIt )
4473  (*pIt)->d->changeSize( size );
4474  // clear 'memory allocation' descriptors
4475  qDeleteAll( d->m_allocatedPixmaps );
4476  d->m_allocatedPixmaps.clear();
4477  d->m_allocatedPixmapsTotalMemory = 0;
4478  // notify the generator that the current page size has changed
4479  d->m_generator->pageSizeChanged( size, d->m_pageSize );
4480  // set the new page size
4481  d->m_pageSize = size;
4482 
4483  foreachObserver( notifySetup( d->m_pagesVector, DocumentObserver::NewLayoutForPages ) );
4484  foreachObserver( notifyContentsCleared( DocumentObserver::Pixmap | DocumentObserver::Highlights ) );
4485  kDebug(OkularDebug) << "New PageSize id:" << sizeid;
4486 }
4487 
4488 
4491 DocumentViewport::DocumentViewport( int n )
4492  : pageNumber( n )
4493 {
4494  // default settings
4495  rePos.enabled = false;
4496  rePos.normalizedX = 0.5;
4497  rePos.normalizedY = 0.0;
4498  rePos.pos = Center;
4499  autoFit.enabled = false;
4500  autoFit.width = false;
4501  autoFit.height = false;
4502 }
4503 
4504 DocumentViewport::DocumentViewport( const QString & xmlDesc )
4505  : pageNumber( -1 )
4506 {
4507  // default settings (maybe overridden below)
4508  rePos.enabled = false;
4509  rePos.normalizedX = 0.5;
4510  rePos.normalizedY = 0.0;
4511  rePos.pos = Center;
4512  autoFit.enabled = false;
4513  autoFit.width = false;
4514  autoFit.height = false;
4515 
4516  // check for string presence
4517  if ( xmlDesc.isEmpty() )
4518  return;
4519 
4520  // decode the string
4521  bool ok;
4522  int field = 0;
4523  QString token = xmlDesc.section( ';', field, field );
4524  while ( !token.isEmpty() )
4525  {
4526  // decode the current token
4527  if ( field == 0 )
4528  {
4529  pageNumber = token.toInt( &ok );
4530  if ( !ok )
4531  return;
4532  }
4533  else if ( token.startsWith( "C1" ) )
4534  {
4535  rePos.enabled = true;
4536  rePos.normalizedX = token.section( ':', 1, 1 ).toDouble();
4537  rePos.normalizedY = token.section( ':', 2, 2 ).toDouble();
4538  rePos.pos = Center;
4539  }
4540  else if ( token.startsWith( "C2" ) )
4541  {
4542  rePos.enabled = true;
4543  rePos.normalizedX = token.section( ':', 1, 1 ).toDouble();
4544  rePos.normalizedY = token.section( ':', 2, 2 ).toDouble();
4545  if (token.section( ':', 3, 3 ).toInt() == 1) rePos.pos = Center;
4546  else rePos.pos = TopLeft;
4547  }
4548  else if ( token.startsWith( "AF1" ) )
4549  {
4550  autoFit.enabled = true;
4551  autoFit.width = token.section( ':', 1, 1 ) == "T";
4552  autoFit.height = token.section( ':', 2, 2 ) == "T";
4553  }
4554  // proceed tokenizing string
4555  field++;
4556  token = xmlDesc.section( ';', field, field );
4557  }
4558 }
4559 
4560 QString DocumentViewport::toString() const
4561 {
4562  // start string with page number
4563  QString s = QString::number( pageNumber );
4564  // if has center coordinates, save them on string
4565  if ( rePos.enabled )
4566  s += QString( ";C2:" ) + QString::number( rePos.normalizedX ) +
4567  ':' + QString::number( rePos.normalizedY ) +
4568  ':' + QString::number( rePos.pos );
4569  // if has autofit enabled, save its state on string
4570  if ( autoFit.enabled )
4571  s += QString( ";AF1:" ) + (autoFit.width ? "T" : "F") +
4572  ':' + (autoFit.height ? "T" : "F");
4573  return s;
4574 }
4575 
4576 bool DocumentViewport::isValid() const
4577 {
4578  return pageNumber >= 0;
4579 }
4580 
4581 bool DocumentViewport::operator==( const DocumentViewport & vp ) const
4582 {
4583  bool equal = ( pageNumber == vp.pageNumber ) &&
4584  ( rePos.enabled == vp.rePos.enabled ) &&
4585  ( autoFit.enabled == vp.autoFit.enabled );
4586  if ( !equal )
4587  return false;
4588  if ( rePos.enabled &&
4589  (( rePos.normalizedX != vp.rePos.normalizedX) ||
4590  ( rePos.normalizedY != vp.rePos.normalizedY ) || rePos.pos != vp.rePos.pos) )
4591  return false;
4592  if ( autoFit.enabled &&
4593  (( autoFit.width != vp.autoFit.width ) ||
4594  ( autoFit.height != vp.autoFit.height )) )
4595  return false;
4596  return true;
4597 }
4598 
4599 bool DocumentViewport::operator<( const DocumentViewport & vp ) const
4600 {
4601  // TODO: Check autoFit and Position
4602 
4603  if ( pageNumber != vp.pageNumber )
4604  return pageNumber < vp.pageNumber;
4605 
4606  if ( !rePos.enabled && vp.rePos.enabled )
4607  return true;
4608 
4609  if ( !vp.rePos.enabled )
4610  return false;
4611 
4612  if ( rePos.normalizedY != vp.rePos.normalizedY )
4613  return rePos.normalizedY < vp.rePos.normalizedY;
4614 
4615  return rePos.normalizedX < vp.rePos.normalizedX;
4616 }
4617 
4618 
4621 DocumentInfo::DocumentInfo()
4622  : QDomDocument( "DocumentInformation" )
4623 {
4624  QDomElement docElement = createElement( "DocumentInfo" );
4625  appendChild( docElement );
4626 }
4627 
4628 void DocumentInfo::set( const QString &key, const QString &value,
4629  const QString &title )
4630 {
4631  QDomElement docElement = documentElement();
4632  QDomElement element;
4633 
4634  // check whether key already exists
4635  QDomNodeList list = docElement.elementsByTagName( key );
4636  if ( list.count() > 0 )
4637  element = list.item( 0 ).toElement();
4638  else
4639  element = createElement( key );
4640 
4641  element.setAttribute( "value", value );
4642  element.setAttribute( "title", title );
4643 
4644  if ( list.count() == 0 )
4645  docElement.appendChild( element );
4646 }
4647 
4648 void DocumentInfo::set( Key key, const QString &value )
4649 {
4650  const QString keyString = getKeyString( key );
4651  if ( !keyString.isEmpty() )
4652  set( keyString, value, getKeyTitle( key ) );
4653  else
4654  kWarning(OkularDebug) << "Invalid key passed";
4655 }
4656 
4657 QString DocumentInfo::get( const QString &key ) const
4658 {
4659  const QDomElement docElement = documentElement();
4660 
4661  // check whether key already exists
4662  const QDomNodeList list = docElement.elementsByTagName( key );
4663  if ( list.count() > 0 )
4664  return list.item( 0 ).toElement().attribute( "value" );
4665  else
4666  return QString();
4667 }
4668 
4669 QString DocumentInfo::getKeyString( Key key ) //const
4670 {
4671  switch ( key ) {
4672  case Title:
4673  return "title";
4674  break;
4675  case Subject:
4676  return "subject";
4677  break;
4678  case Description:
4679  return "description";
4680  break;
4681  case Author:
4682  return "author";
4683  break;
4684  case Creator:
4685  return "creator";
4686  break;
4687  case Producer:
4688  return "producer";
4689  break;
4690  case Copyright:
4691  return "copyright";
4692  break;
4693  case Pages:
4694  return "pages";
4695  break;
4696  case CreationDate:
4697  return "creationDate";
4698  break;
4699  case ModificationDate:
4700  return "modificationDate";
4701  break;
4702  case MimeType:
4703  return "mimeType";
4704  break;
4705  case Category:
4706  return "category";
4707  break;
4708  case Keywords:
4709  return "keywords";
4710  break;
4711  case FilePath:
4712  return "filePath";
4713  break;
4714  case DocumentSize:
4715  return "documentSize";
4716  break;
4717  case PagesSize:
4718  return "pageSize";
4719  break;
4720  default:
4721  return QString();
4722  break;
4723  }
4724 }
4725 
4726 QString DocumentInfo::getKeyTitle( Key key ) //const
4727 {
4728  switch ( key ) {
4729  case Title:
4730  return i18n( "Title" );
4731  break;
4732  case Subject:
4733  return i18n( "Subject" );
4734  break;
4735  case Description:
4736  return i18n( "Description" );
4737  break;
4738  case Author:
4739  return i18n( "Author" );
4740  break;
4741  case Creator:
4742  return i18n( "Creator" );
4743  break;
4744  case Producer:
4745  return i18n( "Producer" );
4746  break;
4747  case Copyright:
4748  return i18n( "Copyright" );
4749  break;
4750  case Pages:
4751  return i18n( "Pages" );
4752  break;
4753  case CreationDate:
4754  return i18n( "Created" );
4755  break;
4756  case ModificationDate:
4757  return i18n( "Modified" );
4758  break;
4759  case MimeType:
4760  return i18n( "Mime Type" );
4761  break;
4762  case Category:
4763  return i18n( "Category" );
4764  break;
4765  case Keywords:
4766  return i18n( "Keywords" );
4767  break;
4768  case FilePath:
4769  return i18n( "File Path" );
4770  break;
4771  case DocumentSize:
4772  return i18n( "File Size" );
4773  break;
4774  case PagesSize:
4775  return i18n("Page Size");
4776  break;
4777  default:
4778  return QString();
4779  break;
4780  }
4781 }
4782 
4783 
4786 DocumentSynopsis::DocumentSynopsis()
4787  : QDomDocument( "DocumentSynopsis" )
4788 {
4789  // void implementation, only subclassed for naming
4790 }
4791 
4792 DocumentSynopsis::DocumentSynopsis( const QDomDocument &document )
4793  : QDomDocument( document )
4794 {
4795 }
4796 
4799 EmbeddedFile::EmbeddedFile()
4800 {
4801 }
4802 
4803 EmbeddedFile::~EmbeddedFile()
4804 {
4805 }
4806 
4807 VisiblePageRect::VisiblePageRect( int page, const NormalizedRect &rectangle )
4808  : pageNumber( page ), rect( rectangle )
4809 {
4810 }
4811 
4812 #undef foreachObserver
4813 #undef foreachObserverD
4814 
4815 #include "document.moc"
4816 
4817 /* kate: replace-tabs on; indent-width 4; */
Okular::Document::editFormList
void editFormList(int pageNumber, Okular::FormFieldChoice *form, const QList< int > &newChoices)
Edit the selected list entries in form on page page to be newChoices.
Definition: document.cpp:3456
Okular::DocumentPrivate::savePageDocumentInfo
bool savePageDocumentInfo(KTemporaryFile *infoFile, int what) const
Definition: document.cpp:972
Okular::Generator::NoFileToPrintError
Definition: generator.h:360
Okular::DocumentPrivate::loadGeneratorLibrary
Generator * loadGeneratorLibrary(const KService::Ptr &service)
Definition: document.cpp:798
Okular::Scripter::execute
QString execute(ScriptType type, const QString &script)
Definition: scripter.cpp:46
Okular::Annotation::AStamp
A stamp annotation.
Definition: annotations.h:111
Okular::Action::DocAction
Start a custom action.
Definition: action.h:53
Okular::NormalizedPoint
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition: area.h:47
Okular::ModifyAnnotationPropertiesCommand
Definition: documentcommands_p.h:60
Okular::DocumentViewport::pos
Position pos
Definition: document.h:1054
Okular::TilesManager::cleanupPixmapMemory
void cleanupPixmapMemory(qulonglong numberOfBytes, const NormalizedRect &visibleRect, int visiblePageNumber)
Removes at least numberOfBytes bytes worth of tiles (least ranked tiles are removed first)...
Definition: tilesmanager.cpp:449
Okular::DocumentPrivate::m_documentInfo
DocumentInfo * m_documentInfo
Definition: document_p.h:265
Okular::DocumentPrivate::m_widget
QPointer< QWidget > m_widget
Definition: document_p.h:188
Okular::Document::error
void error(const QString &text, int duration)
This signal is emitted whenever an error occurred.
Okular::Generator::exportTo
virtual bool exportTo(const QString &fileName, const ExportFormat &format)
This method is called to export the document in the given format and save it under the given fileName...
Definition: generator.cpp:339
Okular::View::setCapability
virtual void setCapability(ViewCapability capability, const QVariant &option)
Sets a new value for the specified capability.
Definition: view.cpp:72
Okular::FormFieldText::text
virtual QString text() const =0
The text of text field.
Okular::Generator::pageSizes
virtual PageSize::List pageSizes() const
Returns the list of supported page sizes.
Definition: generator.cpp:309
Okular::Document::reparseConfig
void reparseConfig()
Reparses and applies the configuration.
Definition: document.cpp:2474
Okular::DocumentViewport::autoFit
struct Okular::DocumentViewport::@1 autoFit
If 'autoFit.enabled == true' then the page must be autofitted in the viewport.
Okular::Generator::PrintToFile
Whether the Generator supports export to PDF & PS through the Print Dialog.
Definition: generator.h:208
Okular::None
Definition: page_p.h:44
Okular::Document::exportFormats
QList< ExportFormat > exportFormats() const
Returns the list of supported export formats.
Definition: document.cpp:2722
GeneratorInfo::generator
Okular::Generator * generator
Definition: document_p.h:55
Okular::AudioPlayer::instance
static AudioPlayer * instance()
Gets the instance of the audio player.
Definition: audioplayer.cpp:219
Okular::Document::startFontReading
void startFontReading()
Starts the reading of the information about the fonts in the document, if available.
Definition: document.cpp:2572
Okular::DocumentPrivate::slotTimedMemoryCheck
void slotTimedMemoryCheck()
Definition: document.cpp:1275
Okular::FontExtractionThread
Definition: generator_p.h:141
Okular::PageSize::List
QList< PageSize > List
Definition: pagesize.h:29
Okular::PagePrivate::tilesManager
TilesManager * tilesManager() const
Get/set the tiles manager for the tiled observer.
Definition: page.cpp:1014
Okular::Generator::generateTextPage
virtual void generateTextPage(Page *page)
This method can be called to trigger the generation of a text page for the given page.
Definition: generator.cpp:257
GeneratorInfo
Definition: document_p.h:47
Okular::Rotation
Rotation
A rotation.
Definition: global.h:44
Okular::DocumentObserver::Highlights
Highlighting information has been changed.
Definition: observer.h:44
Okular::Document::translatePageAnnotation
void translatePageAnnotation(int page, Annotation *annotation, const Okular::NormalizedPoint &delta)
Translates the position of the given annotation on the given page by a distance delta in normalized c...
Definition: document.cpp:2983
Okular::Document::requestPixmaps
void requestPixmaps(const QLinkedList< PixmapRequest * > &requests)
Sends requests for pixmap generation.
Definition: document.cpp:2786
Okular::DocumentPrivate::m_lastSearchID
int m_lastSearchID
Definition: document_p.h:192
Okular::DocumentPrivate::m_searchCancelled
bool m_searchCancelled
Definition: document_p.h:193
Okular::DocumentPrivate::m_pageSizes
PageSize::List m_pageSizes
Definition: document_p.h:231
Okular::DocumentAction::PagePrev
Jump to previous page.
Definition: action.h:275
Okular::DocumentPrivate::m_url
KUrl m_url
Definition: document_p.h:197
Okular::NextResult
Searching for the next result on the page, earlier result should be located so we search from the las...
Definition: global.h:37
Okular::TilesManager::height
int height() const
Gets the height of the page in tiles manager.
Definition: tilesmanager.cpp:152
Okular::PixmapRequest::pageNumber
int pageNumber() const
Returns the page number of the request.
Definition: generator.cpp:449
Okular::DocumentAction::PageLast
Jump to last page.
Definition: action.h:277
pagecontroller_p.h
Okular::Document::NoPrinting
Printing Not Supported.
Definition: document.h:555
Okular::DocumentPrivate::m_nextDocumentViewport
DocumentViewport m_nextDocumentViewport
Definition: document_p.h:208
Okular::DocumentPrivate::performAddPageAnnotation
void performAddPageAnnotation(int page, Annotation *annotation)
Definition: document.cpp:1035
Okular::TilesManager::fromRotatedRect
static NormalizedRect fromRotatedRect(const NormalizedRect &rect, Rotation rotation)
Returns a non rotated version of rect, which is rotated by rotation.
Definition: tilesmanager.cpp:581
Okular::DocumentInfo::Category
The category of the document.
Definition: document.h:1091
misc.h
Okular::Document::unregisterView
void unregisterView(View *view)
Unregister the specified view from the current document.
Definition: document.cpp:4059
Okular::Document::linkEndPresentation
void linkEndPresentation()
This signal is emitted whenever an action requests an end presentation operation. ...
Okular::PixmapRequest::page
Page * page() const
Returns a pointer to the page where the pixmap shall be generated for.
Definition: generator.cpp:479
Okular::DocumentPrivate::setPageBoundingBox
void setPageBoundingBox(int page, const NormalizedRect &boundingBox)
Sets the bounding box of the given page (in terms of upright orientation, i.e., Rotation0).
Definition: document.cpp:4365
tilesmanager_p.h
Okular::DocumentViewport::Center
Relative to the center of the page.
Definition: document.h:1042
Okular::Document::requestTextPage
void requestTextPage(uint number)
Sends a request for text page generation for the given page number.
Definition: document.cpp:2898
Okular::DocumentPrivate::notifyAnnotationChanges
void notifyAnnotationChanges(int page)
Definition: document.cpp:2909
Okular::DocumentPrivate::refreshPixmaps
void refreshPixmaps(int)
Definition: document.cpp:1546
Okular::Document::setViewport
void setViewport(const DocumentViewport &viewport, DocumentObserver *excludeObserver=0, bool smoothMove=false)
Sets the current document viewport to the given viewport.
Definition: document.cpp:3128
Okular::DocumentObserver::Pixmap
Pixmaps has been changed.
Definition: observer.h:42
KXMLGUIClient
Okular::DocumentPrivate::doProcessSearchMatch
void doProcessSearchMatch(RegularAreaRect *match, RunningSearch *search, QSet< int > *pagesToNotify, int currentPage, int searchID, bool moveViewport, const QColor &color)
Definition: document.cpp:1679
Okular::DocumentPrivate::sendGeneratorPixmapRequest
void sendGeneratorPixmapRequest()
Definition: document.cpp:1283
Okular::DocumentAction::Close
Close document.
Definition: action.h:285
Okular::Page::rotation
Rotation rotation() const
Returns the rotation of the page as defined by the user.
Definition: page.cpp:170
Okular::DocumentPrivate::m_warnedOutOfMemory
bool m_warnedOutOfMemory
Definition: document_p.h:223
Okular::Document::sourceReferenceActivated
void sourceReferenceActivated(const QString &absFileName, int line, int col, bool *handled)
This signal is emitted whenever a source reference with the given parameters has been activated...
Okular::Annotation::DenyDelete
Cannot be deleted.
Definition: annotations.h:132
Okular::SourceReference::column
int column() const
Returns the column of the position in the source file.
Definition: sourcereference.cpp:55
Okular::DocumentPrivate::m_executingPixmapRequests
QLinkedList< PixmapRequest * > m_executingPixmapRequests
Definition: document_p.h:217
Okular::DocumentInfo::Copyright
The copyright of the document.
Definition: document.h:1086
bookmarkmanager.h
Okular::Generator::rotationChanged
virtual void rotationChanged(Rotation orientation, Rotation oldOrientation)
This method is called when the orientation has been changed by the user.
Definition: generator.cpp:305
Okular::PixmapRequestPrivate::swap
void swap()
Definition: generator.cpp:507
Okular::View::supportsCapability
virtual bool supportsCapability(ViewCapability capability) const
Query whether the view support the specified capability.
Definition: view.cpp:54
Okular::DocumentInfo::MimeType
The mime type of the document.
Definition: document.h:1090
Okular::Document::NativePrinting
Native Cross-Platform Printing.
Definition: document.h:556
Okular::Generator::UnknownPrintError
Definition: generator.h:352
Okular::Document::modifyPageAnnotationProperties
void modifyPageAnnotationProperties(int page, Annotation *annotation)
Modifies the given annotation on the given page.
Definition: document.cpp:2965
Okular::buildEditorsMap
static QHash< int, QString > buildEditorsMap()
Definition: texteditors_p.h:21
Okular::DocumentPrivate::loadServiceList
void loadServiceList(const KService::List &offers)
Definition: document.cpp:827
Okular::DocumentAction::Find
Open find dialog.
Definition: action.h:283
Okular::DocumentInfo::Author
The author of the document.
Definition: document.h:1083
Okular::DocumentPrivate::cacheExportFormats
void cacheExportFormats()
Definition: document.cpp:851
Okular::Page::hasPixmap
bool hasPixmap(DocumentObserver *observer, int width=-1, int height=-1, const NormalizedRect &rect=NormalizedRect()) const
Returns whether the page of size width x height has a pixmap in the region given by rect for the give...
Definition: page.cpp:218
Okular::DocumentPrivate::m_annotationBeingMoved
bool m_annotationBeingMoved
Definition: document_p.h:272
Okular::Generator::embeddedFiles
virtual const QList< EmbeddedFile * > * embeddedFiles() const
Returns the 'list of embedded files' object of the document or 0 if no list of embedded files is avai...
Definition: generator.cpp:290
Okular::DocumentPrivate::m_archiveData
ArchiveData * m_archiveData
Definition: document_p.h:260
texteditors_p.h
Okular::Generator::isAllowed
virtual bool isAllowed(Permission action) const
This method returns whether given action (Permission) is allowed in this document.
Definition: generator.cpp:300
Okular::PixmapRequest::normalizedRect
const NormalizedRect & normalizedRect() const
Returns the normalized region of the page to request.
Definition: generator.cpp:502
Okular::View
View on the document.
Definition: view.h:32
Okular::Document::canConfigurePrinter
bool canConfigurePrinter() const
Returns whether the document can configure the printer itself.
Definition: document.cpp:2518
Okular::Document::bookmarkManager
BookmarkManager * bookmarkManager() const
Returns the bookmark manager of the document.
Definition: document.cpp:3493
Okular::Document::pages
uint pages() const
Returns the number of pages of the document.
Definition: document.cpp:2652
Okular::DocumentPrivate::_o_configChanged
void _o_configChanged()
Definition: document.cpp:1599
Okular::DocumentPrivate::m_fontsCached
bool m_fontsCached
Definition: document_p.h:264
Okular::Generator::canGeneratePixmap
virtual bool canGeneratePixmap() const
This method returns whether the generator is ready to handle a new pixmap request.
Definition: generator.cpp:211
Okular::Generator::pagesSizeMetric
virtual PageSizeMetric pagesSizeMetric() const
This method returns the metric of the page size.
Definition: generator.cpp:295
foreachObserver
#define foreachObserver(cmd)
Definition: document.cpp:131
Okular::Document::supportsPrintToFile
bool supportsPrintToFile() const
Returns whether the document supports printing to both PDF and PS files.
Definition: document.cpp:3854
Okular::Annotation::BeingMoved
Is being moved (mouse drag and drop). If ExternallyDrawn, the generator must not draw it...
Definition: annotations.h:136
Okular::Annotation::AText
A textual annotation.
Definition: annotations.h:107
Okular::Document::GoogleAny
Search any words in google style.
Definition: document.h:475
Okular::DocumentInfo::FilePath
The path of the file.
Definition: document.h:1093
Okular::DocumentPrivate::loadAllGeneratorLibraries
void loadAllGeneratorLibraries()
Definition: document.cpp:815
Okular::Page::deletePixmap
void deletePixmap(DocumentObserver *observer)
Deletes the pixmap for the given observer.
Definition: page.cpp:722
Okular::DoContinueDirectionMatchSearchStruct::caseSensitivity
Qt::CaseSensitivity caseSensitivity
Definition: document_p.h:76
Okular::Page::number
int number() const
Returns the number of the page in the document.
Definition: page.cpp:160
QWidget
Okular::Document::exportToText
bool exportToText(const QString &fileName) const
Exports the document as ASCII text and saves it under fileName.
Definition: document.cpp:2710
Okular::Generator::ReadRawData
Whether the Generator can read a document directly from its raw data.
Definition: generator.h:203
Okular::Tile::isValid
bool isValid() const
True if the pixmap is available and updated.
Definition: tilesmanager.cpp:706
Okular::Document::currentDocument
KUrl currentDocument() const
Returns the url of the currently opened document.
Definition: document.cpp:2657
Okular::DocumentInfo::Subject
The subject of the document.
Definition: document.h:1081
Okular::LineAnnotation::showCaption
bool showCaption() const
Returns whether the caption shall be shown.
Definition: annotations.cpp:1396
Okular::Document::pageSizes
PageSize::List pageSizes() const
Returns the list of supported page sizes or an empty list if this feature is not available.
Definition: document.cpp:2690
Okular::Document::AllDocument
Search complete document.
Definition: document.h:473
Okular::DocumentObserver::TextSelection
Text selection has been changed.
Definition: observer.h:45
Okular::NormalizedRect
NormalizedRect is a helper class which stores the coordinates of a normalized rect, which is a rectangle of.
Definition: area.h:105
configinterface.h
debug_p.h
Okular::Document::print
bool print(QPrinter &printer)
Prints the document to the given printer.
Definition: document.cpp:3859
Okular::DocumentPrivate::m_viewportHistory
QLinkedList< DocumentViewport > m_viewportHistory
Definition: document_p.h:206
Okular::GuiInterface
Abstract interface for user interface control.
Definition: guiinterface.h:39
GeneratorInfo::configChecked
bool configChecked
Definition: document_p.h:60
Okular::DocumentPrivate::m_generatorsLoaded
bool m_generatorsLoaded
Definition: document_p.h:248
Okular::DocumentPrivate::m_allocatedPixmapsTotalMemory
qulonglong m_allocatedPixmapsTotalMemory
Definition: document_p.h:220
OKULAR_HISTORY_SAVEDSTEPS
#define OKULAR_HISTORY_SAVEDSTEPS
Definition: document.cpp:140
Okular::DoContinueDirectionMatchSearchStruct::currentPage
int currentPage
Definition: document_p.h:73
Okular::DocumentPrivate::m_exportFormats
ExportFormat::List m_exportFormats
Definition: document_p.h:235
Okular::Document::close
void close()
This signal is emitted whenever an action requests a document close operation.
generator_p.h
Okular::Document::NoOption
No options.
Definition: document.h:349
saveinterface.h
Okular::RegularAreaRect
Definition: area.h:860
Okular::Document::editPageAnnotationContents
void editPageAnnotationContents(int page, Annotation *annotation, const QString &newContents, int newCursorPos, int prevCursorPos, int prevAnchorPos)
Edits the plain text contents of the given annotation on the given page.
Definition: document.cpp:2990
annotations_p.h
Okular::Generator::metaData
virtual QVariant metaData(const QString &key, const QVariant &option) const
This method returns the meta data of the given key with the given option of the document.
Definition: generator.cpp:328
Okular::Document::undo
void undo()
Undo last edit command.
Definition: document.cpp:3435
Okular::DocumentPrivate::saveDocumentInfo
void saveDocumentInfo() const
Definition: document.cpp:1186
foreachObserverD
#define foreachObserverD(cmd)
Definition: document.cpp:135
Okular::ScriptAction
The Script action executes a Script code.
Definition: action.h:387
Okular::Document::supportedMimeTypes
QStringList supportedMimeTypes() const
Returns the list with the supported MIME types.
Definition: document.cpp:3950
Okular::Generator::InvalidPrinterStatePrintError
Definition: generator.h:358
Okular::AnnotationProxy
Native annotation interface.
Definition: annotations.h:686
chooseenginedialog_p.h
Okular::Generator::FontInfo
Whether the Generator can provide information about the fonts used in the document.
Definition: generator.h:204
Okular::DocumentPrivate::doContinueGooglesDocumentSearch
void doContinueGooglesDocumentSearch(void *pagesToNotifySet, void *pageMatchesMap, int currentPage, int searchID, const QStringList &words, int caseSensitivity, const QColor &color, bool matchAll)
Definition: document.cpp:1817
page_p.h
Okular::DocumentViewport::enabled
bool enabled
Definition: document.h:1051
Okular::ScriptAction::script
QString script() const
Returns the code.
Definition: action.cpp:410
Okular::Document::SearchType
SearchType
Describes the possible search types.
Definition: document.h:469
Okular::Document::SaveCapability
SaveCapability
Saving capabilities.
Definition: document.h:616
Okular::DocumentPrivate::m_exportCached
bool m_exportCached
Definition: document_p.h:234
Okular::Annotation::ALine
A line annotation.
Definition: annotations.h:108
Okular::AllowNotes
Allows to add annotations to the document.
Definition: global.h:25
Okular::DocumentInfo::getKeyTitle
static QString getKeyTitle(Key key)
Returns the user visible string for the given key.
Definition: document.cpp:4726
Okular::EmbeddedFile::~EmbeddedFile
virtual ~EmbeddedFile()
Destroys the embedded file.
Definition: document.cpp:4803
Okular::Document::processRenditionAction
void processRenditionAction(const Okular::RenditionAction *action)
This signal is emitted whenever an rendition action is triggered and the UI should process it...
Okular::Generator::PrintPostscript
Whether the Generator supports postscript-based file printing.
Definition: generator.h:207
QObject
Okular::Page::hasTextPage
bool hasTextPage() const
Returns whether the page provides a text page (TextPage).
Definition: page.cpp:244
Okular::BrowseAction::url
QString url() const
Returns the url to browse.
Definition: action.cpp:219
Okular::Generator::Points
The page size is given in 1/72 inches.
Definition: generator.h:311
Okular::Rotation0
Not rotated.
Definition: global.h:46
Okular::EditAnnotationContentsCommand
Definition: documentcommands_p.h:140
Okular::Annotation::setContents
void setContents(const QString &contents)
Sets the contents of the annotation.
Definition: annotations.cpp:539
Okular::Tile
This class represents a rectangular portion of a page.
Definition: tile.h:25
Okular::ExecuteAction
The Execute action executes an external application.
Definition: action.h:181
Okular::JavaScript
JavaScript code.
Definition: global.h:78
Okular::DocumentPrivate::documentMetaData
QVariant documentMetaData(const QString &key, const QVariant &option) const
Request a particular metadata of the Document itself (ie, not something depending on the document typ...
Definition: document.cpp:1938
Okular::View::CapabilityRead
Possibility to read a capability.
Definition: view.h:55
Okular::TextAnnotation::textType
TextType textType() const
Returns the text type of the text annotation.
Definition: annotations.cpp:1024
Okular::DocumentPrivate::m_bookmarkManager
BookmarkManager * m_bookmarkManager
Definition: document_p.h:239
Okular::Document::SaveAnnotationsCapability
Can save annotation changes.
Definition: document.h:619
page.h
Okular::Document::openDocument
bool openDocument(const QString &docFile, const KUrl &url, const KMimeType::Ptr &mime)
Opens the document.
Definition: document.cpp:2060
Okular::DocumentPrivate::m_pagesVector
QVector< Page * > m_pagesVector
Definition: document_p.h:249
Okular::LineAnnotation
Definition: annotations.h:856
Okular::FromTop
Searching from top of the page, next result is to be found, there was no earlier search result...
Definition: global.h:35
Okular::Document::canUndoChanged
void canUndoChanged(bool undoAvailable)
This signal is emmitted whenever the availability of the undo function changes.
Okular::Document::setNextViewport
void setNextViewport()
Sets the current document viewport to the previous viewport in the viewport history.
Definition: document.cpp:3208
observer.h
Okular::DocumentInfo::Key
Key
The list of predefined keys.
Definition: document.h:1079
Okular::View::ZoomModality
Possibility to get/set the zoom mode of the view.
Definition: view.h:46
Okular::Document::stopFontReading
void stopFontReading()
Force the termination of the reading of the information about the fonts in the document, if running.
Definition: document.cpp:2598
Okular::PixmapRequest::setNormalizedRect
void setNormalizedRect(const NormalizedRect &rect)
Sets the region of the page to request.
Definition: generator.cpp:494
Okular::PixmapRequestPrivate::mPage
Page * mPage
Definition: generator_p.h:83
Okular::Document::printError
QString printError() const
Returns the last print error in case print() failed.
Definition: document.cpp:3864
Okular::PixmapRequest::height
int height() const
Returns the page height of the requested pixmap.
Definition: generator.cpp:459
Okular::Document::isOpened
bool isOpened() const
Returns whether the document is currently opened.
Definition: document.cpp:2513
Okular::FormFieldText
Interface of a text form field.
Definition: form.h:176
Okular::DocumentPrivate::m_generatorName
QString m_generatorName
Definition: document_p.h:247
Okular::Document::rotation
Rotation rotation() const
Returns the current rotation of the document.
Definition: document.cpp:2751
Okular::DocumentPrivate::getFreeMemory
qulonglong getFreeMemory(qulonglong *freeSwap=0)
Definition: document.cpp:484
Okular::DocumentPrivate::m_fontThread
QPointer< FontExtractionThread > m_fontThread
Definition: document_p.h:263
Okular::DocumentInfo::Title
The title of the document.
Definition: document.h:1080
Okular::FromBottom
Searching from bottom of the page, next result is to be found, there was no earlier search result...
Definition: global.h:36
Okular::Document::removeObserver
void removeObserver(DocumentObserver *observer)
Unregisters the given observer for the document.
Definition: document.cpp:2444
Okular::VisiblePageRect::VisiblePageRect
VisiblePageRect(int pageNumber=-1, const NormalizedRect &rectangle=NormalizedRect())
Creates a new visible page rectangle.
Definition: document.cpp:4807
Okular::ExportFormat::List
QList< ExportFormat > List
Definition: generator.h:78
Okular::DocumentPrivate::m_annotationEditingEnabled
bool m_annotationEditingEnabled
Definition: document_p.h:270
Okular::Document::canRedoChanged
void canRedoChanged(bool redoAvailable)
This signal is emmitted whenever the availability of the redo function changes.
Okular::Generator::Threaded
Definition: generator.h:201
Okular::DocumentAction::HistoryForward
Go forward in page history.
Definition: action.h:279
Okular::EditFormButtonsCommand
Definition: documentcommands_p.h:232
Okular::DocumentPrivate::m_archivedFileName
QString m_archivedFileName
Definition: document_p.h:261
Okular::Document::Document
Document(QWidget *widget)
Creates a new document with the given widget as widget to relay GUI things (messageboxes, ...).
Definition: document.cpp:2002
Okular::PageController
Definition: pagecontroller_p.h:26
Okular::Document::canProvideFontInformation
bool canProvideFontInformation() const
Whether the current document can provide information about the fonts used in it.
Definition: document.cpp:2609
Okular::DocumentSynopsis::DocumentSynopsis
DocumentSynopsis()
Creates a new document synopsis object.
Definition: document.cpp:4786
Okular::GotoAction::fileName
QString fileName() const
Returns the filename of the external document.
Definition: action.cpp:116
Okular::Page::height
double height() const
Returns the height of the page.
Definition: page.cpp:185
Okular::DocumentPrivate::canAddAnnotationsNatively
bool canAddAnnotationsNatively() const
Definition: document.cpp:3042
Okular::DocumentPrivate::m_scripter
Scripter * m_scripter
Definition: document_p.h:258
Okular::Document::linkGoToPage
void linkGoToPage()
This signal is emitted whenever an action requests a goto operation.
Okular::Document::PrintingType
PrintingType
What type of printing a document supports.
Definition: document.h:553
Okular::Document::printConfigurationWidget
QWidget * printConfigurationWidget() const
Returns a custom printer configuration page or 0 if no custom printer configuration page is available...
Definition: document.cpp:3901
Okular::DocumentObserver::notifyViewportChanged
virtual void notifyViewportChanged(bool smoothMove)
This method is called whenever the viewport has been changed.
Definition: observer.cpp:27
Okular::DocumentPrivate::m_searches
QMap< int, RunningSearch * > m_searches
Definition: document_p.h:191
Okular::PreviousResult
Searching for the previous result on the page, earlier result should be located so we search from the...
Definition: global.h:38
Okular::Document::page
const Page * page(int number) const
Returns the page object for the given page number or 0 if the number is out of range.
Definition: document.cpp:2619
Okular::GotoAction::isExternal
bool isExternal() const
Returns whether the goto action points to an external document.
Definition: action.cpp:110
Okular::Document::~Document
~Document()
Destroys the document.
Definition: document.cpp:2018
Okular::Generator::exportFormats
virtual ExportFormat::List exportFormats() const
Returns the list of additional supported export formats.
Definition: generator.cpp:334
Okular::DocumentObserver::NeedSaveAs
Set along with Annotations when Save As is needed or annotation changes will be lost.
Definition: observer.h:48
Okular::DocumentPrivate::saveViewsInfo
void saveViewsInfo(View *view, QDomElement &e) const
Definition: document.cpp:752
Okular::DocumentPrivate::generatorSave
SaveInterface * generatorSave(GeneratorInfo &info)
Definition: document.cpp:878
Okular::View::capabilityFlags
virtual CapabilityFlags capabilityFlags(ViewCapability capability) const
Query the flags for the specified capability.
Definition: view.cpp:60
Okular::DocumentInfo::get
QString get(const QString &key) const
Returns the value for a given key or an empty string when the key doesn't exist.
Definition: document.cpp:4657
Okular::ConfigInterface
Abstract interface for configuration control.
Definition: configinterface.h:38
Okular::DocumentPrivate::m_exportToText
ExportFormat m_exportToText
Definition: document_p.h:236
Okular::RenditionAction::script
QString script() const
Returns the script code.
Definition: action.cpp:544
Okular::Document::linkFind
void linkFind()
This signal is emitted whenever an action requests a find operation.
Okular::TilesManager::tilesAt
QList< Tile > tilesAt(const NormalizedRect &rect, TileLeaf tileLeaf)
Returns a list of all tiles intersecting with rect.
Definition: tilesmanager.cpp:358
Okular::FontInfo
A small class that represents the information of a font.
Definition: fontinfo.h:27
Okular::Annotation::AGeom
A geometrical annotation.
Definition: annotations.h:109
Okular::TranslateAnnotationCommand
Definition: documentcommands_p.h:79
Okular::AnnotationProxy::Modification
Generator can edit native annotations.
Definition: annotations.h:692
Okular::DocumentPrivate::performSetAnnotationContents
void performSetAnnotationContents(const QString &newContents, Annotation *annot, int pageNumber)
Definition: document.cpp:1150
Okular::FormFieldChoice::editChoice
virtual QString editChoice() const
The text entered into an editable combo box choice field.
Definition: form.cpp:242
view.h
Okular::Page::setBoundingBox
void setBoundingBox(const NormalizedRect &bbox)
Sets the bounding box of the page content in normalized [0,1] coordinates, in terms of the upright or...
Definition: page.cpp:205
Okular::DocumentInfo::CreationDate
The date of creation of the document.
Definition: document.h:1088
Okular::DoContinueDirectionMatchSearchStruct::searchID
int searchID
Definition: document_p.h:74
Okular::TilesManager::setRequest
void setRequest(const NormalizedRect &rect, int pageWidth, int pageHeight)
Sets a region to be requested so the tiles manager knows which pixmaps to expect and discard those no...
Definition: tilesmanager.cpp:539
Okular::Document::isAllowed
bool isAllowed(Permission action) const
Returns whether the given action is allowed in the document.
Definition: document.cpp:2662
Okular::Document::setVisiblePageRects
void setVisiblePageRects(const QVector< VisiblePageRect * > &visiblePageRects, DocumentObserver *excludeObserver=0)
Sets the list of visible page rectangles.
Definition: document.cpp:2634
Okular::Document::documentInfo
const DocumentInfo * documentInfo() const
Returns the meta data of the document or 0 if no meta data are available.
Definition: document.cpp:2529
Okular::Document::SearchStatus
SearchStatus
Describes how search ended.
Definition: document.h:481
Okular::Generator::NoPrintError
There was no print error.
Definition: generator.h:351
Okular::EmbeddedFile::EmbeddedFile
EmbeddedFile()
Creates a new embedded file.
Definition: document.cpp:4799
Okular::PixmapRequest::width
int width() const
Returns the page width of the requested pixmap.
Definition: generator.cpp:454
Okular::Annotation::subType
virtual SubType subType() const =0
Returns the sub type of the annotation.
Okular::Annotation::getAnnotationPropertiesDomNode
QDomNode getAnnotationPropertiesDomNode() const
Retrieve the QDomNode representing this annotation's properties.
Definition: annotations.cpp:801
Okular::Generator::PrintingProcessCrashPrintError
Definition: generator.h:355
Okular::TilesManager
Tiles management.
Definition: tilesmanager_p.h:98
Okular::Document::NoMatchFound
No match was found.
Definition: document.h:484
Okular::DocumentAction::PageNext
Jump to next page.
Definition: action.h:276
Okular::PixmapRequest::observer
DocumentObserver * observer() const
Returns the observer of the request.
Definition: generator.cpp:444
Okular::GuiInterface::guiClient
KXMLGUIClient * guiClient()
This method requests the XML GUI Client provided by the interface.
Definition: guiinterface.h:50
action.h
annotations.h
Okular::FormFieldChoice
Interface of a choice form field.
Definition: form.h:258
Okular::DocumentObserver::BoundingBox
Bounding boxes have been changed.
Definition: observer.h:47
Okular::Document::GoogleAll
Search all words in google style.
Definition: document.h:474
Okular::Document::removePageAnnotation
void removePageAnnotation(int page, Annotation *annotation)
Removes the given annotation from the given page.
Definition: document.cpp:3025
Okular::DocumentInfo::DocumentInfo
DocumentInfo()
Creates a new document info.
Definition: document.cpp:4621
Okular::Document::setRotation
void setRotation(int rotation)
This slot is called whenever the user changes the rotation of the document.
Definition: document.cpp:4426
Okular::Document::removePageAnnotations
void removePageAnnotations(int page, const QList< Annotation * > &annotations)
Removes the given annotations from the given page.
Definition: document.cpp:3031
Okular::Annotation::External
Is stored external.
Definition: annotations.h:134
Okular::SourceReference::fileName
QString fileName() const
Returns the filename of the source.
Definition: sourcereference.cpp:45
Okular::Annotation::flags
int flags() const
Returns the flags of the annotation.
Definition: annotations.cpp:593
GeneratorInfo::saveChecked
bool saveChecked
Definition: document_p.h:61
Okular::Document::pageSizeString
QString pageSizeString(int page) const
Returns the size string for the given page or an empty string if the page is out of range...
Definition: document.cpp:2773
Okular::DocumentObserver::notifySetup
virtual void notifySetup(const QVector< Okular::Page * > &pages, int setupFlags)
This method is called whenever the document is initialized or reconstructed.
Definition: observer.cpp:23
Okular::Document::redo
void redo()
Redo last undone edit command.
Definition: document.cpp:3440
Okular::DoContinueDirectionMatchSearchStruct::match
RegularAreaRect * match
Definition: document_p.h:72
documentcommands_p.h
OkularDebug
#define OkularDebug
Definition: debug_p.h:13
Okular::Document::bookmarkedPageRange
QString bookmarkedPageRange() const
Returns the range of the bookmarked.pages.
Definition: document.cpp:3514
Okular::GotoAction
The Goto action changes the viewport to another page or loads an external document.
Definition: action.h:115
Okular::PagePrivate::m_pixmaps
QMap< DocumentObserver *, PixmapObject > m_pixmaps
Definition: page_p.h:119
Okular::Document::saveDocumentArchive
bool saveDocumentArchive(const QString &fileName)
Saves a document archive.
Definition: document.cpp:4180
Okular::Page::boundingBox
NormalizedRect boundingBox() const
Returns the bounding box of the page content in normalized [0,1] coordinates, in terms of the upright...
Definition: page.cpp:195
GeneratorInfo::save
Okular::SaveInterface * save
Definition: document_p.h:59
Okular::GotoAction::destViewport
DocumentViewport destViewport() const
Returns the document viewport the goto action points to.
Definition: action.cpp:122
Okular::Document::fontReadingProgress
void fontReadingProgress(int page)
Reports the progress when reading the fonts in the document.
Okular::Document::canUndo
bool canUndo() const
Returns true if there is an undo command available; otherwise returns false.
Definition: document.cpp:3091
Okular::DocumentPrivate::fontReadingGotFont
void fontReadingGotFont(const Okular::FontInfo &font)
Definition: document.cpp:1497
Okular::Document
The Document.
Definition: document.h:84
Okular::Document::setZoom
void setZoom(int factor, DocumentObserver *excludeObserver=0)
Sets the zoom for the current document.
Definition: document.cpp:3183
Okular::Page
Collector for all the data belonging to a page.
Definition: page.h:49
Okular::AllPageItems
Definition: page_p.h:47
Okular::TilesManager::markDirty
void markDirty()
Mark all tiles as dirty.
Definition: tilesmanager.cpp:170
Okular::PrintInterface::printConfigurationWidget
virtual QWidget * printConfigurationWidget() const =0
Builds and returns a new printing configuration widget.
Okular::Document::closeDocument
void closeDocument()
Closes the document.
Definition: document.cpp:2294
Okular::Document::setPageSize
void setPageSize(const PageSize &size)
This slot is called whenever the user changes the page size of the document.
Definition: document.cpp:4458
Okular::TextAnnotation::InPlace
The annotation is located next to the text.
Definition: annotations.h:740
Okular::Page::width
double width() const
Returns the width of the page.
Definition: page.cpp:180
Okular::DocumentPrivate::openRelativeFile
bool openRelativeFile(const QString &fileName)
Definition: document.cpp:786
Okular::DocumentObserver::notifyVisibleRectsChanged
virtual void notifyVisibleRectsChanged()
This method is called whenever the visible rects have been changed.
Definition: observer.cpp:39
form.h
Okular::DocumentPrivate::m_observers
QSet< DocumentObserver * > m_observers
Definition: document_p.h:212
Okular::PagePrivate::rotationMatrix
QTransform rotationMatrix() const
Definition: page.cpp:119
document.h
Okular::Document::bookmarkedPageList
QList< int > bookmarkedPageList() const
Returns a list of the bookmarked.pages.
Definition: document.cpp:3498
Okular::DocumentPrivate::canModifyExternalAnnotations
bool canModifyExternalAnnotations() const
Definition: document.cpp:3053
Okular::DoContinueDirectionMatchSearchStruct::noDialogs
bool noDialogs
Definition: document_p.h:79
Okular::Annotation::AInk
An ink annotation.
Definition: annotations.h:112
Okular::DocumentPrivate::m_loadedGenerators
QHash< QString, GeneratorInfo > m_loadedGenerators
Definition: document_p.h:245
Okular::DocumentPrivate::m_prevPropsOfAnnotBeingModified
QDomNode m_prevPropsOfAnnotBeingModified
Definition: document_p.h:276
Okular::Document::widget
QWidget * widget() const
Returns the widget to be used for relaying GUI things (messageboxes, ...)
Definition: document.cpp:2508
Okular::Generator::generateDocumentInfo
virtual const DocumentInfo * generateDocumentInfo()
Returns the general information object of the document or 0 if no information are available...
Definition: generator.cpp:275
Okular::DocumentPrivate::getTotalMemory
qulonglong getTotalMemory()
Definition: document.cpp:448
Okular::FormFieldChoice::choices
virtual QStringList choices() const =0
The possible choices of the choice field.
tile.h
Okular::Annotation::AHighlight
A highlight annotation.
Definition: annotations.h:110
Okular::Action::Goto
Goto a given page or external document.
Definition: action.h:50
Okular::SaveInterface
Abstract interface for saving.
Definition: saveinterface.h:39
Okular::PagePrivate::m_doc
DocumentPrivate * m_doc
Definition: page_p.h:126
Okular::DocumentViewport::operator<
bool operator<(const DocumentViewport &other) const
Definition: document.cpp:4599
Okular::DocumentPrivate::openDocumentInternal
bool openDocumentInternal(const KService::Ptr &offer, bool isstdin, const QString &docFile, const QByteArray &filedata)
Definition: document.cpp:888
Okular::DocumentViewport::DocumentViewport
DocumentViewport(int number=-1)
Creates a new viewport for the given page number.
Definition: document.cpp:4491
Okular::DocumentPrivate::m_docSize
qint64 m_docSize
Definition: document_p.h:203
Okular::Page::findText
RegularAreaRect * findText(int id, const QString &text, SearchDirection direction, Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *lastRect=0) const
Returns the bounding rect of the text which matches the following criteria or 0 if the search is not ...
Definition: page.cpp:304
Okular::GotoAction::destinationName
QString destinationName() const
Returns the document named destination the goto action points to.
Definition: action.cpp:128
Okular::Page::removeAnnotation
bool removeAnnotation(Annotation *annotation)
Removes the annotation from the page.
Definition: page.cpp:661
Okular::Rotation270
Rotated 2700 degrees clockwise.
Definition: global.h:49
Okular::Generator::PageSizes
Whether the Generator can change the size of the document pages.
Definition: generator.h:205
Okular::Document::visiblePageRects
const QVector< VisiblePageRect * > & visiblePageRects() const
Returns the list of visible page rectangles.
Definition: document.cpp:2629
Okular::Document::processMovieAction
void processMovieAction(const Okular::MovieAction *action)
This signal is emitted whenever an movie action is triggered and the UI should process it...
Okular::DocumentPrivate::m_tempFile
KTemporaryFile * m_tempFile
Definition: document_p.h:202
Okular::RenditionAction::scriptType
ScriptType scriptType() const
Returns the type of script.
Definition: action.cpp:538
Okular::Document::PostscriptPrinting
Postscript file printing.
Definition: document.h:557
Okular::DocumentPrivate::m_fontsCache
FontInfo::List m_fontsCache
Definition: document_p.h:266
Okular::DoContinueDirectionMatchSearchStruct::pagesToNotify
QSet< int > * pagesToNotify
Definition: document_p.h:71
Okular::RemoveAnnotationCommand
Definition: documentcommands_p.h:45
Okular::NormalizedRect::geometry
QRect geometry(int xScale, int yScale) const
Returns the rectangle that accrues when the normalized rectangle is multiplyed with the scaling xScal...
Definition: area.cpp:239
Okular::DocumentPrivate::m_generator
Generator * m_generator
Definition: document_p.h:246
Okular::Document::canModifyPageAnnotation
bool canModifyPageAnnotation(const Annotation *annotation) const
Tests if the annotation can be modified.
Definition: document.cpp:2929
Okular::DocumentViewport::pageNumber
int pageNumber
The number of the page nearest the center of the viewport.
Definition: document.h:1035
Okular::PrintInterface
Abstract interface for advanced printing control.
Definition: printinterface.h:39
Okular::PagePrivate::setTextSelections
void setTextSelections(RegularAreaRect *areas, const QColor &color)
Sets the color and areas of text selections.
Definition: page.cpp:591
Okular::Document::searchFinished
void searchFinished(int id, Okular::Document::SearchStatus endStatus)
Reports that the current search finished.
Okular::Document::componentData
const KComponentData * componentData() const
Returns the component data associated with the generator.
Definition: document.cpp:3971
Okular::Document::PreviousMatch
Search previous match.
Definition: document.h:472
Okular::DocumentViewport::rePos
struct Okular::DocumentViewport::@0 rePos
If 'rePos.enabled == true' then this structure contains the viewport center or top left depending on ...
Okular::Annotation::ExternallyDrawn
Is drawn externally (by the generator which provided it)
Definition: annotations.h:135
Okular::DocumentPrivate::rotationFinished
void rotationFinished(int page, Okular::Page *okularPage)
Definition: document.cpp:1475
Okular::Document::printingSupport
PrintingType printingSupport() const
Returns what sort of printing the document supports: Native, Postscript, None.
Definition: document.cpp:3832
Okular::Document::supportsPageSizes
bool supportsPageSizes() const
Returns whether the document supports the listing of page sizes.
Definition: document.cpp:2680
Okular::Page::annotations
QLinkedList< Annotation * > annotations() const
Returns the list of annotations of the page.
Definition: page.cpp:492
Okular::DocumentPrivate::m_pageSize
PageSize m_pageSize
Definition: document_p.h:230
Okular::PixmapRequest::asynchronous
bool asynchronous() const
Returns whether the generation should be done synchronous or asynchronous.
Definition: generator.cpp:469
Okular::Generator::TemporaryFileOpenPrintError
Definition: generator.h:353
Okular::DocumentPrivate::namePaperSize
QString namePaperSize(double inchesWidth, double inchesHeight) const
Definition: document.cpp:159
Okular::DocumentInfo::Keywords
The keywords which describe the content of the document.
Definition: document.h:1092
Okular::DocumentPrivate::nextDocumentViewport
DocumentViewport nextDocumentViewport() const
Definition: document.cpp:1002
Okular::Document::documentSynopsis
const DocumentSynopsis * documentSynopsis() const
Returns the table of content of the document or 0 if no table of content is available.
Definition: document.cpp:2567
sourcereference.h
Okular::Generator::PrintNative
Whether the Generator supports native cross-platform printing (QPainter-based).
Definition: generator.h:206
Okular::Generator::FileConversionPrintError
Definition: generator.h:354
Okular::TilesManager::width
int width() const
Gets the width of the page in tiles manager.
Definition: tilesmanager.cpp:147
Okular::Generator::hasFeature
bool hasFeature(GeneratorFeature feature) const
Query for the specified feature.
Definition: generator.cpp:344
Okular::DocumentPrivate::unloadGenerator
void unloadGenerator(const GeneratorInfo &info)
Definition: document.cpp:846
Okular::Document::viewport
const DocumentViewport & viewport() const
Returns the current viewport of the document.
Definition: document.cpp:2624
Okular::DocumentObserver::notifyCurrentPageChanged
virtual void notifyCurrentPageChanged(int previous, int current)
This method is called after the current page of the document has been entered.
Definition: observer.cpp:52
Okular::DocumentPrivate
Definition: document_p.h:83
Okular::AudioPlayerPrivate::m_currentDocument
KUrl m_currentDocument
Definition: audioplayer_p.h:44
Okular::PixmapRequest::preload
bool preload() const
Returns whether the generation request is for a page that is not important i.e.
Definition: generator.cpp:474
Okular::Action
Encapsulates data that describes an action.
Definition: action.h:43
Okular::Document::SaveFormsCapability
Can save form changes.
Definition: document.h:618
Okular::DocumentInfo
A DOM tree containing information about the document.
Definition: document.h:1073
Okular::Document::editFormCombo
void editFormCombo(int pageNumber, Okular::FormFieldChoice *form, const QString &newText, int newCursorPos, int prevCursorPos, int prevAnchorPos)
Set the active choice in the combo box form on page page to newText The new cursor position (newCurso...
Definition: document.cpp:3465
Okular::AudioPlayer::playSound
void playSound(const Sound *sound, const SoundAction *linksound=0)
Enqueue the specified sound for playing, optionally taking more information about the playing from th...
Definition: audioplayer.cpp:225
Okular::Document::metaData
QVariant metaData(const QString &key, const QVariant &option=QVariant()) const
Returns the meta data for the given key and option or an empty variant if the key doesn't exists...
Definition: document.cpp:2746
Okular::copyQIODevice
void copyQIODevice(QIODevice *from, QIODevice *to)
Definition: utils.cpp:250
Okular::PixmapRequest::priority
int priority() const
Returns the priority (less it better, 0 is maximum) of the request.
Definition: generator.cpp:464
Okular::DocumentObserver::notifyZoom
virtual void notifyZoom(int factor)
This method is called whenever the zoom of the document has been changed.
Definition: observer.cpp:43
Okular::DocumentPrivate::localizedSize
QString localizedSize(const QSizeF &size) const
Definition: document.cpp:260
view_p.h
Okular::Document::setPrevViewport
void setPrevViewport()
Sets the current document viewport to the next viewport in the viewport history.
Definition: document.cpp:3191
Okular::DocumentPrivate::m_showWarningLimitedAnnotSupport
bool m_showWarningLimitedAnnotSupport
Definition: document_p.h:273
Okular::SourceReference
Defines a source reference.
Definition: sourcereference.h:25
Okular::DoContinueDirectionMatchSearchStruct::color
QColor color
Definition: document_p.h:78
Okular::Document::editFormText
void editFormText(int pageNumber, Okular::FormFieldText *form, const QString &newContents, int newCursorPos, int prevCursorPos, int prevAnchorPos)
Edit the text contents of the specified form on page page to be newContents.
Definition: document.cpp:3445
Okular::DoContinueDirectionMatchSearchStruct::pagesDone
int pagesDone
Definition: document_p.h:80
ChooseEngineDialog
Definition: chooseenginedialog_p.h:20
Okular::DocumentPrivate::m_pageRects
QVector< VisiblePageRect * > m_pageRects
Definition: document_p.h:250
Okular::Generator::print
virtual bool print(QPrinter &printer)
This method is called to print the document to the given printer.
Definition: generator.cpp:318
Okular::Document::canRemovePageAnnotation
bool canRemovePageAnnotation(const Annotation *annotation) const
Tests if the annotation can be removed.
Definition: document.cpp:3003
Okular::DocumentPrivate::m_viewportIterator
QLinkedList< DocumentViewport >::iterator m_viewportIterator
Definition: document_p.h:207
Okular::DocumentObserver::DocumentChanged
The document is a new document.
Definition: observer.h:55
Okular::DocumentInfo::set
void set(const QString &key, const QString &value, const QString &title=QString())
Sets a value for a special key.
Definition: document.cpp:4628
Okular::SaveInterface::annotationProxy
virtual AnnotationProxy * annotationProxy() const =0
Returns the annotation proxy.
Okular::Document::cancelSearch
void cancelSearch()
Cancels the current search.
Definition: document.cpp:3430
Okular::Document::fontData
QByteArray fontData(const FontInfo &font) const
Gets the font data for the given font.
Definition: document.cpp:4072
Okular::TilesManager::totalMemory
qulonglong totalMemory() const
The total memory consumed by the tiles manager.
Definition: tilesmanager.cpp:444
Okular::DocumentViewport::normalizedX
double normalizedX
Definition: document.h:1052
Okular::TilesManager::setSize
void setSize(int width, int height)
Inform the new size of the page and mark all tiles to repaint.
Definition: tilesmanager.cpp:136
Okular::Document::linkPresentation
void linkPresentation()
This signal is emitted whenever an action requests a start presentation operation.
Okular::SaveInterface::SaveChanges
The possibility to save with the current changes to the document.
Definition: saveinterface.h:48
Okular::Document::processSourceReference
void processSourceReference(const SourceReference *reference)
Processes/Executes the given source reference.
Definition: document.cpp:3761
Okular::PagePrivate::setTilesManager
void setTilesManager(TilesManager *tm)
Definition: page.cpp:1019
Okular::DocumentPrivate::performRemovePageAnnotation
void performRemovePageAnnotation(int page, Annotation *annotation)
Definition: document.cpp:1068
Okular::EditFormListCommand
Definition: documentcommands_p.h:185
Okular::Document::setNextDocumentViewport
void setNextDocumentViewport(const DocumentViewport &viewport)
Sets the next viewport in the viewport history.
Definition: document.cpp:3227
Okular::Document::setAnnotationEditingEnabled
void setAnnotationEditingEnabled(bool enable)
Control annotation editing (creation, modification and removal), which is enabled by default...
Definition: document.cpp:4288
Okular::Generator::loadDocumentFromData
virtual bool loadDocumentFromData(const QByteArray &fileData, QVector< Page * > &pagesVector)
Loads the document from the raw data fileData and fills the pagesVector with the parsed pages...
Definition: generator.cpp:176
Okular::Rotation90
Rotated 90 degrees clockwise.
Definition: global.h:47
Okular::DocumentPrivate::m_undoStack
QUndoStack * m_undoStack
Definition: document_p.h:275
document_p.h
OKULAR_HISTORY_MAXSTEPS
#define OKULAR_HISTORY_MAXSTEPS
Definition: document.cpp:139
Okular::EditFormComboCommand
Definition: documentcommands_p.h:206
Okular::Action::Movie
Play a movie.
Definition: action.h:55
Okular::DocumentInfo::Pages
The number of pages of the document.
Definition: document.h:1087
Okular::DocumentPrivate::giveAbsolutePath
QString giveAbsolutePath(const QString &fileName) const
Definition: document.cpp:775
Okular::Generator::None
The page size is not defined in a physical metric.
Definition: generator.h:310
Okular::Document::guiClient
KXMLGUIClient * guiClient()
Returns the gui client of the generator, if it provides one.
Definition: document.cpp:2283
Okular::DocumentPrivate::textGenerationDone
void textGenerationDone(Page *page)
Definition: document.cpp:4408
Okular::Document::historyAtBegin
bool historyAtBegin() const
Returns whether the document history is at the begin.
Definition: document.cpp:2736
Okular::Document::configurableGenerators
int configurableGenerators() const
Returns the number of generators that have a configuration widget.
Definition: document.cpp:3943
Okular::DocumentPrivate::calculateMaxTextPages
void calculateMaxTextPages()
Definition: document.cpp:4385
Okular::DocumentViewport::normalizedY
double normalizedY
Definition: document.h:1053
Okular::Tile::rect
NormalizedRect rect() const
Location of the tile.
Definition: tilesmanager.cpp:696
Okular::Document::exportTo
bool exportTo(const QString &fileName, const ExportFormat &format) const
Exports the document in the given format and saves it under fileName.
Definition: document.cpp:2731
Okular::DocumentPrivate::m_views
QSet< View * > m_views
Definition: document_p.h:268
Okular::DocumentPrivate::canRemoveExternalAnnotations
bool canRemoveExternalAnnotations() const
Definition: document.cpp:3064
Okular::DocumentInfo::DocumentSize
The size of the document.
Definition: document.h:1094
Okular::DocumentObserver::notifyPageChanged
virtual void notifyPageChanged(int page, int flags)
This method is called whenever the content on page described by the passed flags has been changed...
Definition: observer.cpp:31
guiinterface.h
Okular::TilesManager::TerminalTile
Return tiles without children.
Definition: tilesmanager_p.h:103
Okular::ExportFormat
Defines an entry for the export menu.
Definition: generator.h:75
Okular::DocumentInfo::Creator
The creator of the document (this can be different from the author)
Definition: document.h:1084
Okular::Annotation
Annotation struct holds properties shared by all annotations.
Definition: annotations.h:90
Okular::NormalizedRect::isNull
bool isNull() const
Returns whether this normalized rectangle is a null normalized rect.
Definition: area.cpp:151
Okular::Document::fontReadingEnded
void fontReadingEnded()
Reports that the reading of the fonts in the document is finished.
Okular::FormFieldChoice::currentChoices
virtual QList< int > currentChoices() const =0
The currently selected choices.
Okular::Generator::PrintingProcessStartPrintError
Definition: generator.h:356
Okular::DocumentPrivate::m_saveBookmarksTimer
QTimer * m_saveBookmarksTimer
Definition: document_p.h:243
Okular::PageSize
A small class that represents the size of a page.
Definition: pagesize.h:26
Okular::View::Zoom
Possibility to get/set the zoom of the view.
Definition: view.h:45
Okular::Generator::PrintToFilePrintError
Definition: generator.h:357
Okular::Document::canExportToText
bool canExportToText() const
Returns whether the document supports the export to ASCII text.
Definition: document.cpp:2701
Okular::DocumentPrivate::m_allocatedPixmaps
QLinkedList< AllocatedPixmap * > m_allocatedPixmaps
Definition: document_p.h:219
Okular::Action::Script
Executes a Script code.
Definition: action.h:56
Okular::Generator::pageSizeChanged
virtual void pageSizeChanged(const PageSize &pageSize, const PageSize &oldPageSize)
This method is called when the page size has been changed by the user.
Definition: generator.cpp:314
Okular::DocumentPrivate::m_memCheckTimer
QTimer * m_memCheckTimer
Definition: document_p.h:242
Okular::DocumentObserver::NewLayoutForPages
All the pages have.
Definition: observer.h:56
Okular::Document::allPagesSize
QSizeF allPagesSize() const
If all pages have the same size this method returns it, if the page sizes differ an empty size object...
Definition: document.cpp:2756
Okular::DocumentPrivate::slotGeneratorConfigChanged
void slotGeneratorConfigChanged(const QString &)
Definition: document.cpp:1505
Okular::DocumentPrivate::m_xmlFileName
QString m_xmlFileName
Definition: document_p.h:201
Okular::Action::Rendition
Play a movie and/or execute a Script code.
Definition: action.h:57
Okular::ScriptAction::scriptType
ScriptType scriptType() const
Returns the type of action.
Definition: action.cpp:404
Okular::Generator::PrintError
PrintError
Possible print errors.
Definition: generator.h:349
Okular::View::CapabilitySerializable
The capability is suitable for being serialized/deserialized.
Definition: view.h:57
Okular::SaveInterface::save
virtual bool save(const QString &fileName, SaveOptions options, QString *errorText)=0
Save to the specified fileName with the specified options.
Okular::DocumentPrivate::performModifyPageAnnotation
void performModifyPageAnnotation(int page, Annotation *annotation, bool appearanceChanged)
Definition: document.cpp:1106
Okular::DocumentPrivate::searchLowestPriorityPixmap
AllocatedPixmap * searchLowestPriorityPixmap(bool unloadableOnly=false, bool thenRemoveIt=false, DocumentObserver *observer=0)
Definition: document.cpp:413
Okular::Document::searchText
void searchText(int searchID, const QString &text, bool fromStart, Qt::CaseSensitivity caseSensitivity, SearchType type, bool moveViewport, const QColor &color, bool noDialogs=false)
Searches the given text in the document.
Definition: document.cpp:3237
Okular::DocumentInfo::PagesSize
The size of the pages (if all pages have the same size)
Definition: document.h:1095
Okular::DocumentAction::PageFirst
Jump to first page.
Definition: action.h:274
printinterface.h
Okular::ExecuteAction::parameters
QString parameters() const
Returns the parameters of the application to execute.
Definition: action.cpp:174
Okular::Document::historyAtEnd
bool historyAtEnd() const
Returns whether the document history is at the end.
Definition: document.cpp:2741
Okular::DocumentPrivate::requestDone
void requestDone(PixmapRequest *request)
This method is used by the generators to signal the finish of the pixmap generation request...
Definition: document.cpp:4294
Okular::SoundAction::sound
Okular::Sound * sound() const
Returns the sound object which contains the sound data.
Definition: action.cpp:358
Okular::Document::gotFont
void gotFont(const Okular::FontInfo &font)
Emitted when a new font is found during the reading of the fonts of the document. ...
Okular::DoContinueDirectionMatchSearchStruct
Definition: document_p.h:68
Okular::DocumentObserver
Base class for objects being notified when something changes.
Definition: observer.h:28
Okular::Generator::generatePixmap
virtual void generatePixmap(PixmapRequest *request)
This method can be called to trigger the generation of a new pixmap as described by request...
Definition: generator.cpp:217
Okular::View::name
QString name() const
Return the name of this view.
Definition: view.cpp:49
Okular::TilesManager::setPixmap
void setPixmap(const QPixmap *pixmap, const NormalizedRect &rect)
Sets the pixmap of the tiles covered by rect (which represents the location of pixmap on the page)...
Definition: tilesmanager.cpp:188
Okular::DocumentAction::Quit
Quit application.
Definition: action.h:280
Okular::PixmapRequestPrivate::mPriority
int mPriority
Definition: generator_p.h:79
Okular::AudioPlayer::stopPlaybacks
void stopPlaybacks()
Tell the AudioPlayer to stop all the playbacks.
Definition: audioplayer.cpp:246
Okular::DocumentPrivate::warnLimitedAnnotSupport
void warnLimitedAnnotSupport()
Definition: document.cpp:1016
Okular::DocumentInfo::getKeyString
static QString getKeyString(Key key)
Returns the internal string for the given key.
Definition: document.cpp:4669
Okular::DocumentViewport::operator==
bool operator==(const DocumentViewport &other) const
Definition: document.cpp:4581
Okular::BrowseAction
The Browse action browses an url by opening a web browser or email client, depedning on the url proto...
Definition: action.h:226
Okular::PixmapRequest::isTile
bool isTile() const
Returns whether the generator should render just the region given by normalizedRect() or the entire p...
Definition: generator.cpp:489
Okular::SaveInterface::supportsOption
virtual bool supportsOption(SaveOption option) const =0
Query for the supported saving options.
utils_p.h
Okular::DocumentAction
The DocumentAction action contains an action that is performed on the current document.
Definition: action.h:265
Okular::Document::prepareToModifyAnnotationProperties
void prepareToModifyAnnotationProperties(Annotation *annotation)
Prepares to modify the properties of the given annotation.
Definition: document.cpp:2954
Okular::Document::setNextDocumentDestination
void setNextDocumentDestination(const QString &namedDestination)
Sets the next namedDestination in the viewport history.
Definition: document.cpp:3232
Okular::EditFormTextCommand
Definition: documentcommands_p.h:164
Okular::Document::openUrl
void openUrl(const KUrl &url)
This signal is emitted whenever an action requests an open url operation for the given document url...
Okular::DocumentPrivate::m_pixmapRequestsMutex
QMutex m_pixmapRequestsMutex
Definition: document_p.h:218
Okular::AnnotationPageItems
Definition: page_p.h:45
Okular::Document::editFormButtons
void editFormButtons(int pageNumber, const QList< Okular::FormFieldButton * > &formButtons, const QList< bool > &newButtonStates)
Set the states of the group of form buttons formButtons on page page to newButtonStates.
Definition: document.cpp:3487
Okular::DocumentObserver::Annotations
Annotations have been changed.
Definition: observer.h:46
Okular::Document::SearchCancelled
The search was cancelled.
Definition: document.h:485
Okular::TilesManager::isRequesting
bool isRequesting(const NormalizedRect &rect, int pageWidth, int pageHeight) const
Checks whether a given region has already been requested.
Definition: tilesmanager.cpp:534
Okular::Document::saveChanges
bool saveChanges(const QString &fileName)
Save the document and the optional changes to it to the specified fileName.
Definition: document.cpp:4019
Okular::ExecuteAction::fileName
QString fileName() const
Returns the file name of the application to execute.
Definition: action.cpp:168
Okular::DocumentPrivate::generatorConfig
ConfigInterface * generatorConfig(GeneratorInfo &info)
Definition: document.cpp:868
Okular::Generator::NoBinaryToPrintError
Definition: generator.h:361
Okular::Generator::TiledRendering
Whether the Generator can render tiles.
Definition: generator.h:209
Okular::Document::supportsTiles
bool supportsTiles() const
Returns whether the current document supports tiles.
Definition: document.cpp:2685
Okular::Document::registerView
void registerView(View *view)
Register the specified view for the current document.
Definition: document.cpp:4040
Okular::View::capability
virtual QVariant capability(ViewCapability capability) const
Query the value of the specified capability.
Definition: view.cpp:66
Okular::Permission
Permission
Describes the DRM capabilities.
Definition: global.h:20
Okular::Document::canRedo
bool canRedo() const
Returns true if there is a redo command available; otherwise returns false.
Definition: document.cpp:3096
Okular::DocumentPrivate::m_rotation
Rotation m_rotation
Definition: document_p.h:226
Okular::DocumentPrivate::m_closingLoop
QEventLoop * m_closingLoop
Definition: document_p.h:256
Okular::DoContinueDirectionMatchSearchStruct::moveViewport
bool moveViewport
Definition: document_p.h:77
Okular::DocumentPrivate::m_docFileName
QString m_docFileName
Definition: document_p.h:200
Okular::DocumentViewport
A view on the document.
Definition: document.h:1003
Okular::Generator::UnableToFindFilePrintError
Definition: generator.h:359
Okular::Document::addPageAnnotation
void addPageAnnotation(int page, Annotation *annotation)
Adds a new annotation to the given page.
Definition: document.cpp:2919
Okular::DocumentPrivate::pagesSizeString
QString pagesSizeString() const
Definition: document.cpp:144
Okular::extractLilyPondSourceReference
bool extractLilyPondSourceReference(const QString &url, QString *file, int *row, int *col)
Definition: sourcereference.cpp:60
Okular::Document::addObserver
void addObserver(DocumentObserver *observer)
Registers a new observer for the document.
Definition: document.cpp:2431
Okular::Generator::TextExtraction
Whether the Generator can extract text from the document in the form of TextPage's.
Definition: generator.h:202
Okular::Annotation::contents
QString contents() const
Returns the contents of the annotation.
Definition: annotations.cpp:545
Okular::Document::fillConfigDialog
void fillConfigDialog(KConfigDialog *dialog)
Fill the KConfigDialog dialog with the setting pages of the generators.
Definition: document.cpp:3912
Okular::RenditionAction
The Rendition action executes an operation on a video or executes some JavaScript code on activation...
Definition: action.h:491
Okular::Page::orientation
Rotation orientation() const
Returns the orientation of the page as defined by the document.
Definition: page.cpp:165
sourcereference_p.h
Okular::Page::addAnnotation
void addAnnotation(Annotation *annotation)
Adds a new annotation to the page.
Definition: page.cpp:641
Okular::Action::Browse
Browse a given website.
Definition: action.h:52
Okular::PixmapRequestPrivate::mForce
bool mForce
Definition: generator_p.h:81
Okular::DocumentAction::HistoryBack
Go back in page history.
Definition: action.h:278
Okular::DocumentViewport::toString
QString toString() const
Returns the viewport as xml description.
Definition: document.cpp:4560
Okular::Document::supportsSearching
bool supportsSearching() const
Returns whether the document supports searching.
Definition: document.cpp:2675
Okular::AnnotationProxy::Addition
Generator can create native annotations.
Definition: annotations.h:691
Okular::Document::dynamicSourceReference
const SourceReference * dynamicSourceReference(int pageNr, double absX, double absY)
Asks the generator to dynamically generate a SourceReference for a given page number and absolute X a...
Definition: document.cpp:3822
Okular::Document::MatchFound
Any match was found.
Definition: document.h:483
Okular::Document::processAction
void processAction(const Action *action)
Processes the given action.
Definition: document.cpp:3560
Okular::ConfigInterface::reparseConfig
virtual bool reparseConfig()=0
This method is called to tell the generator to re-parse its configuration.
Okular::DocumentPrivate::m_allocatedTextPagesFifo
QList< int > m_allocatedTextPagesFifo
Definition: document_p.h:221
Okular::Document::canSaveChanges
bool canSaveChanges() const
Returns whether the changes to the document (modified annotations, values in form fields...
Definition: document.cpp:3987
Okular::View::viewDocument
Document * viewDocument() const
Return the document which this view is associated to, or null if it is not associated with any docume...
Definition: view.cpp:44
Okular::DocumentViewport::TopLeft
Relative to the top left corner of the page.
Definition: document.h:1043
Okular::Document::quit
void quit()
This signal is emitted whenever an action requests an application quit operation. ...
Okular::TextAnnotation
Definition: annotations.h:731
audioplayer_p.h
Okular::AnnotationProxy::Removal
Generator can remove native annotations.
Definition: annotations.h:693
Okular::Annotation::DenyWrite
Cannot be changed.
Definition: annotations.h:131
Okular::DocumentViewport::width
bool width
Definition: document.h:1062
Okular::OriginalAnnotationPageItems
Definition: page_p.h:51
Okular::DocumentPrivate::m_pageController
PageController * m_pageController
Definition: document_p.h:255
Okular::Generator::loadDocument
virtual bool loadDocument(const QString &fileName, QVector< Page * > &pagesVector)=0
Loads the document with the given fileName and fills the pagesVector with the parsed pages...
Okular::Document::orientation
QPrinter::Orientation orientation() const
Returns the orientation of the document (for printing purposes).
Definition: document.cpp:4266
Okular::DocumentPrivate::doContinueAllDocumentSearch
void doContinueAllDocumentSearch(void *pagesToNotifySet, void *pageMatchesMap, int currentPage, int searchID, const QString &text, int caseSensitivity, const QColor &color)
Definition: document.cpp:1729
Okular::Document::NextMatch
Search next match.
Definition: document.h:471
GeneratorInfo::config
Okular::ConfigInterface * config
Definition: document_p.h:58
Okular::Generator::generateDocumentSynopsis
virtual const DocumentSynopsis * generateDocumentSynopsis()
Returns the 'table of content' object of the document or 0 if no table of content is available...
Definition: generator.cpp:280
Okular::Generator::closeDocument
bool closeDocument()
This method is called when the document is closed and not used any longer.
Definition: generator.cpp:181
Okular::PixmapRequest::Asynchronous
Definition: generator.h:531
Okular::AddAnnotationCommand
Definition: documentcommands_p.h:27
Okular::Action::Sound
Play a sound.
Definition: action.h:54
Okular::DocumentAction::GoToPage
Goto page.
Definition: action.h:284
Okular::SourceReference::row
int row() const
Returns the row of the position in the source file.
Definition: sourcereference.cpp:50
Okular::DocumentPrivate::m_tiledObserver
DocumentObserver * m_tiledObserver
Definition: document_p.h:215
Okular::Document::continueSearch
void continueSearch(int searchID)
Continues the search for the given searchID.
Definition: document.cpp:3365
Okular::Scripter
Definition: scripter.h:24
QUndoCommand
KPluginFactory
scripter.h
Okular::Document::embeddedFiles
const QList< EmbeddedFile * > * embeddedFiles() const
Returns the list of embedded files or 0 if no embedded files are available.
Definition: document.cpp:2614
Okular::DocumentPrivate::m_parent
Document * m_parent
Definition: document_p.h:187
Okular::DocumentPrivate::m_nextDocumentDestination
QString m_nextDocumentDestination
Definition: document_p.h:209
Okular::Action::actionType
virtual ActionType actionType() const =0
Returns the type of the action.
Okular::DocumentPrivate::loadDocumentInfo
void loadDocumentInfo()
Definition: document.cpp:590
Okular::DocumentPrivate::cleanupPixmapMemory
void cleanupPixmapMemory()
Definition: document.cpp:326
Okular::DoContinueDirectionMatchSearchStruct::forward
bool forward
Definition: document_p.h:70
Okular::DocumentAction::EndPresentation
End presentation.
Definition: action.h:282
Okular::DocumentInfo::Description
The description of the document.
Definition: document.h:1082
Okular::DocumentPrivate::m_supportedMimeTypes
QStringList m_supportedMimeTypes
Definition: document_p.h:253
Okular::DoContinueDirectionMatchSearchStruct::text
QString text
Definition: document_p.h:75
Okular::DocumentPrivate::fontReadingProgress
void fontReadingProgress(int page)
Definition: document.cpp:1485
Okular::DocumentAction::documentActionType
DocumentActionType documentActionType() const
Returns the type of action.
Definition: action.cpp:247
Okular::DocumentSynopsis
A DOM tree that describes the Table of Contents.
Definition: document.h:1154
Okular::DocumentPrivate::loadViewsInfo
void loadViewsInfo(View *view, const QDomElement &e)
Definition: document.cpp:719
Okular::DocumentViewport::isValid
bool isValid() const
Returns whether the viewport is valid.
Definition: document.cpp:4576
Okular::SoundAction
The Sound action plays a sound on activation.
Definition: action.h:323
Okular::Action::Execute
Execute a command or external application.
Definition: action.h:51
Okular::BookmarkManager
Bookmarks manager utility.
Definition: bookmarkmanager.h:32
Okular::Document::openDocumentArchive
bool openDocumentArchive(const QString &docFile, const KUrl &url)
Opens a document archive.
Definition: document.cpp:4084
Okular::Document::setPageTextSelection
void setPageTextSelection(int page, RegularAreaRect *rect, const QColor &color)
Sets the text selection for the given page.
Definition: document.cpp:3075
Okular::DocumentPrivate::doContinueDirectionMatchSearch
void doContinueDirectionMatchSearch(void *doContinueDirectionMatchSearchStruct)
Definition: document.cpp:1610
audioplayer.h
ChooseEngineDialog::selectedGenerator
int selectedGenerator() const
Definition: chooseenginedialog.cpp:43
Okular::Document::resetSearch
void resetSearch(int searchID)
Resets the search for the given searchID.
Definition: document.cpp:3401
Okular::Document::setViewportPage
void setViewportPage(int page, DocumentObserver *excludeObserver=0, bool smoothMove=false)
Sets the current document viewport to the given page.
Definition: document.cpp:3116
Okular::DocumentPrivate::m_pixmapRequestsStack
QLinkedList< PixmapRequest * > m_pixmapRequestsStack
Definition: document_p.h:216
Okular::DocumentViewport::height
bool height
Definition: document.h:1063
Okular::PixmapRequest
Describes a pixmap type request.
Definition: generator.h:522
Okular::Document::RemoveAllPrevious
Remove all the previous requests, even for non requested page pixmaps.
Definition: document.h:350
Okular::ExportFormat::isNull
bool isNull() const
Returns whether the export format is null/valid.
Definition: generator.cpp:577
Okular::DocumentInfo::ModificationDate
The date of last modification of the document.
Definition: document.h:1089
Okular::ConfigInterface::addPages
virtual void addPages(KConfigDialog *dialog)=0
This method allows the generator to add custom configuration pages to the config dialog of okular...
Okular::PixmapRequest::setTile
void setTile(bool tile)
Sets whether the generator should render only the given normalized rect or the entire page...
Definition: generator.cpp:484
Okular::AnnotationProxy::supports
virtual bool supports(Capability capability) const =0
Query for the supported capabilities.
Okular::DocumentPrivate::setRotationInternal
void setRotationInternal(int r, bool notify)
Definition: document.cpp:4431
Okular::DocumentPrivate::m_annotationsNeedSaveAs
bool m_annotationsNeedSaveAs
Definition: document_p.h:271
Okular::Generator
[Abstract Class] The information generator.
Definition: generator.h:185
Okular::PagePrivate::deleteTextSelections
void deleteTextSelections()
Deletes all text selection objects of the page.
Definition: page.cpp:774
Okular::DocumentPrivate::calculateMemoryToFree
qulonglong calculateMemoryToFree()
Definition: document.cpp:283
Okular::DocumentInfo::Producer
The producer of the document (e.g. some software)
Definition: document.h:1085
Okular::Document::currentPage
uint currentPage() const
Returns the number of the current page.
Definition: document.cpp:2647
Okular::DocumentPrivate::m_maxAllocatedTextPages
int m_maxAllocatedTextPages
Definition: document_p.h:222
Okular::DocumentAction::Presentation
Start presentation.
Definition: action.h:281
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:45:02 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

okular

Skip menu "okular"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdegraphics API Reference

Skip menu "kdegraphics API Reference"
  •     libkdcraw
  •     libkexiv2
  •     libkipi
  •     libksane
  • okular

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal