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

okular

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