Changeset View
Changeset View
Standalone View
Standalone View
Mainpage.dox
Show All 18 Lines | |||||
19 | viewing PDF but also other types of document, e.g. PostScript files, images and many more. | 19 | viewing PDF but also other types of document, e.g. PostScript files, images and many more. | ||
20 | 20 | | |||
21 | \page okular_design The Design of Okular | 21 | \page okular_design The Design of Okular | ||
22 | 22 | | |||
23 | To support a wide range of document formats, Okular was designed in a modular way, so you | 23 | To support a wide range of document formats, Okular was designed in a modular way, so you | ||
24 | have the following components: | 24 | have the following components: | ||
25 | 25 | | |||
26 | \li \ref Shell | 26 | \li \ref Shell | ||
27 | \li \ref Part | 27 | \li \ref Okular::Part | ||
28 | \li \ref Okular::Document Class | 28 | \li \ref Okular::Document Class | ||
29 | \li \ref Okular::Generator | 29 | \li \ref Okular::Generator | ||
30 | 30 | | |||
31 | The shell is the application which is started by the user as standalone application and | 31 | The shell is the application which is started by the user as standalone application and | ||
32 | which embeds the part. The part contains all GUI elements of Okular, for example the | 32 | which embeds the part. The part contains all GUI elements of Okular, for example the | ||
33 | content list, the bookmark manager, menus and the graphical view of the document class. | 33 | content list, the bookmark manager, menus and the graphical view of the document class. | ||
34 | The document class is an abstract presentation of the document content. It contains information | 34 | The document class is an abstract presentation of the document content. It contains information | ||
35 | about every page of the document, its size, orientation etc. | 35 | about every page of the document, its size, orientation etc. | ||
36 | 36 | | |||
37 | But somehow the document class must retrieve these information from the various types of documents. | 37 | But somehow the document class must retrieve these information from the various types of documents. | ||
38 | This is the task of the Generators. Generators are plugins which are loaded at runtime and which | 38 | This is the task of the Generators. Generators are plugins which are loaded at runtime and which | ||
39 | have the knowledge about the internal structure of the different document types. | 39 | have the knowledge about the internal structure of the different document types. | ||
40 | They extract the needed information from the documents, convert the data into a common format and | 40 | They extract the needed information from the documents, convert the data into a common format and | ||
41 | pass them to the document class. | 41 | pass them to the document class. | ||
42 | 42 | | |||
43 | Currently Generators for the following document types are available: | 43 | Currently Generators for the following document types are available: | ||
44 | 44 | | |||
45 | \li Portable Document Format (PDF) | 45 | \li Portable Document Format (PDF) | ||
aacid: I'd use the original sorting here, "noone" about xps but everyone cares about PDF, so it being… | |||||
46 | \li PostScript | 46 | \li PostScript | ||
47 | \li Device Independent Format (DVI) | 47 | \li Device Independent Format (DVI) | ||
48 | \li DeJaVu Format | 48 | \li DeJaVu Format | ||
49 | \li Comic Books | 49 | \li Comic Books | ||
50 | \li Images (JPEG, PNG, GIF, and many more) | 50 | \li Images (JPEG, PNG, GIF, and many more) | ||
51 | \li TIFF Image Format | 51 | \li TIFF Image Format | ||
52 | \li FictionBook Format | 52 | \li FictionBook Format | ||
53 | \li Plucker Format | 53 | \li Plucker Format | ||
54 | \li OpenDocument Text Format | 54 | \li OpenDocument Text Format | ||
55 | \li Microsofts CHM Format | 55 | \li Microsoft's CHM Format | ||
56 | \li Microsofts XML Document Format | 56 | \li Microsoft's XML Document Format | ||
57 | \li Markdown Format | ||||
57 | 58 | | |||
58 | Now the questions is how can these various formats be represented in a unified way? | 59 | Now the questions is how can these various formats be represented in a unified way? | ||
59 | Okular provides features like rotation, text search and extraction, zooming and many more, so how | 60 | Okular provides features like rotation, text search and extraction, zooming and many more, so how | ||
60 | does it match with the different capabilities of the formats? | 61 | does it match with the different capabilities of the formats? | ||
61 | 62 | | |||
62 | \section okular_design_basics Basics of Generators | 63 | \section okular_design_basics Basics of Generators | ||
63 | 64 | | |||
64 | Lets start with the smallest commonness of all document formats: | 65 | Lets start with the smallest commonness of all document formats: | ||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Line(s) | |||||
192 | 193 | | |||
193 | The implementation of the Generator looks like this: | 194 | The implementation of the Generator looks like this: | ||
194 | 195 | | |||
195 | \code | 196 | \code | ||
196 | #include <okular/core/page.h> | 197 | #include <okular/core/page.h> | ||
197 | 198 | | |||
198 | #include "magicgenerator.h" | 199 | #include "magicgenerator.h" | ||
199 | 200 | | |||
200 | static KAboutData createAboutData() | 201 | OKULAR_EXPORT_PLUGIN(MagicGenerator, "libokularGenerator_magic.json") | ||
201 | { | | |||
202 | KAboutData aboutData(...); | | |||
203 | // fill the about data | | |||
204 | return aboutData; | | |||
205 | } | | |||
206 | | ||||
207 | OKULAR_EXPORT_PLUGIN(MagicGenerator, createAboutData()) | | |||
208 | 202 | | |||
209 | MagicGenerator::MagicGenerator( QObject *parent, const QVariantList &args ) | 203 | MagicGenerator::MagicGenerator( QObject *parent, const QVariantList &args ) | ||
210 | : Okular::Generator( parent, args ) | 204 | : Okular::Generator( parent, args ) | ||
211 | { | 205 | { | ||
212 | } | 206 | } | ||
213 | 207 | | |||
214 | MagicGenerator::~MagicGenerator() | 208 | MagicGenerator::~MagicGenerator() | ||
215 | { | 209 | { | ||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Line(s) | |||||
277 | pixmap in the Okular::Page object which is associated with the page request. | 271 | pixmap in the Okular::Page object which is associated with the page request. | ||
278 | When this task is finished, the Generator has to call signalPixmapRequestDone() with the page request object | 272 | When this task is finished, the Generator has to call signalPixmapRequestDone() with the page request object | ||
279 | as argument. This extra call is needed to allow the Generator to use signals and slots internally and create the | 273 | as argument. This extra call is needed to allow the Generator to use signals and slots internally and create the | ||
280 | pixmap asynchronously. | 274 | pixmap asynchronously. | ||
281 | 275 | | |||
282 | So now you have the code of a working Okular Generator, the next step is to tell Okular about the new plugin. | 276 | So now you have the code of a working Okular Generator, the next step is to tell Okular about the new plugin. | ||
283 | Like in other places in KDE that is done by .desktop files, which are installed to the services directory. | 277 | Like in other places in KDE that is done by .desktop files, which are installed to the services directory. | ||
284 | 278 | | |||
285 | Every Generator needs 3 .desktop files: | 279 | Every Generator needs 1 .json, 3 .desktop files, and 1 .xml file: | ||
286 | 280 | | |||
287 | \li libokularGenerator_<name>.desktop | 281 | \li libokularGenerator_<name>.json | ||
288 | \li okularApplication_<name>.desktop | 282 | \li okularApplication_<name>.desktop | ||
289 | \li okular<name>.desktop | 283 | \li okular<name>.desktop | ||
284 | \li org.kde.mobile.okular_<name>.desktop | ||||
285 | \li org.kde.okular-<name>.metainfo.xml | ||||
290 | 286 | | |||
291 | where <name> should be the name of the document format. So for our Magic Document Generator we | 287 | where <name> should be the name of the document format. So for our Magic Document Generator we | ||
292 | create the following 3 files: | 288 | create the following 4 files: | ||
293 | 289 | | |||
294 | \li libokularGenerator_magic.desktop | 290 | \li libokularGenerator_magic.json | ||
295 | \li okularApplication_magic.desktop | 291 | \li okularApplication_magic.desktop | ||
296 | \li okularMagic.desktop | 292 | \li okularMagic.desktop | ||
293 | \li org.kde.mobile.okular_magic.desktop | ||||
294 | \li org.kde.okular-magic.metainfo.xml | ||||
297 | 295 | | |||
298 | with the following content: | 296 | where libokularGenerator_magic.json has the following content something like this | ||
299 | 297 | | |||
300 | \verbatim | 298 | \verbatim | ||
301 | [Desktop Entry] | 299 | { | ||
302 | Type=Service | 300 | "KPlugin": { | ||
303 | Name=Magic Document | 301 | "Authors": [ | ||
304 | Comment=Magic Document backend for okular | 302 | { | ||
305 | ServiceTypes=okular/Generator | 303 | "Email": "author@hosting.suffix", | ||
306 | MimeType=application/x-magic; | 304 | "Name": "Proud Author", | ||
307 | X-KDE-Library=okularGenerator_magic | 305 | } | ||
308 | X-KDE-Priority=1 | 306 | ], | ||
309 | X-KDE-okularAPIVersion=1 | 307 | "Copyright": "© 2042 Proud Author", | ||
310 | X-KDE-okularHasInternalSettings=false | 308 | "Id": "okular_magic", | ||
309 | "License": "GPL", | ||||
310 | "MimeTypes": [ | ||||
311 | "text/magic", | ||||
312 | "text/x-magic" | ||||
313 | ], | ||||
314 | "Name": "Magic Backend", | ||||
315 | "ServiceTypes": [ | ||||
316 | "okular/Generator" | ||||
317 | ], | ||||
318 | "Version": "0.1.0" | ||||
319 | }, | ||||
320 | "X-KDE-Priority": 1, | ||||
321 | "X-KDE-okularAPIVersion": 1, | ||||
322 | "X-KDE-okularHasInternalSettings": true | ||||
323 | } | ||||
311 | \endverbatim | 324 | \endverbatim | ||
312 | 325 | | |||
313 | The first 6 fields are standard .desktop entries, the fields afterwards have a special meaning to Okular | 326 | The last five fields has the special meaning to Okular | ||
314 | 327 | | |||
315 | \li <b>ServiceType</b> Must be 'okular/Generator' for all Okular Generator Plugins | 328 | \li <b>ServiceType</b> Must be 'okular/Generator' for all Okular Generator Plugins | ||
316 | \li <b>MimeType</b> The mimetype or list of mimetypes of the supported document format(s) | 329 | \li <b>MimeType</b> The mimetype or list of mimetypes of the supported document format(s) | ||
317 | \li <b>X-KDE-Library</b> The name of the plugin library | | |||
318 | \li <b>X-KDE-Priority</b> When multiple Generators for the same mimetype exists, the one with the highest priority is used | 330 | \li <b>X-KDE-Priority</b> When multiple Generators for the same mimetype exists, the one with the highest priority is used | ||
319 | \li <b>X-KDE-okularAPIVersion</b> The version of the Generator Plugin API ('1' currently) | 331 | \li <b>X-KDE-okularAPIVersion</b> The version of the Generator Plugin API ('1' currently) | ||
320 | \li <b>X-KDE-okularHasInternalSettings</b> Is 'true' when the Generator provides configuration dialogs | 332 | \li <b>X-KDE-okularHasInternalSettings</b> Is 'true' when the Generator provides configuration dialogs | ||
321 | 333 | | |||
322 | The second .desktop file has the following content: | 334 | The first .desktop file has the following content: | ||
323 | 335 | | |||
324 | \verbatim | 336 | \verbatim | ||
325 | [Desktop Entry] | 337 | [Desktop Entry] | ||
326 | MimeType=application/x-magic; | 338 | MimeType=application/x-magic; | ||
327 | Terminal=false | 339 | Terminal=false | ||
328 | Name=okular | 340 | Name=okular | ||
329 | GenericName=Document Viewer | 341 | GenericName=Document Viewer | ||
330 | Exec=okular %U %i | 342 | Exec=okular %U | ||
331 | Icon=okular | 343 | Icon=okular | ||
332 | Type=Application | 344 | Type=Application | ||
333 | InitialPreference=7 | 345 | InitialPreference=7 | ||
334 | Categories=Qt;KDE;Graphics;Viewer; | 346 | Categories=Qt;KDE;Graphics;Viewer; | ||
335 | NoDisplay=true | 347 | NoDisplay=true | ||
348 | X-KDE-Keywords=Magic | ||||
336 | \endverbatim | 349 | \endverbatim | ||
337 | 350 | | |||
338 | You can use the file as it is, you just have to adapt the mimetype. This file is needed to allow Okular | 351 | You can use the file as it is, you just have to adapt the mimetype. This file is needed to allow Okular | ||
339 | to handle multiple mimetypes. | 352 | to handle multiple mimetypes. | ||
340 | 353 | | |||
341 | The third .desktop file looks like this: | 354 | The second .desktop file looks like this: | ||
342 | 355 | | |||
343 | \verbatim | 356 | \verbatim | ||
344 | [Desktop Entry] | 357 | [Desktop Entry] | ||
345 | Icon=okular | 358 | Icon=okular | ||
346 | Name=okular | 359 | Name=okular | ||
347 | ServiceTypes=KParts/ReadOnlyPart | 360 | X-KDE-ServiceTypes=KParts/ReadOnlyPart | ||
348 | X-KDE-Library=okularpart | 361 | X-KDE-Library=okularpart | ||
349 | Type=Service | 362 | Type=Service | ||
350 | MimeType=application/x-magic; | 363 | MimeType=application/x-magic; | ||
351 | \endverbatim | 364 | \endverbatim | ||
352 | 365 | | |||
366 | where | ||||
367 | | ||||
368 | \li <b>X-KDE-Library</b> The name of the plugin library | ||||
369 | | ||||
353 | You can use the file as it is as well, you just have to adapt the mimetype. This file is needed to allow | 370 | You can use the file as it is as well, you just have to adapt the mimetype. This file is needed to allow | ||
354 | the Okular part to handle multiple mimetypes. | 371 | the Okular part to handle multiple mimetypes. | ||
355 | 372 | | |||
373 | The third .desktop file contains data for the mobile version | ||||
374 | | ||||
375 | \verbatim | ||||
376 | [Desktop Entry] | ||||
377 | MimeType=application/x-magic; | ||||
378 | Name=Reader | ||||
379 | GenericName=Document viewer | ||||
380 | Comment=Viewer for various types of documents | ||||
381 | TryExec=kpackagelauncherqml -a org.kde.mobile.okular | ||||
382 | Exec=kpackagelauncherqml -a org.kde.mobile.okular %u | ||||
383 | Terminal=false | ||||
384 | Icon=okular | ||||
385 | Type=Application | ||||
386 | Categories=Qt;KDE;Graphics;Office;Viewer; | ||||
387 | InitialPreference=2 | ||||
388 | NoDisplay=true | ||||
389 | X-KDE-Keywords=Magic | ||||
390 | \endverbatim | ||||
391 | | ||||
392 | And the last .xml file has the following content | ||||
393 | | ||||
394 | \verbatim | ||||
395 | <?xml version="1.0" encoding="utf-8"?> | ||||
396 | <component type="addon"> | ||||
397 | <id>org.kde.okular-md</id> | ||||
398 | <extends>org.kde.okular.desktop</extends> | ||||
399 | <metadata_license>CC0-1.0</metadata_license> | ||||
400 | <project_license>GPL-2.0+ and GFDL-1.3</project_license> | ||||
401 | <name>Magic</name> | ||||
402 | <summary>Adds support for reading Magic documents</summary> | ||||
403 | <mimetypes> | ||||
404 | <mimetype>application/magic</mimetype> | ||||
405 | </mimetypes> | ||||
406 | <url type="homepage">https://okular.kde.org</url> | ||||
407 | </component> | ||||
408 | \endverbatim | ||||
409 | | ||||
356 | The last piece you need for a complete Generator is a CMakeLists.txt which compiles and installs the | 410 | The last piece you need for a complete Generator is a CMakeLists.txt which compiles and installs the | ||
357 | Generator. Our CMakeLists.txt looks like the following: | 411 | Generator. Our CMakeLists.txt looks like the following: | ||
358 | 412 | | |||
359 | \verbatim | 413 | \verbatim | ||
414 | add_definitions(-DTRANSLATION_DOMAIN="okular_magic") | ||||
415 | | ||||
360 | macro_optional_find_package(Okular) | 416 | macro_optional_find_package(Okular) | ||
This changeset is wrong (or at least changes the original intent of the document), your changes are for building in source, while the manual is for people that build out of okular's source aacid: This changeset is wrong (or at least changes the original intent of the document), your changes… | |||||
361 | 417 | | |||
362 | include_directories( ${OKULAR_INCLUDE_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) | 418 | include_directories( ${OKULAR_INCLUDE_DIR} ${KF5_INCLUDE_DIR} ${QT_INCLUDES} ) | ||
363 | 419 | | |||
364 | ########### next target ############### | 420 | ########### next target ############### | ||
365 | 421 | | |||
366 | set( okularGenerator_magic_SRCS generator_magic.cpp ) | 422 | set( okularGenerator_magic_PART_SRCS generator_magic.cpp ) | ||
367 | 423 | | |||
368 | kde4_add_plugin( okularGenerator_magic ${okularGenerator_magic_SRCS} ) | 424 | target_link_libraries( okularGenerator_magic PRIVATE okularcore KF5::I18n KF5::KIOCore ) | ||
369 | | ||||
370 | target_link_libraries( okularGenerator_magic ${OKULAR_LIBRARIES} ${KDE4_KDEUI_LIBS} ) | | |||
371 | 425 | | |||
372 | install( TARGETS okularGenerator_magic DESTINATION ${PLUGIN_INSTALL_DIR} ) | 426 | install( TARGETS okularGenerator_magic DESTINATION ${PLUGIN_INSTALL_DIR} ) | ||
373 | 427 | | |||
374 | ########### install files ############### | 428 | ########### install files ############### | ||
375 | 429 | | |||
376 | install( FILES libokularGenerator_magic.desktop okularMagic.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) | 430 | install( FILES okularMagic.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) | ||
377 | install( FILES okularApplication_magic.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) | 431 | install( PROGRAMS okularApplication_magic.desktop org.kde.mobile.okular_magic.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) | ||
432 | install( FILES org.kde.okular-magic.metainfo.xml DESTINATION ${KDE_INSTALL_METAINFODIR} ) | ||||
378 | \endverbatim | 433 | \endverbatim | ||
379 | 434 | | |||
380 | The macro_optional_find_package(Okular) call is required to make the ${OKULAR_INCLUDE_DIR} and ${OKULAR_LIBRARIES} | 435 | The macro_optional_find_package(Okular) call is required to make the ${OKULAR_INCLUDE_DIR} and ${OKULAR_LIBRARIES} | ||
381 | variables available. | 436 | variables available. | ||
382 | 437 | | |||
383 | Now you can compile the Generator plugin and install it. After a restart of Okular the new plugin is available | 438 | Now you can compile the Generator plugin and install it. After a restart of Okular the new plugin is available | ||
384 | and you can open Magic documents. | 439 | and you can open Magic documents. | ||
385 | 440 | | |||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Line(s) | 703 | { | |||
671 | private: | 726 | private: | ||
672 | QTextDocument *mTextDocument; | 727 | QTextDocument *mTextDocument; | ||
673 | Okular::DocumentInfo mDocumentInfo; | 728 | Okular::DocumentInfo mDocumentInfo; | ||
674 | Okular::DocumentSynopsis mDocumentSynopsis; | 729 | Okular::DocumentSynopsis mDocumentSynopsis; | ||
675 | }; | 730 | }; | ||
676 | \endcode | 731 | \endcode | ||
677 | 732 | | |||
678 | The Generator doesn't support text search and selection, as the code would be quite complex, we'll show | 733 | The Generator doesn't support text search and selection, as the code would be quite complex, we'll show | ||
679 | how to do it in the next chapter \ref okular_generators_textdocument anyway. | 734 | how to do it in the next chapter (not yet written) anyway. | ||
680 | 735 | | |||
681 | As you can see we have 5 new methods in the class: | 736 | As you can see we have 5 new methods in the class: | ||
682 | 737 | | |||
683 | \li <b>generateDocumentInfo()</b> Creates an Okular::DocumentInfo (which is in fact a QDomDocument) | 738 | \li <b>generateDocumentInfo()</b> Creates an Okular::DocumentInfo (which is in fact a QDomDocument) | ||
684 | which contains document information like author, creation time etc. | 739 | which contains document information like author, creation time etc. | ||
685 | \li <b>generateDocumentSynopsis()</b> Creates an Okular::DocumentSynopsis (which is a QDomDocument as well) | 740 | \li <b>generateDocumentSynopsis()</b> Creates an Okular::DocumentSynopsis (which is a QDomDocument as well) | ||
686 | which contains the table of content. | 741 | which contains the table of content. | ||
687 | \li <b>print()</b> Prints the document to the passed printer. | 742 | \li <b>print()</b> Prints the document to the passed printer. | ||
688 | \li <b>exportFormats()</b> Returns the supported export formats. | 743 | \li <b>exportFormats()</b> Returns the supported export formats. | ||
689 | \li <b>exportTo()</b> Exports the document to the given file in the given format. | 744 | \li <b>exportTo()</b> Exports the document to the given file in the given format. | ||
690 | 745 | | |||
691 | Now that you know what the methods are supposed to do, let's take a look at the implementation: | 746 | Now that you know what the methods are supposed to do, let's take a look at the implementation: | ||
692 | 747 | | |||
693 | \code | 748 | \code | ||
694 | #include <QFile> | 749 | #include <QFile> | ||
695 | #include <QAbstractTextDocumentLayout> | 750 | #include <QAbstractTextDocumentLayout> | ||
696 | | ||||
697 | #include <QPrinter> | 751 | #include <QPrinter> | ||
698 | 752 | | |||
699 | #include <okular/core/document.h> | 753 | #include <okular/core/document.h> | ||
700 | #include <okular/core/page.h> | 754 | #include <okular/core/page.h> | ||
701 | 755 | | |||
702 | #include "htmlgenerator.h" | 756 | #include "htmlgenerator.h" | ||
703 | 757 | | |||
704 | static KAboutData createAboutData() | 758 | #include <KLocalizedString> | ||
aacid: i guess we don't really need this | |||||
705 | { | | |||
706 | KAboutData aboutData(...); | | |||
707 | // fill the about data | | |||
708 | return aboutData; | | |||
709 | } | | |||
710 | 759 | | |||
711 | OKULAR_EXPORT_PLUGIN(HTMLGenerator, createAboutData()) | 760 | OKULAR_EXPORT_PLUGIN(HTMLGenerator, "libokularGenerator_html.json") | ||
712 | 761 | | |||
713 | HTMLGenerator::HTMLGenerator( QObject *parent, const QVariantList &args ) | 762 | HTMLGenerator::HTMLGenerator( QObject *parent, const QVariantList &args ) | ||
714 | : Okular::Generator( parent, args ), | 763 | : Okular::Generator( parent, args ), | ||
715 | mTextDocument( 0 ) | 764 | mTextDocument( 0 ) | ||
716 | { | 765 | { | ||
717 | } | 766 | } | ||
718 | 767 | | |||
719 | HTMLGenerator::~HTMLGenerator() | 768 | HTMLGenerator::~HTMLGenerator() | ||
▲ Show 20 Lines • Show All 139 Lines • Show Last 20 Lines |
I'd use the original sorting here, "noone" about xps but everyone cares about PDF, so it being on top makes sense