root/trunk/src/IDocument.cxx

Revision 250, 37.4 kB (checked in by jordi, 2 years ago)

When a new file is loaded, the page cache is emptied to prevent showing pages from previous files. See bug #43.

Part of this fix is thanks to LoneFox?.

Line 
1// ePDFView - A lightweight PDF Viewer.
2// Copyright (C) 2006 Emma's Software.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18#include <config.h>
19#include <string.h>
20#include <gdk/gdkcolor.h>
21#include "epdfview.h"
22
23using namespace ePDFView;
24
25G_LOCK_EXTERN (JobRender);
26G_LOCK_DEFINE_STATIC (pageImage);
27G_LOCK_DEFINE_STATIC (pageSearch);
28
29// Constants.
30static const gdouble ZOOM_IN_FACTOR = 1.2;
31static const gdouble ZOOM_IN_MAX = 4.0;
32static const gdouble ZOOM_OUT_FACTOR = (1.0 / ZOOM_IN_FACTOR);
33static const gdouble ZOOM_OUT_MAX = 0.05409;
34static const guint CACHE_SIZE = 3;
35
36/// This is the error domain that will be used to report Document's errors.
37GQuark IDocument::errorQuark = 0;
38
39///
40/// @brief Gets the IDocument's error quark.
41///
42/// The first time it's called will create the new quark value for the
43/// document class. Successive calls will just return the previously created
44/// quark value.
45///
46/// The error quark is used by Glib's g_set_error() function to set the
47/// domain in that the error happened. EPDFVIEW_DOCUMENT_ERROR has been
48/// defined to call this function, use that defined string when using
49/// g_set_error() inside a document's class.
50///
51/// @return The IDocument's quark.
52///
53GQuark
54IDocument::getErrorQuark ()
55{
56    if ( 0 == IDocument::errorQuark )
57        IDocument::errorQuark =
58            g_quark_from_static_string ("epdfview-document");
59
60    return IDocument::errorQuark;
61}
62
63///
64/// @brief Gives the error's description.
65///
66/// This function looks the error at @a errorCode and gives an human
67/// readable error string.
68///
69/// The error message must be freed using g_free().
70///
71/// @param errorCode The error code to get the string from.
72///
73/// @return An human readable error message.
74///
75gchar *
76IDocument::getErrorMessage (DocumentError errorCode)
77{
78    gchar *errorMessage = NULL;
79    switch (errorCode)
80    {
81        case DocumentErrorNone:
82            errorMessage = g_strdup (_("No error."));
83            break;
84        case DocumentErrorOpenFile:
85            errorMessage = g_strdup (_("File not found."));
86            break;
87        case DocumentErrorBadCatalog:
88            errorMessage = g_strdup (_("Couldn't read the page catalog."));
89            break;
90        case DocumentErrorDamaged:
91            errorMessage = g_strdup (_("The PDF file is damaged and can't be repaired."));
92            break;
93        case DocumentErrorEncrypted:
94            errorMessage = g_strdup (_("The file is encrypted and the password was incorrect or not supplied."));
95            break;
96        case DocumentErrorHighlightFile:
97            errorMessage = g_strdup (_("Nonexistent or invalid highlight file."));
98            break;
99        case DocumentErrorBadPrinter:
100            errorMessage = g_strdup (_("Invalid printer."));
101            break;
102        case DocumentErrorPrinting:
103            errorMessage = g_strdup (_("Error during printing."));
104            break;
105        case DocumentErrorPermission:
106            errorMessage = g_strdup (_("The PDF file doesn't allow that operation."));
107            break;
108        case DocumentErrorBadPageNumber:
109            errorMessage = g_strdup (_("Invalid page number."));
110            break;
111        case DocumentErrorFileIO:
112            errorMessage = g_strdup (_("File I/O error."));
113            break;
114        default:
115            errorMessage = g_strdup_printf (_("Unknown error (%d)."), errorCode);
116    }
117
118    g_assert (NULL != errorMessage && "The error message is NULL");
119    return errorMessage;
120}
121
122///
123/// @brief Constructs a new IDocument object.
124///
125IDocument::IDocument ()
126{
127    m_Author = NULL;
128    m_CreationDate = NULL;
129    m_Creator = NULL;
130    m_CurrentPage = 0;
131    m_Observers = NULL;
132    m_Outline = NULL;
133    m_FileName = NULL;
134    m_FindRect = NULL;
135    m_FindPage = 0;
136    m_Format = NULL;
137    m_Keywords = NULL;
138    m_Linearized = NULL;
139    m_ModifiedDate = NULL;
140    m_PageCache = NULL;
141    m_PageCacheAge = 0;
142    m_PageLayout = PageLayoutUnset;
143    m_PageMode = PageModeUnset;
144    m_PageNumber = 0;
145    m_Password = NULL;
146    m_Producer = NULL;
147    m_Rotation = 0;
148    m_Scale = 1.0f;
149    m_Subject = NULL;
150    m_Title = NULL;
151}
152
153///
154/// @brief Deletes all dynamically created objects of IDocument.
155///
156IDocument::~IDocument ()
157{
158    g_list_free (m_Observers);
159    delete m_Outline;
160    delete m_FindRect;
161    g_free (m_Author);
162    g_free (m_CreationDate);
163    g_free (m_Creator);
164    g_free (m_FileName);
165    g_free (m_Format);
166    g_free (m_Keywords);
167    g_free (m_Linearized);
168    g_free (m_ModifiedDate);
169    g_free (m_Password);
170    g_free (m_Producer);
171    g_free (m_Subject);
172    g_free (m_Title);
173}
174
175///
176/// @brief Attaches a new observer object.
177///
178/// When a changes happens on the document all classes that
179/// have been attached to the document will receive a notification
180/// of such a change.
181///
182/// @param observer The observer object to attach.
183///
184void
185IDocument::attach (const IDocumentObserver *observer)
186{
187    g_assert (NULL != observer && "Tried to attach a NULL observer.");
188
189    m_Observers = g_list_prepend (m_Observers, (gpointer)observer);
190}
191
192///
193/// @brief Detaches an observer object.
194///
195/// When a previously attached object is detached no longer receives
196/// notification messages when the document is changed. It in turn
197/// notifies all observers.
198///
199/// @param observer The observer object to detach.
200///
201void
202IDocument::detach (const IDocumentObserver *observer)
203{
204    g_assert (NULL != observer && "Tried to detach a NULL observer.");
205
206    m_Observers = g_list_remove_all (m_Observers, observer);
207}
208
209///
210/// @brief The selection find result has changed.
211///
212/// This is called when the result to show to the user has changed.
213///
214/// @param pageNum The page where the result belong to.
215/// @param matchRect The unscaled rectangle of the new selected result.
216///
217void
218IDocument::notifyFindChanged (gint pageNum, DocumentRectangle *matchRect)
219{
220    delete m_FindRect;
221    m_FindRect = NULL;
222    if ( NULL != matchRect )
223    {
224        m_FindRect = new DocumentRectangle (*matchRect);
225    }
226    m_FindPage = pageNum;
227
228    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
229          item = g_list_next (item) )
230    {
231        IDocumentObserver *observer = (IDocumentObserver *)item->data;
232        observer->notifyFindChanged (matchRect);
233    }
234}
235
236///
237/// @brief The find has finished with no results.
238///
239/// This is called when the find has finished without any results. It in turn
240/// notifies all observers.
241///
242void
243IDocument::notifyFindFinished ()
244{
245    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
246          item = g_list_next (item) )
247    {
248        IDocumentObserver *observer = (IDocumentObserver *)item->data;
249        observer->notifyFindFinished ();
250    }
251}
252
253///
254/// @brief A new search has started.
255///
256/// This is called just before the find starts. It in turn notifies
257/// all observers.
258///
259void
260IDocument::notifyFindStarted ()
261{
262    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
263          item = g_list_next (item) )
264    {
265        IDocumentObserver *observer = (IDocumentObserver *)item->data;
266        observer->notifyFindStarted ();
267    }
268}
269
270///
271/// @brief The document has been loaded.
272///
273/// This is called when the JobLoad class is done. It in turn notifies
274/// all attached observers about this situation.
275///
276void
277IDocument::notifyLoad ()
278{
279    // Empty the cache to avoid displaying pages from previous file.
280    clearCache ();
281    // Add the two first pages, if they exists, to the cache.
282    addPageToCache (1);
283    if ( 1 < getNumPages () )
284    {
285        addPageToCache (2);
286    }
287
288    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
289          item = g_list_next (item) )
290    {
291        IDocumentObserver *observer = (IDocumentObserver *)item->data;
292        observer->notifyLoad ();
293    }
294}
295
296///
297/// @brief The document couldn't be loaded.
298///
299/// This is called by the JobLoad class when the document couldn't
300/// be opened. It in turns notifies all attached observers.
301///
302/// @param error The error message of why couldn't open the document.
303///
304void
305IDocument::notifyLoadError (const GError *error)
306{
307    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
308          item = g_list_next (item) )
309    {
310        IDocumentObserver *observer = (IDocumentObserver *)item->data;
311        observer->notifyLoadError (error);
312    }
313}
314
315///
316/// @brief The document couldn't be loaded because it's encrypted.
317///
318/// This is called by the JobLoad class when the document to load is
319/// encrypted and no password or an invalid one was supplied. It in turns
320/// notifies all attached observers.
321///
322/// @param fileName The file that was trying to load.
323/// @param reload TRUE if the document was trying to reload, FALSE if it
324///               was being loaded as new.
325/// @param error The error message that the operation produced.
326///
327void
328IDocument::notifyLoadPassword (const gchar *fileName, gboolean reload,
329                               const GError *error)
330{
331    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
332          item = g_list_next (item) )
333    {
334        IDocumentObserver *observer = (IDocumentObserver *)item->data;
335        observer->notifyLoadPassword (fileName, reload, error);
336    }
337}
338
339///
340/// @brief The current page has been changed.
341///
342/// This is called when the current page has been changed. It notifies
343/// all attached observers about this.
344///
345void
346IDocument::notifyPageChanged ()
347{
348    gint pageNum = getCurrentPageNum ();
349    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
350          item = g_list_next (item) )
351    {
352        IDocumentObserver *observer = (IDocumentObserver *)item->data;
353        observer->notifyPageChanged (pageNum);
354    }
355}
356
357///
358/// @brief A document's page has been rendered.
359///
360/// This is called by the JobRender class when it finished to render
361/// a document's page.
362///
363/// @param pageNumber The number of the page that has been rendered.
364/// @param age The age that the page had when started to be rendered.
365/// @param pageImage The rendered page's image.
366///
367void
368IDocument::notifyPageRendered (gint pageNumber, guint32 age,
369                               DocumentPage *pageImage)
370{
371    PageCache *cachedPage = getCachedPage (pageNumber);
372    if ( NULL != cachedPage && age == cachedPage->age )
373    {
374        G_LOCK (pageImage);
375        delete cachedPage->pageImage;
376        cachedPage->pageImage = pageImage;
377        G_UNLOCK (pageImage);
378    }
379    else
380    {
381        delete pageImage;
382    }
383}
384
385///
386/// @brief The page has been rotated.
387///
388/// This is called when the page rotation changes. It notifies all
389/// attached observer about this.
390///
391void
392IDocument::notifyPageRotated ()
393{
394    gint rotation = getRotation ();
395    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
396          item = g_list_next (item) )
397    {
398        IDocumentObserver *observer = (IDocumentObserver *)item->data;
399        observer->notifyPageRotated (rotation);
400    }
401}
402
403///
404/// @brief The page's zoom has been changed.
405///
406/// This is called when the page scale has been changed. It notifies
407/// all attached observers about this.
408///
409void
410IDocument::notifyPageZoomed ()
411{
412    gdouble zoom = getZoom ();
413    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
414          item = g_list_next (item) )
415    {
416        IDocumentObserver *observer = (IDocumentObserver *)item->data;
417        observer->notifyPageZoomed (zoom);
418    }
419}
420
421///
422/// @brief The document has been reloaded.
423///
424/// This is called by the JobLoad class when the document has been reloaded.
425/// It in turns notifies all attached observers about this.
426///
427void
428IDocument::notifyReload ()
429{
430    // Refresh the cache.
431    G_LOCK (JobRender);
432    refreshCache ();
433    G_UNLOCK (JobRender);
434
435    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
436          item = g_list_next (item) )
437    {
438        IDocumentObserver *observer = (IDocumentObserver *)item->data;
439        observer->notifyReload ();
440    }
441}
442
443///
444/// @brief The document has been saved.
445///
446/// This is called when the JobSave class is done. It in turn notifies
447/// all attached observers about this situation.
448///
449void
450IDocument::notifySave ()
451{
452    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
453          item = g_list_next (item) )
454    {
455        IDocumentObserver *observer = (IDocumentObserver *)item->data;
456        observer->notifySave ();
457    }
458}
459
460///
461/// @brief The document couldn't be saved.
462///
463/// This is called by the JobSave class when the document couldn't
464/// be saved. It in turns notifies all attached observers.
465///
466/// @param error The error message of why couldn't save the document.
467///
468void
469IDocument::notifySaveError (const GError *error)
470{
471    for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
472          item = g_list_next (item) )
473    {
474        IDocumentObserver *observer = (IDocumentObserver *)item->data;
475        observer->notifySaveError (error);
476    }
477}
478
479///
480/// @brief Loads a file.
481///
482/// This is used when loading a new file name.
483///
484/// @param fileName The file name to load.
485/// @param password The password to use to load the file or NULL if no
486///                 password is used.
487///
488void
489IDocument::load (const gchar *fileName, const gchar *password)
490{
491    m_CurrentPage = 1;
492    m_Rotation = 0;
493    m_Scale = 1.0f;
494
495    JobLoad *job = new JobLoad ();
496    job->setDocument (this);
497    job->setFileName (fileName);
498    job->setPassword (password);
499    IJob::enqueue (job);
500}
501
502///
503/// @brief Reloads the document.
504///
505/// Opens again the same file name using the previously used password.
506///
507void
508IDocument::reload (void)
509{
510    JobLoad *job = new JobLoad ();
511    job->setDocument (this);
512    job->setFileName (getFileName ());
513    job->setPassword (getPassword ());
514    job->setReload (TRUE);
515    IJob::enqueue (job);
516}
517
518///
519/// @brief Saves a copy of the document.
520///
521/// Saves the current document in a new file.
522///
523/// @param fileName The file name to save the document's copy to.
524///
525void
526IDocument::save (const gchar *fileName)
527{
528    JobSave *job = new JobSave ();
529    job->setDocument (this);
530    job->setFileName (fileName);
531    IJob::enqueue (job);
532}
533
534///
535/// @brief Gets the document's title.
536///
537/// @return The title of the document or an empty string if the document don't
538///         have a title.
539///
540const gchar *
541IDocument::getTitle ()
542{
543    if ( NULL == m_Title )
544    {
545        return "";
546    }
547    return m_Title;
548}
549
550///
551/// @brief Sets the document's title.
552///
553/// @param title The title of the document. IDocument will free it.
554///
555void
556IDocument::setTitle (gchar *title)
557{
558    gchar *oldTitle = m_Title;
559    m_Title = g_strdup (title);
560    g_free (oldTitle);
561    g_free (title);
562}
563
564///
565/// @brief Gets the document's author.
566///
567/// @return The author of the document or an empty string if the document don't
568///         have the author name.
569///
570const gchar *
571IDocument::getAuthor ()
572{
573    if ( NULL == m_Author )
574    {
575        return "";
576    }
577    return m_Author;
578}
579
580///
581/// @brief Sets the document's author.
582///
583/// @param author The name of the document's author. IDocument will free it.
584///
585void
586IDocument::setAuthor (gchar *author)
587{
588    gchar *oldAuthor = m_Author;
589    m_Author = g_strdup (author);
590    g_free (oldAuthor);
591    g_free (author);
592}
593
594///
595/// @brief Gets the document's subject.
596///
597/// @return The subject of the document or an empty string if the document don't
598///         have subject.
599///
600const gchar *
601IDocument::getSubject ()
602{
603    if ( NULL == m_Subject )
604    {
605        return "";
606    }
607    return m_Subject;
608}
609
610///
611/// @brief Sets the document's subject.
612///
613/// @param subject The subject of the document. IDocument will free it.
614///
615void
616IDocument::setSubject (gchar *subject)
617{
618    gchar *oldSubject = m_Subject;
619    m_Subject = g_strdup (subject);
620    g_free (oldSubject);
621    m_Subject = subject;
622}
623
624///
625/// @brief Gets the document's keywords.
626///
627/// @return An string with all keywords separated by white space, or an empty
628///         string if the document have no keywords.
629///
630const gchar *
631IDocument::getKeywords ()
632{
633    if ( NULL == m_Keywords )
634    {
635        return "";
636    }
637    return m_Keywords;
638}
639
640///
641/// @brief Sets the document's keywords.
642///
643/// @param keywords A white space separated list of keywords. IDocument will
644///                 free it.
645///
646void
647IDocument::setKeywords (gchar *keywords)
648{
649    gchar *oldKeywords = m_Keywords;
650    m_Keywords = g_strdup (keywords);
651    g_free (oldKeywords);
652    g_free (keywords);
653}
654
655///
656/// @brief Gets the document's creator.
657///
658/// @return The name of the software that created the document or an empty
659///         string if the creator's name is not available.
660///
661const gchar *
662IDocument::getCreator ()
663{
664    if ( NULL == m_Creator )
665    {
666        return "";
667    }
668    return m_Creator;
669}
670
671///
672/// @brief Sets the document's creator.
673///
674/// @param creator The name of the software that created the document.
675///                IDocument will free it.
676///
677void
678IDocument::setCreator (gchar *creator)
679{
680    gchar *oldCreator = m_Creator;
681    m_Creator = g_strdup (creator);
682    g_free (oldCreator);
683    g_free (creator);
684}
685///
686/// @brief Gets the document's producer.
687///
688/// @return The name of the software that converted the document or an empty
689///         string if the producer's name is not available.
690///
691const gchar *
692IDocument::getProducer ()
693{
694    if ( NULL == m_Producer )
695    {
696        return "";
697    }
698    return m_Producer;
699}
700
701///
702/// @brief Sets the document's producer.
703///
704/// @param producer The name of the software that converted the document.
705///                 IDocument will free it.
706///
707void
708IDocument::setProducer (gchar *producer)
709{
710    gchar *oldProducer = m_Producer;
711    m_Producer = g_strdup (producer);
712    g_free (oldProducer);
713    g_free (producer);
714}
715
716///
717/// @brief Gets the document's format.
718///
719/// @returns The version of the document or an empty string if the version
720///          is not available (usually only when the document has not been
721///          loaded yet).
722///
723const gchar *
724IDocument::getFormat ()
725{
726    if ( NULL == m_Format )
727    {
728        return "";
729    }
730    return m_Format;
731}
732
733///
734/// @brief Sets the document's format.
735///
736/// @param format Set the format in which the document is. IDocument will free
737///               it.
738///
739void
740IDocument::setFormat (gchar *format)
741{
742    gchar *oldFormat = m_Format;
743    m_Format = g_strdup (format);
744    g_free (oldFormat);
745    g_free (format);
746}
747
748///
749/// @brief Gets if the document is linearised.
750///
751/// @return The string "Yes" if the document is optimised for web viewing, "No"
752///         if it's not optimised or an empty string if this information is
753///         not available.
754///
755const gchar *
756IDocument::getLinearized ()
757{
758    if ( NULL == m_Linearized )
759    {
760        return "No";
761    }
762    return m_Linearized;
763}
764
765///
766/// @brief Sets if the document is linearised.
767///
768/// @param linearized Set to "Yes" if the document is linearized. "No"
769///                   otherwise. IDocument will free it.
770///
771void
772IDocument::setLinearized (gchar *linearized)
773{
774    gchar *oldLinearized = m_Linearized;
775    m_Linearized = g_strdup (linearized);
776    g_free (oldLinearized);
777    g_free (linearized);
778}
779
780///
781/// @brief Gets the document's creation date.
782///
783/// @return The date and time the document was created or an empty string if
784///         this information is not available.
785///
786const gchar *
787IDocument::getCreationDate ()
788{
789    if ( NULL == m_CreationDate )
790    {
791        return "";
792    }
793    return m_CreationDate;
794}
795
796///
797/// @brief Sets the document's creation date.
798///
799/// @param date The date and time the document was created in format
800///             'Y-M-D H:M:s'. IDocument will free it.
801///
802void
803IDocument::setCreationDate (gchar *date)
804{
805    gchar *oldCreationDate = m_CreationDate;
806    m_CreationDate = g_strdup (date);
807    g_free (oldCreationDate);
808    g_free (date);
809}
810
811///
812/// @brief Gets the document's modification date.
813///
814/// @return The date and time the document was modified or an empty string if
815///         this information is not available.
816///
817const gchar *
818IDocument::getModifiedDate ()
819{
820    if ( NULL == m_ModifiedDate )
821    {
822        return "";
823    }
824    return m_ModifiedDate;
825}
826
827///
828/// @brief Sets the document's modification date.
829///
830/// @param date The date and time the document was modified in format
831///             'Y-M-D H:M:s'. IDocument will free it.
832///
833void
834IDocument::setModifiedDate (gchar *date)
835{
836    gchar *oldModifiedDate = m_ModifiedDate;
837    m_ModifiedDate = g_strdup (date);
838    g_free (oldModifiedDate);
839    g_free (date);
840}
841
842///
843/// @brief Gets the document's page mode.
844///
845/// @return The page mode of the document or PageModeUnset if this
846///         information is not available.
847///
848PageMode
849IDocument::getPageMode ()
850{
851    return m_PageMode;
852}
853
854///
855/// @brief Sets the document's page mode.
856///
857/// @param mode The page mode of the document.
858///
859void
860IDocument::setPageMode (PageMode mode)
861{
862    m_PageMode = mode;
863}
864
865///
866/// @brief Gets the document's page layout.
867///
868/// @return The initial page layout of the document or PageLayoutUnset if this
869///         information is not available.
870///
871PageLayout
872IDocument::getPageLayout ()
873{
874    return m_PageLayout;
875}
876
877///
878/// @brief Sets the document's page layout.
879///
880/// @param layout The initial layout of the document.
881///
882void
883IDocument::setPageLayout (PageLayout layout)
884{
885    m_PageLayout = layout;
886}
887
888///
889/// @brief Get the document's number of pages.
890///
891/// @return The total number of pages the document has or 0 if the document has
892///         not been loaded yet.
893///
894gint
895IDocument::getNumPages ()
896{
897    return m_PageNumber;
898}
899
900///
901/// @brief Gets the password used to open the document.
902///
903/// @return The password used to open the document, or NULL
904///         if no password was used.
905///
906const gchar *
907IDocument::getPassword () const
908{
909    return m_Password;
910}
911
912///
913/// @brief Sets the password user to open the document.
914///
915/// @param password The password used.
916///
917void
918IDocument::setPassword (const gchar *password)
919{
920    gchar *oldPassword = m_Password;
921    m_Password = g_strdup (password);
922    g_free (oldPassword);
923}
924
925///
926/// @brief Sets the document's number of pages.
927///
928/// @param numPages The number of pages the document has.
929///
930void
931IDocument::setNumPages (gint numPages)
932{
933    m_PageNumber = numPages;
934}
935
936///
937/// @brief Gets the document's file name.
938///
939/// @return The file name that contains the document, or an empty string
940///         if the document isn't loaded yet.
941///
942const gchar *
943IDocument::getFileName () const
944{
945    if ( NULL == m_FileName )
946    {
947        return "";
948    }
949    return m_FileName;
950}
951
952///
953/// @brief Sets the document's file name.
954///
955/// @param fileName The name to set as the document's file name.
956///
957void
958IDocument::setFileName (const gchar *fileName)
959{
960    g_assert (NULL != fileName && "Tried to set a NULL file name.");
961
962    // Don't ask me why, but then I set like this:
963    //      g_free (m_FileName);
964    //      m_FileName = fileName
965    // Somehow the g_free also frees the parameter ????????
966    //     
967    gchar *oldFileName = m_FileName;
968    m_FileName = g_strdup (fileName);
969    g_free (oldFileName);
970}
971
972///
973/// @brief Gets the document's current page image.
974///
975/// @return The rendered image of the current page or NULL if the image
976///         is not yet available.
977///
978
979DocumentPage *
980IDocument::getCurrentPage ()
981{
982    PageCache *cachedPage = getCachedPage (m_CurrentPage);
983    if ( NULL == cachedPage )
984    {
985        return NULL;
986    }
987
988    G_LOCK (pageImage);
989    DocumentPage *pageImage = cachedPage->pageImage;
990    G_UNLOCK (pageImage);
991
992    if ( NULL != pageImage )
993    {
994        /// XXX: Only non rotated documents for now.
995        if ( m_FindPage == m_CurrentPage && NULL != m_FindRect &&
996             0 == getRotation () )
997        {
998            pageImage->setSelection (*m_FindRect, getZoom ());
999        }
1000        else
1001        {
1002            pageImage->clearSelection ();
1003        }
1004    }
1005
1006    return pageImage;
1007}
1008
1009///
1010/// @brief Gets an empty page of the same size than the current page.
1011///
1012/// This is used when the page is now ready on the cache and the presenter
1013/// wants to show something to the user. This function just will create
1014/// an empty document (i.e., no text or image) using the size that the
1015/// page would have it it was rendered.
1016///
1017/// @return An DocumentPage whose image is just a blank page. The caller
1018///         must delete this DocumentPage object.
1019///
1020DocumentPage *
1021IDocument::getEmptyPage ()
1022{
1023    gdouble pageWidth;
1024    gdouble pageHeight;
1025    getPageSizeForPage (getCurrentPageNum (), &pageWidth, &pageHeight);
1026    gint width = MAX((gint) ((pageWidth * getZoom ()) + 0.5), 1);
1027    gint height = MAX((gint) ((pageHeight * getZoom ()) + 0.5) , 1);
1028    DocumentPage *emptyPage = new DocumentPage ();
1029    emptyPage->newPage (width, height);
1030
1031    return emptyPage;
1032}
1033
1034///
1035/// @brief Get the document's current page number.
1036///
1037/// @return The number of the current page that we are viewing or 0 if the
1038///         document has not been loaded yet.
1039///
1040gint
1041IDocument::getCurrentPageNum ()
1042{
1043    return m_CurrentPage;
1044}
1045
1046///
1047/// @brief Get the document's outline.
1048///
1049/// @return The top level DocumentOutline for this document.
1050///         The returned object must not be freed, the
1051///         IDocument class will do it.
1052///
1053DocumentOutline *
1054IDocument::getOutline ()
1055{
1056    return m_Outline;
1057}
1058
1059///
1060/// @brief Gets the current page's unscaled size.
1061///
1062/// Retrieves the width and height of the current page before to scale, but
1063/// after rotation.
1064///
1065/// @param width The output pointer to save the page's width.
1066/// @param height The output pointer to save the page's height.
1067///
1068void
1069IDocument::getPageSize (gdouble *width, gdouble *height)
1070{
1071    getPageSizeForPage (getCurrentPageNum (), width, height);
1072}
1073
1074///
1075/// @brief Goes to the document's first page.
1076///
1077/// Changes the current page to be the first page of the
1078/// document.
1079///
1080void
1081IDocument::goToFirstPage ()
1082{
1083    goToPage (1);
1084}
1085
1086///
1087/// @brief Goes to the document's last page.
1088///
1089/// Changes the current page to be the last page of the
1090/// document.
1091///
1092void
1093IDocument::goToLastPage ()
1094{
1095    goToPage (getNumPages ());
1096}
1097
1098///
1099/// @brief Goes the the document's next page.
1100///
1101/// Changes the current page to be the next page. If the current page is
1102/// already the last, then it will not change.
1103///
1104void
1105IDocument::goToNextPage ()
1106{
1107    goToPage (getCurrentPageNum() + 1);
1108}
1109
1110///
1111/// @brief Goes to a document page.
1112///
1113/// Changes the current page to be the page @a pageNum. If @a pageNum is
1114/// greater than the document's last page, then the current page becomes
1115/// the last page. If @a pageNum is instead less then the first page (i.e.,
1116/// <= 0) then the current page becomes the first (i.e., 1).
1117///
1118/// @param pageNum The page index to go to.
1119///
1120void
1121IDocument::goToPage (gint pageNum)
1122{
1123    if ( pageNum != m_CurrentPage && 1 <= pageNum && pageNum <= getNumPages ())
1124    {
1125        m_CurrentPage = pageNum;
1126
1127        addPageToCache (m_CurrentPage);
1128        if ( 1 < m_CurrentPage )
1129        {
1130            addPageToCache (m_CurrentPage - 1);
1131        }
1132        if ( m_CurrentPage < getNumPages () )
1133        {
1134            addPageToCache (m_CurrentPage + 1);
1135        }
1136
1137        notifyPageChanged ();
1138    }
1139}
1140
1141///
1142/// @brief Goes to the document's previous page.
1143///
1144/// Changes the current page to be the previous page. If the current page
1145/// is already the first page, then it will not change.
1146///
1147void
1148IDocument::goToPreviousPage ()
1149{
1150    goToPage (getCurrentPageNum () - 1);
1151}
1152
1153///
1154/// @brief Gets the current rotation degrees.
1155///
1156/// @return The current document's rotation degrees.
1157///
1158gint
1159IDocument::getRotation ()
1160{
1161    return m_Rotation;
1162}
1163
1164///
1165/// @brief Sets the current rotation degrees.
1166///
1167/// @param rotation The rotation in positive degrees.
1168///                 If the parameter is greater than 360 degrees, its set
1169///                 between 0 and 360 as a result of @a rotation % 360.
1170///
1171void
1172IDocument::setRotation (gint rotation)
1173{
1174    if ( rotation != m_Rotation )
1175    {
1176        G_LOCK (JobRender);
1177        m_Rotation = (rotation % 360);
1178        refreshCache ();
1179        G_UNLOCK (JobRender);
1180        notifyPageRotated ();
1181    }
1182}
1183
1184///
1185/// @brief Rotates 90 to the left.
1186///
1187/// Substract 90 degrees to the document's rotation.
1188///
1189void
1190IDocument::rotateLeft ()
1191{
1192    gint rotation = (getRotation () - 90);
1193    if ( rotation < 0 )
1194    {
1195        rotation += 360;
1196    }
1197    setRotation (rotation);
1198}
1199
1200///
1201/// @brief Rotates 90 to the right.
1202///
1203/// Adds 90 degrees to the document's rotation.
1204///
1205void
1206IDocument::rotateRight ()
1207{
1208    setRotation (getRotation () + 90);
1209}
1210
1211///
1212/// @brief Checks if is possible to zoom in.
1213///
1214/// Checks if after zooming in the zoom level will be below the max level.
1215///
1216gboolean
1217IDocument::canZoomIn (void)
1218{
1219    return ( getZoom () * ZOOM_IN_FACTOR <= ZOOM_IN_MAX );
1220}
1221
1222///
1223/// @brief Checks if is possible to zoom out.
1224///
1225/// Checks if after zooming out the zoom level will be above the min level.
1226///
1227gboolean
1228IDocument::canZoomOut (void)
1229{
1230    return ( getZoom () * ZOOM_OUT_FACTOR >= ZOOM_OUT_MAX );
1231}
1232
1233///
1234/// @brief Gets the current zoom.
1235///
1236/// @return The current zoom or scale level.
1237///
1238gdouble
1239IDocument::getZoom (void)
1240{
1241    return m_Scale;
1242}
1243
1244///
1245/// @brief Sets the current zoom.
1246///
1247/// @param zoom The new zoom level.
1248///
1249void
1250IDocument::setZoom (gdouble zoom)
1251{
1252    if ( ABS (zoom - m_Scale) > 0.00001 )
1253    {
1254        G_LOCK (JobRender);
1255        m_Scale = CLAMP (zoom, ZOOM_OUT_MAX, ZOOM_IN_MAX);
1256        refreshCache ();
1257        G_UNLOCK (JobRender);
1258        notifyPageZoomed ();
1259    }
1260}
1261
1262///
1263/// @brief Zooms In.
1264///
1265/// Adds a fixed amount to the scale / zoom level if the zoom level has not
1266/// reached the max.
1267///
1268/// @see canZoomIn()
1269///
1270void
1271IDocument::zoomIn (void)
1272{
1273    if (canZoomIn ())
1274    {
1275        setZoom (getZoom () * ZOOM_IN_FACTOR);
1276    }
1277}
1278
1279///
1280/// @brief Zooms Out.
1281///
1282/// Substracts a fixed amount to the scale / zoom level is the zoom level
1283/// has not reached the min.
1284///
1285/// @see canZoomOut()
1286///
1287void
1288IDocument::zoomOut (void)
1289{
1290    if (canZoomOut ())
1291    {
1292        setZoom (getZoom () * ZOOM_OUT_FACTOR);
1293    }
1294}
1295
1296///
1297/// @brief Zooms the document to fit the width and the height.
1298///
1299/// It tries to get the best zoom / scale level that will let the
1300/// document fit into @a width and @a height.
1301///
1302/// @param width The width to fit the document to.
1303/// @param height The height to fit the document to.
1304///
1305void
1306IDocument::zoomToFit (gint width, gint height)
1307{
1308    gdouble pageWidth;
1309    gdouble pageHeight;
1310
1311    getPageSize (&pageWidth, &pageHeight);
1312    // In this case we are interested in the minimum zoom level,
1313    // as is the one that fits best.
1314    gdouble widthScale = (gdouble)width / pageWidth;
1315    gdouble heightScale = (gdouble)height / pageHeight;
1316    setZoom (MIN (widthScale, heightScale));
1317}
1318
1319///
1320/// @brief Zooms the document to fit the width.
1321///
1322/// It tries to get the best zooms / scale level that will let the document
1323/// fit into @a width, without looking into any height.
1324///
1325/// @param width The width to fit the document to.
1326///
1327void
1328IDocument::zoomToWidth (gint width)
1329{
1330    gdouble pageWidth;
1331    gdouble pageHeight;
1332
1333    getPageSize (&pageWidth, &pageHeight);
1334    setZoom ((gdouble)width / pageWidth);
1335}
1336
1337///
1338/// @brief Adds a new page to the cache and starts to render it.
1339///
1340/// This function checks if a page is already on the cache. If it is, then
1341/// only updates the age and returns. Otherwise adds the page to the cache and
1342/// creates a new job for rendering it.
1343///
1344/// After adding the new page, if the cache size is larger that it should be,
1345/// then this deletes the oldest request from the cache.
1346///
1347/// @param pageNum The page number to add to the cache.
1348///
1349void
1350IDocument::addPageToCache (gint pageNum)
1351{
1352    // Check if the page is already on cache.
1353    PageCache *cached = getCachedPage (pageNum);
1354    // If it's not.
1355    G_LOCK (pageImage);
1356    if ( NULL == cached || NULL == cached->pageImage )
1357    {
1358        G_UNLOCK (pageImage);
1359        //Create it.
1360        cached = new PageCache;
1361        cached->age = m_PageCacheAge++;
1362        cached->pageNumber = pageNum;
1363        cached->pageImage = NULL;
1364
1365        JobRender *job = new JobRender ();
1366        job->setAge (cached->age);
1367        job->setDocument (this);
1368        job->setPageNumber (pageNum);
1369        IJob::enqueue (job);
1370
1371        G_LOCK (pageSearch);
1372        // Check which cached page to drop.
1373        if ( g_list_length (m_PageCache) >= CACHE_SIZE )
1374        {
1375            PageCache *oldestCachedPage = NULL;
1376            guint32 oldestAge = G_MAXUINT32;
1377            for ( GList *page = g_list_first (m_PageCache) ; NULL != page ;
1378                  page = g_list_next (page) )
1379            {
1380                PageCache *tmpCachedPage = (PageCache *)page->data;
1381                if ( tmpCachedPage->age < oldestAge )
1382                {
1383                    oldestAge = tmpCachedPage->age;
1384                    oldestCachedPage = tmpCachedPage;
1385                }
1386            }
1387            m_PageCache = g_list_remove_all (m_PageCache, oldestCachedPage);
1388            G_LOCK (JobRender);
1389            JobRender::setMinAge (oldestCachedPage->age);
1390            G_UNLOCK (JobRender);
1391            G_LOCK (pageImage);
1392            delete oldestCachedPage->pageImage;
1393            G_UNLOCK (pageImage);
1394            delete oldestCachedPage;           
1395        }
1396        // Add the page to the cache.
1397        m_PageCache = g_list_append (m_PageCache, cached);
1398        G_UNLOCK (pageSearch);
1399    }
1400    else
1401    {
1402        G_UNLOCK (pageImage);
1403        // If the page is already on cache, just update the age.
1404        cached->age = m_PageCacheAge++;
1405    }
1406}
1407
1408///
1409/// @brief Retrieves a page from the cache.
1410///
1411/// @param pageNum The number of the page to get from the cache.
1412///
1413/// @return The page cached if the page is in the cache or NULL if it's not
1414///         in the cache.
1415///
1416PageCache *
1417IDocument::getCachedPage (gint pageNum)
1418{
1419    G_LOCK (pageSearch);
1420    PageCache *cached = NULL;
1421    for ( GList *page = g_list_first (m_PageCache) ;
1422          NULL != page && NULL == cached ;
1423          page = g_list_next (page) )
1424    {
1425        PageCache *tmpCached = (PageCache *)page->data;
1426        if ( NULL != tmpCached && pageNum == tmpCached->pageNumber )
1427        {
1428            cached = tmpCached;
1429        }
1430    }
1431    G_UNLOCK (pageSearch);
1432
1433    return cached;
1434}
1435
1436///
1437/// @brief Refreshes the cache list.
1438///
1439/// Renders again all requested pages on the cache that had been rendered
1440/// already.  This is useful when rotating or zooming.
1441///
1442void
1443IDocument::refreshCache ()
1444{
1445    gint pag