Changeset 124

Show
Ignore:
Timestamp:
04/29/06 02:29:35 (2 years ago)
Author:
jordi
Message:

The IDocument is now "observable": observers can attach themselves to the document that will call the notify methods when the document changes.

Also, is now the document that is threaded when loading a file instead of the MainPter? class, but instead of create the thread each time the document load I created an abstract class IJob that all jobs will derive from (load jobs, render jobs, etc.). This new class also creates a single threaded function that waits for a job to enter the queue and then runs it. That simple ;-)

To easier see the tests resuls I have removed temporarly all tests suites except the ConfigTest? (which have nothing to do with the document) and the PDFDocument, although mosts of the methods are commented out.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/IDocument.cxx

    r122 r124  
    177177    m_Creator = NULL; 
    178178    m_CurrentPage = 0; 
     179    m_Observers = NULL; 
    179180    m_Outline = NULL; 
    180181    m_FileName = NULL; 
     
    218219    g_async_queue_push (m_RenderQueue, (gpointer)request); 
    219220 
     221    g_list_free (m_Observers); 
    220222    delete m_Outline; 
    221223    g_free (m_Author); 
     
    231233    g_free (m_Subject); 
    232234    g_free (m_Title); 
     235} 
     236 
     237void 
     238IDocument::attach (const IDocumentObserver *observer) 
     239{ 
     240    g_assert (NULL != observer && "Tried to attach a NULL observer."); 
     241     
     242    m_Observers = g_list_prepend (m_Observers, (gpointer)observer); 
     243} 
     244 
     245void 
     246IDocument::deattach (const IDocumentObserver *observer) 
     247{ 
     248    g_assert (NULL != observer && "Tried to deattach a NULL observer."); 
     249 
     250    m_Observers = g_list_remove_all (m_Observers, observer); 
     251} 
     252 
     253void 
     254IDocument::notifyLoadError (GError *error) 
     255{ 
     256    for ( GList *item = g_list_first (m_Observers) ; NULL != item ; 
     257          item = g_list_next (item) ) 
     258    { 
     259        IDocumentObserver *observer = (IDocumentObserver *)item->data; 
     260        observer->notifyLoadError (error); 
     261    } 
     262    g_error_free (error); 
     263} 
     264 
     265void 
     266IDocument::load (const gchar *fileName, const gchar *password) 
     267{ 
     268    JobLoad *job = new JobLoad (); 
     269    job->setDocument (this); 
     270    job->setFileName (fileName); 
     271    job->setPassword (NULL); 
     272 
     273    IJob::queue (job); 
    233274} 
    234275 
  • trunk/src/IDocument.h

    r121 r124  
    2525{ 
    2626    // Forward declarations. 
     27    class DocumentIndex; 
     28    class IDocumentObserver; 
    2729    class DocumentPage; 
    28     class DocumentIndex; 
    2930 
    3031    /// 
     
    173174            virtual DocumentPage *renderPage (gint pageNum) = 0; 
    174175 
     176            void attach (const IDocumentObserver *observer); 
     177            void deattach (const IDocumentObserver *observer); 
     178 
     179            void notifyLoadError (GError *error); 
    175180             
    176181            const gchar *getTitle (void); 
     
    211216            void clearCache (void); 
    212217 
     218            void load (const gchar *fileName, const gchar *password); 
     219 
    213220            void goToFirstPage (void); 
    214221            void goToLastPage (void); 
     
    251258            gchar *m_Linearized; 
    252259            gchar *m_ModifiedDate; 
     260            GList *m_Observers; 
    253261            DocumentOutline *m_Outline; 
    254262            GList *m_PageCache; 
  • trunk/src/JobLoad.cxx

    r117 r124  
    2525static gboolean job_load_error (gpointer data); 
    2626static gboolean job_load_password (gpointer data); 
    27 static gpointer job_load_run (gpointer data); 
    2827 
    2928/// 
    3029/// @brief Constructs a new JobLoad object. 
    3130/// 
    32 JobLoad::JobLoad () 
     31JobLoad::JobLoad (): 
     32    IJob () 
    3333{ 
    3434    m_FileName = NULL; 
    3535    m_Error = NULL; 
    36     m_PageNum = 0; 
    3736    m_Password = NULL; 
    38     m_PasswordTries = 3; 
    39     m_Presenter = NULL; 
    40     m_Reload = FALSE; 
    41     m_Rotation = 0; 
    42     m_Zoom = 0.0; 
     37    m_Document = NULL; 
    4338} 
    4439 
     
    5752 
    5853/// 
    59 /// @brief Checks if a new password can be tried. 
    60 /// 
    61 /// This function checks if we passed the number of time we can try a 
    62 /// password. 
    63 /// 
    64 /// Be warned that this function alters the number of tries left. 
    65 /// 
    66 /// @return TRUE if we can try another password, FALSE otherwise. 
    67 /// 
    68 gboolean 
    69 JobLoad::canTryPassword () 
    70 { 
    71     if ( m_PasswordTries > 0 ) 
    72     { 
    73         m_PasswordTries--; 
    74         return TRUE; 
    75     } 
    76  
    77     return FALSE; 
    78 } 
    79  
    80 /// 
    8154/// @brief Gets the file name to load or reload. 
    8255/// 
     
    10174 
    10275/// 
    103 /// @brief Gets the previously used page num. 
    104 /// 
    105 /// This is for reloading, gives the page where we were before reloading 
    106 /// the document. 
    107 /// 
    108 /// @return The numbe of the page where we were. 
    109 /// 
    110 gint 
    111 JobLoad::getPageNum () 
    112 { 
    113     return m_PageNum; 
    114 } 
    115  
    116 /// 
    11776/// @brief Gets the password. 
    11877/// 
     
    12685 
    12786/// 
    128 /// @brief The presenter that's opening the file. 
    129 /// 
    130 /// @return The presenter that is loading or reloading the document. 
    131 /// 
    132 MainPter & 
    133 JobLoad::getPresenter () 
    134 
    135     g_assert (NULL != m_Presenter && "The presenter is NULL."); 
    136  
    137     return *m_Presenter; 
    138 
    139  
    140 /// 
    141 /// @brief Gets the previously used rotation. 
    142 /// 
    143 /// This is for reloading. Gets the rotation of the document before reloading. 
    144 /// 
    145 /// @return The degrees the document was rotated before. 
    146 /// 
    147 gint 
    148 JobLoad::getRotation () 
    149 
    150     return m_Rotation; 
    151 
    152  
    153 /// 
    154 /// @brief Gets the previously used zoom. 
    155 /// 
    156 /// This is for reloading. Gets the zoom of the document before reloading. 
    157 /// 
    158 /// @return The degrees the document was zoomed before. 
    159 /// 
    160 gdouble 
    161 JobLoad::getZoom () 
    162 
    163     return m_Zoom; 
    164 
    165  
    166 /// 
    167 /// @brief Checks if we are reloading. 
    168 /// 
    169 /// @return TRUE if we are reloading, FALSE otherwise. 
    170 /// 
    171 gboolean 
    172 JobLoad::isReload () 
    173 
    174     return m_Reload; 
    175 
     87/// @brief The document that's loading. 
     88/// 
     89/// @return The document that is loading. 
     90/// 
     91IDocument & 
     92JobLoad::getDocument () 
     93
     94    g_assert (NULL != m_Document && "The document is NULL."); 
     95 
     96    return *m_Document; 
     97
     98 
    17699 
    177100/// 
    178101/// @brief Open the document. 
    179102/// 
    180 /// This function will insensitive the Open and Reload actions, set 
    181 /// the view's status bar text, sets the wait cursor, and creates a new thread 
    182 /// that opens the document. 
    183 /// 
    184 void 
     103/// 
     104gboolean 
    185105JobLoad::run () 
    186106{ 
    187     if ( !g_thread_supported () ) 
    188     { 
    189         g_thread_init (NULL); 
    190     } 
    191      
    192     // Unsensitive the open and reload actions. 
    193     IMainView &view = getPresenter ().getView (); 
    194     view.sensitiveOpen (FALSE); 
    195     view.sensitiveReload (FALSE); 
    196     // Show the statusbar text. 
    197     gchar *statusText = NULL; 
    198     if ( isReload () ) 
    199     { 
    200         statusText = g_strdup_printf (_("Reloading file %s..."),  
    201                                         getFileName ()); 
     107    GError *error = NULL; 
     108    if ( getDocument ().loadFile (getFileName (), getPassword (), &error) ) 
     109    { 
     110        JOB_NOTIFIER (job_load_done, this); 
     111    } 
     112    else if ( DocumentErrorEncrypted == error->code ) 
     113    { 
     114        g_error_free (error); 
     115        JOB_NOTIFIER (job_load_password, this); 
    202116    } 
    203117    else 
    204118    { 
    205         statusText = g_strdup_printf (_("Loading file %s..."), getFileName ()); 
    206     } 
    207     view.setStatusBarText (statusText); 
    208     g_free (statusText); 
    209     // Set the cursor. 
    210     view.setCursor (MAIN_VIEW_CURSOR_WAIT); 
    211  
    212     GError *error = NULL; 
    213     if ( NULL == g_thread_create (job_load_run, this, FALSE, &error) ) 
    214     { 
    215         g_warning ("Couldn't create thread: %s\n", error->message); 
    216         g_error_free (error); 
    217     } 
     119        setError (error); 
     120        JOB_NOTIFIER (job_load_error, this); 
     121    } 
     122    return FALSE; 
    218123} 
    219124 
     
    246151 
    247152/// 
    248 /// @brief Sets the page number. 
    249 /// 
    250 /// This is used for reloading, see getPageNum(). 
    251 /// 
    252 /// @param pageNum The page to go when the document is reloaded. 
    253 /// 
    254 void 
    255 JobLoad::setPage (gint pageNum) 
    256 { 
    257     m_PageNum = pageNum; 
    258 } 
    259  
    260 /// 
    261153/// @brief Sets the password to open the document. 
    262154/// 
     
    271163 
    272164/// 
    273 /// @brief Sets the presenter that loads the document. 
    274 /// 
    275 /// @param pter The MainPter that will load the document. 
    276 /// 
    277 void 
    278 JobLoad::setPresenter (MainPter *pter) 
    279 
    280     m_Presenter = pter; 
    281 
    282  
    283 /// 
    284 /// @brief Sets if we are reloading. 
    285 /// 
    286 /// @param reload TRUE if we are reloading, false otherwise. 
    287 /// 
    288 void 
    289 JobLoad::setReload (gboolean reload) 
    290 
    291     m_Reload = reload; 
    292 
    293  
    294 /// 
    295 /// @brief Sets the rotation to use after reloading. 
    296 /// 
    297 /// @param rotation The degrees of rotation. 
    298 /// 
    299 void 
    300 JobLoad::setRotation (gint rotation) 
    301 
    302     m_Rotation = rotation; 
    303 
    304  
    305 /// 
    306 /// @brief Sets the zoom to use after reloading. 
    307 /// 
    308 /// @param zoom The level of zoom. 
    309 /// 
    310 void 
    311 JobLoad::setZoom (gdouble zoom) 
    312 
    313     m_Zoom = zoom; 
    314 
     165/// @brief Sets the document to load. 
     166/// 
     167/// @param document The document that will load. 
     168/// 
     169void 
     170JobLoad::setDocument (IDocument *document) 
     171
     172    g_assert ( NULL != document && "Tried to set a NULL document."); 
     173     
     174    m_Document = document; 
     175
     176 
    315177 
    316178//////////////////////////////////////////////////////////////// 
     
    319181 
    320182/// 
    321 /// @brief The load is finished. 
    322 /// 
    323 /// This can be called either when the document was loaded correctly or  
    324 /// after an error. What it does is set the presenter in a known state 
    325 /// ready to be used again. 
     183/// @brief The load is finished correctly. 
     184/// 
     185/// @param data This parameter holds the JobLoad that finished. 
     186///  
     187gboolean 
     188job_load_done (gpointer data) 
     189
     190    g_assert (NULL != data && "The data parameter is NULL."); 
     191 
     192    JobLoad *job = (JobLoad *)data; 
     193 
     194    return FALSE; 
     195
     196 
     197/// 
     198/// @brief The load had errors. 
     199/// 
     200/// This is called when the load of the document had any error except 
     201/// when it's encrypted. 
    326202/// 
    327203/// @param data This parameter hold the JobLoad to open. 
    328204///  
    329205gboolean 
    330 job_load_done (gpointer data) 
     206job_load_error (gpointer data) 
    331207{ 
    332208    g_assert (NULL != data && "The data parameter is NULL."); 
    333209 
    334210    JobLoad *job = (JobLoad *)data; 
    335     job->getPresenter ().setInitialState (!job->isReload ()); 
    336     if ( job->isReload () ) 
    337     { 
    338         job->getPresenter ().setContext (job->getPageNum (),  
    339                                          job->getRotation (), job->getZoom ()); 
    340     } 
    341     delete job; 
    342  
     211    job->getDocument ().notifyLoadError (job->getError ()); 
     212     
    343213    return FALSE; 
    344 } 
    345  
    346 /// 
    347 /// @brief The load had errors. 
    348 /// 
    349 /// This is called when the load of the document had any error except 
    350 /// when it's encrypted. 
    351 /// 
    352 /// @param data This parameter hold the JobLoad to open. 
    353 ///  
    354 gboolean 
    355 job_load_error (gpointer data) 
    356 { 
    357     g_assert (NULL != data && "The data parameter is NULL."); 
    358  
    359     JobLoad *job = (JobLoad *)data; 
    360     job->getPresenter ().getView ().showErrorMessage (_("Error Loading File"), 
    361                                                     job->getError ()->message); 
    362     job->setReload (FALSE); 
    363     return job_load_done (data); 
    364214} 
    365215 
     
    381231 
    382232    JobLoad *job = (JobLoad *)data; 
    383     if ( job->canTryPassword () ) 
    384     { 
    385         gchar *password =  
    386             job->getPresenter ().getView ().promptPasswordDialog (); 
    387         if ( password != NULL ) 
    388         { 
    389             job->setPassword (password); 
    390             g_free (password); 
    391             GError *error = NULL; 
    392             if ( NULL == g_thread_create (job_load_run, job, FALSE, &error) ) 
    393             { 
    394                 g_warning ("Couldn't create thread: %s\n", error->message); 
    395                 g_error_free (error); 
    396             } 
    397             return FALSE; 
    398         } 
    399     } 
    400     else 
    401     { 
    402         job->getPresenter ().getView ().showErrorMessage ( 
    403                 _("Error Loading File"), 
    404                 _("The password you have supplier is not a valid password " 
    405                   "for this file.")); 
    406     } 
    407233 
    408234    return job_load_done (data); 
    409235} 
    410  
    411 /// 
    412 /// @brief Opens the files. 
    413 /// 
    414 /// This is the threaded function that will try to call the presenter's 
    415 /// loading function with the given file name and password. This function 
    416 /// just tests if the load was successful or not and then tells glib to  
    417 /// call the actual end function, that will show the result to the user. 
    418 /// 
    419 /// When this function is compiled with DEBUG defined, the calls to the 
    420 /// "end" functions aren't scheduled by glib, since the test framework doesn't 
    421 /// use it. 
    422 /// 
    423 /// @param data This parameter hold the JobLoad to open. 
    424 /// 
    425 gpointer 
    426 job_load_run (gpointer data) 
    427 { 
    428     g_assert (NULL != data && "The data parameter is NULL."); 
    429  
    430     JobLoad *job = (JobLoad *)data; 
    431     GError *error = NULL; 
    432     if ( job->getPresenter ().openDocument (job->getFileName (),  
    433                                             job->getPassword (), &error) ) 
    434     { 
    435 #if defined DEBUG 
    436         job_load_done (job); 
    437 #else 
    438         g_idle_add (job_load_done, job); 
    439 #endif 
    440     } 
    441     else if ( DocumentErrorEncrypted == error->code ) 
    442     { 
    443         g_error_free (error); 
    444 #if defined DEBUG 
    445         job_load_password (job); 
    446 #else 
    447         g_idle_add (job_load_password, job); 
    448 #endif 
    449     } 
    450     else 
    451     { 
    452         job->setError (error); 
    453 #if defined DEBUG 
    454         job_load_error (job); 
    455 #else 
    456         g_idle_add (job_load_error, job); 
    457 #endif 
    458     } 
    459  
    460     return NULL; 
    461 } 
  • trunk/src/JobLoad.h

    r117 r124  
    2222{ 
    2323    // Forward declarations. 
    24     class MainPter
     24    class IDocument
    2525    
    2626    /// 
     
    2828    /// @brief A background job that loads a file. 
    2929    /// 
    30     /// This class is used to load and reload the PDF files. It creates 
    31     /// a thread that loads a file name. 
     30    /// This class is used to load and reload the PDF files. 
    3231    /// 
    33     class JobLoad 
     32    class JobLoad: public IJob 
    3433    { 
    3534        public: 
     
    3736            ~JobLoad (void); 
    3837 
    39             gboolean canTryPassword (void); 
     38            IDocument &getDocument (void); 
     39            GError *getError (void); 
    4040            const gchar *getFileName (void); 
    41             GError *getError (void); 
    42             gint getPageNum (void); 
    4341            const gchar *getPassword (void); 
    44             MainPter &getPresenter (void); 
    45             gint getRotation (void); 
    46             gdouble getZoom (void); 
    47             gboolean isReload (void); 
    48             void run (void); 
     42            gboolean run (void); 
    4943            void setFileName (const gchar *fileName); 
    5044            void setError (GError *error); 
    51             void setPage (gint pageNum); 
    5245            void setPassword (const gchar *password); 
    53             void setPresenter (MainPter *pter); 
    54             void setReload (gboolean reload); 
    55             void setRotation (gint rotation); 
    56             void setZoom (gdouble zoom); 
     46            void setDocument (IDocument *document); 
    5747 
    5848        protected: 
    5949            gchar *m_FileName; 
    6050            GError *m_Error; 
    61             gint m_PageNum; 
    6251            gchar *m_Password; 
    63             gint m_PasswordTries; 
    64             MainPter *m_Presenter; 
    65             gboolean m_Reload; 
    66             gint m_Rotation; 
    67             gdouble m_Zoom; 
     52            IDocument *m_Document; 
    6853    }; 
    6954} 
  • trunk/src/MainPter.cxx

    r123 r124  
    292292 
    293293    // Open the file. 
    294     JobLoad *job = new JobLoad (); 
     294/*    JobLoad *job = new JobLoad (); 
    295295    job->setPresenter (this); 
    296296    job->setFileName (fileName); 
     
    298298    job->setPassword (NULL); 
    299299    job->setReload (FALSE); 
    300     job->run (); 
     300    job->run ();*/ 
    301301} 
    302302 
     
    363363{    
    364364    // Reopen the document. 
    365     JobLoad *job = new JobLoad (); 
     365/*    JobLoad *job = new JobLoad (); 
    366366    job->setPresenter (this); 
    367367    job->setFileName (m_Document->getFileName ()); 
     
    372372    job->setRotation (m_Document->getRotation ()); 
    373373    job->setZoom ( m_Document->getZoom ()); 
    374     job->run (); 
     374    job->run ();*/ 
    375375} 
    376376 
  • trunk/src/Makefile.am

    r115 r124  
    1313    epdfview.h          \ 
    1414    gettext.h           \ 
     15    IJob.cxx    \ 
     16    IJob.h  \ 
    1517    IDocument.cxx       \ 
    1618    IDocument.h         \ 
     19    IDocumentObserver.h \ 
    1720    JobLoad.cxx         \ 
    1821    JobLoad.h           \ 
  • trunk/src/epdfview.h

    r115 r124  
    2626#include <DocumentOutline.h> 
    2727#include <DocumentPage.h> 
     28#include <IDocumentObserver.h> 
    2829#include <IDocument.h> 
    2930#include <PDFDocument.h> 
     
    3233#include <MainPter.h> 
    3334 
     35#include <IJob.h> 
    3436#include <JobLoad.h> 
    3537 
  • trunk/tests/Makefile.am

    r101 r124  
    1010    ConfigTest.cxx          \ 
    1111    ConfigTest.h            \ 
    12     DocumentOutlineTest.cxx \ 
    13     DocumentOutlineTest.h   \ 
    1412    DumbDocument.cxx        \ 
    1513    DumbDocument.h          \ 
     14    DumbDocumentObserver.cxx    \ 
     15    DumbDocumentObserver.h  \ 
    1616    DumbMainView.cxx        \ 
    1717    DumbMainView.h          \ 
    1818    main.cxx                \ 
    19     MainPterTest.cxx        \ 
    20     MainPterTest.h          \ 
    2119    PDFDocumentTest.cxx     \ 
    2220    PDFDocumentTest.h       \ 
    2321    Utils.cxx               \ 
    2422    Utils.h 
     23 
     24 
     25#   DocumentOutlineTest.cxx 
     26#   DocumentOutlineTest.h 
     27#   MainPterTest.cxx 
     28#   MainPterTest.h 
    2529 
    2630test_epdfview_CXXFLAGS =                        \ 
  • trunk/tests/PDFDocumentTest.cxx

    r122 r124  
    1818#include <epdfview.h> 
    1919#include "Utils.h" 
     20#include "DumbDocumentObserver.h" 
    2021#include "PDFDocumentTest.h" 
    2122 
     
    3334{ 
    3435    m_Document = new PDFDocument (); 
     36    m_Observer = new DumbDocumentObserver (); 
     37    m_Document->attach (m_Observer); 
    3538} 
    3639 
     
    4144PDFDocumentTest::tearDown () 
    4245{ 
     46    m_Document->deattach (m_Observer); 
     47    delete m_Observer; 
    4348    delete m_Document; 
    4449} 
     
    9499PDFDocumentTest::fileNotFound (void) 
    95100{ 
    96     GError *error = NULL; 
    97101    gchar *testFile = getTestFile ("noFile.pdf"); 
    98     CPPUNIT_ASSERT (!m_Document->loadFile (testFile, NULL, &error)); 
     102    m_Document->load (testFile, NULL); 
     103    while ( !m_Observer->loadFinished () ) { } 
    99104    CPPUNIT_ASSERT (!m_Document->isLoaded ()); 
    100      
     105    CPPUNIT_ASSERT (m_Observer->notifiedError ()); 
     106 
    101107    gchar *documentError = IDocument::getErrorMessage(DocumentErrorOpenFile); 
    102108    gchar *errorMessage = g_strdup_printf ( 
    103109            "Failed to load document '%s'.\n%s\n", testFile, documentError); 
    104110    g_free(documentError); 
     111    const GError *error = m_Observer->getLoadError (); 
    105112    DocumentError errorCode = (DocumentError)error->code; 
    106113    CPPUNIT_ASSERT_EQUAL (DocumentErrorOpenFile, errorCode); 
     
    109116    g_free (errorMessage); 
    110117    g_free (testFile); 
    111     g_error_free (error); 
    112 
    113  
     118
     119/* 
    114120/// 
    115121/// @brief Test that loading an invalid file fails. 
     
    123129    GError *error = NULL; 
    124130    gchar *testFile = getTestFile ("PDFDocumentTest.cxx"); 
    125     CPPUNIT_ASSERT (!m_Document->loadFile (testFile, NULL, &error)); 
     131    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, &error)); 
     132    while ( !m_Observer->loadFinished () ) { } 
    126133    CPPUNIT_ASSERT (!m_Document->isLoaded ()); 
     134    CPPUNIT_ASSERT (m_Observer->notifiedError ()); 
    127135 
    128136    gchar *documentError = IDocument::getErrorMessage(DocumentErrorDamaged); 
     
    130138            "Failed to load document '%s'.\n%s\n", testFile, documentError); 
    131139    g_free(documentError); 
     140    error = m_Observer->getLoadError (); 
    132141    DocumentError errorCode = (DocumentError)error->code; 
    133142    CPPUNIT_ASSERT_EQUAL (DocumentErrorDamaged, errorCode); 
     
    136145    g_free (testFile); 
    137146    g_free (errorMessage); 
    138     g_error_free (error); 
    139147} 
    140148 
     
    152160    GError *error = NULL; 
    153161    gchar *testFile = getTestFile ("test_encrypted.pdf"); 
    154     CPPUNIT_ASSERT (!m_Document->loadFile (testFile, NULL, &error)); 
     162    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, &error)); 
     163    while ( !m_Observer->loadFinished () ) { } 
    155164    CPPUNIT_ASSERT (!m_Document->isLoaded ()); 
     165    CPPUNIT_ASSERT (m_Observer->notifiedPassword ()); 
    156166 
    157167    gchar *documentError = IDocument::getErrorMessage(DocumentErrorEncrypted); 
     
    159169            "Failed to load document '%s'.\n%s\n", testFile, documentError); 
    160170    g_free(documentError); 
     171    error = m_Observer->getLoadError (); 
    161172    DocumentError errorCode = (DocumentError)error->code; 
    162173    CPPUNIT_ASSERT_EQUAL (DocumentErrorEncrypted, errorCode); 
     
    164175                                                 error->message)); 
    165176    g_free (errorMessage); 
    166     g_error_free (error); 
    167177     
    168178    // Now try with an invalid password... 
    169179    error = NULL; 
    170     CPPUNIT_ASSERT (!m_Document->loadFile (testFile, "invalidpasswd", &error)); 
     180    CPPUNIT_ASSERT (m_Document->loadFile (testFile, "invalidpasswd", &error)); 
     181    while ( !m_Observer->loadFinished () ) { } 
    171182    CPPUNIT_ASSERT (!m_Document->isLoaded ()); 
     183    CPPUNIT_ASSERT (m_Observer->notifiedPassword ()); 
    172184 
    173185    documentError = IDocument::getErrorMessage(DocumentErrorEncrypted); 
     
    175187            "Failed to load document '%s'.\n%s\n", testFile, documentError); 
    176188    g_free(documentError); 
     189    error = m_Observer->getLoadError (); 
    177190    errorCode = (DocumentError)error->code; 
    178191    CPPUNIT_ASSERT_EQUAL (DocumentErrorEncrypted, errorCode); 
     
    180193                                                 error->message)); 
    181194    g_free (errorMessage); 
    182     g_error_free (error); 
    183195 
    184196    // And now, just to test that it can load the pdf using the  
     
    186198    error = NULL; 
    187199    CPPUNIT_ASSERT (m_Document->loadFile (testFile, "testpasswd", &error)); 
    188     CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    189     CPPUNIT_ASSERT (NULL == error); 
     200    while ( !m_Observer->loadFinished () ) { } 
     201    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
     202    CPPUNIT_ASSERT (m_Observer->notifiedLoaded ()); 
    190203    CPPUNIT_ASSERT_EQUAL (0, 
    191204            g_ascii_strcasecmp (testFile, m_Document->getFileName ())); 
     
    208221    gchar *testFile = getTestFile ("test2.pdf"); 
    209222    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, NULL)); 
     223    while ( !m_Observer->loadFinished () ) { } 
     224    CPPUNIT_ASSERT (m_Observer->notifiedLoaded ()); 
    210225    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    211226    CPPUNIT_ASSERT_EQUAL (0,  
     
    246261    testFile = getTestFile ("test1.pdf"); 
    247262    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, NULL)); 
     263    while ( !m_Observer->loadFinished () ) { } 
     264    CPPUNIT_ASSERT (m_Observer->notifiedLoaded ()); 
    248265    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    249266    CPPUNIT_ASSERT_EQUAL (0,  
     
    287304{ 
    288305    CPPUNIT_ASSERT (m_Document->loadFile (TEST_DIR "test1.pdf", NULL, NULL)); 
     306    while ( !m_Observer->loadFinished () ) { } 
     307    CPPUNIT_ASSERT (m_Observer->notifiedLoaded ()); 
    289308    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    290309    CPPUNIT_ASSERT_EQUAL (0, 
     
    307326    gchar *testFile = getTestFile ("test2.pdf"); 
    308327    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, NULL)); 
     328    while ( !m_Observer->loadFinished () ) { } 
     329    CPPUNIT_ASSERT (m_Observer->notifiedLoaded ()); 
    309330    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    310331    CPPUNIT_ASSERT_EQUAL (2, m_Document->getNumPages ()); 
    311332    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     333    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    312334    m_Document->goToNextPage (); 
    313335    CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     336    CPPUNIT_ASSERT_EQUAL (2, m_Observer->getCurrentPage ()); 
    314337    // Don't let the page go after the last page. 
    315338    m_Document->goToNextPage (); 
    316339    CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     340    CPPUNIT_ASSERT_EQUAL (2, m_Observer->getCurrentPage ()); 
    317341    // Now go backwards. 
    318342    m_Document->goToPreviousPage (); 
    319343    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     344    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    320345    m_Document->goToPreviousPage (); 
    321346    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     347    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    322348    // First and last pages. 
    323349    m_Document->goToLastPage (); 
    324350    CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     351    CPPUNIT_ASSERT_EQUAL (2, m_Observer->getCurrentPage ()); 
    325352    m_Document->goToFirstPage (); 
    326353    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     354    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    327355    // Now, let's go to an specific page. If the page is beyond the 
    328     // last page, then the current page will be the last. On the other 
    329     // hand, if the page is less than the first (< 1) then the current 
    330     // page will be the first. 
     356    // last page or before the first page then the current page 
     357    // doesn't change. 
    331358    m_Document->goToPage (2); 
    332359    CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     360    CPPUNIT_ASSERT_EQUAL (2, m_Observer->getCurrentPage ()); 
    333361    m_Document->goToPage (1); 
    334362    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     363    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    335364    m_Document->goToPage (13); 
    336     CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     365    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     366    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    337367    m_Document->goToPage (0); 
    338368    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     369    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    339370 
    340371    // Let's try with a 5 page document. 
     
    342373    testFile = getTestFile ("test1.pdf"); 
    343374    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, NULL)); 
     375    while ( !m_Observer->loadFinished () ) { } 
     376    CPPUNIT_ASSERT (m_Observer->notifiedLoaded ()); 
    344377    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    345378    CPPUNIT_ASSERT_EQUAL (5, m_Document->getNumPages ()); 
    346379    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     380    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    347381    m_Document->goToNextPage (); 
    348382    CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     383    CPPUNIT_ASSERT_EQUAL (2, m_Observer->getCurrentPage ()); 
    349384    m_Document->goToNextPage (); 
    350385    CPPUNIT_ASSERT_EQUAL (3, m_Document->getCurrentPageNum ()); 
     386    CPPUNIT_ASSERT_EQUAL (3, m_Observer->getCurrentPage ()); 
    351387    m_Document->goToPage (5); 
    352388    CPPUNIT_ASSERT_EQUAL (5, m_Document->getCurrentPageNum ()); 
     389    CPPUNIT_ASSERT_EQUAL (5, m_Observer->getCurrentPage ()); 
    353390    // Don't let the page go after the last page. 
    354391    m_Document->goToNextPage (); 
    355392    CPPUNIT_ASSERT_EQUAL (5, m_Document->getCurrentPageNum ()); 
     393    CPPUNIT_ASSERT_EQUAL (5, m_Observer->getCurrentPage ()); 
    356394    // Now go backwards. 
    357395    m_Document->goToPreviousPage (); 
    358396    CPPUNIT_ASSERT_EQUAL (4, m_Document->getCurrentPageNum ()); 
     397    CPPUNIT_ASSERT_EQUAL (4, m_Observer->getCurrentPage ()); 
    359398    m_Document->goToPreviousPage (); 
    360399    CPPUNIT_ASSERT_EQUAL (3, m_Document->getCurrentPageNum ()); 
     400    CPPUNIT_ASSERT_EQUAL (3, m_Observer->getCurrentPage ()); 
    361401    m_Document->goToPage (1); 
    362402    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     403    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    363404    m_Document->goToPreviousPage (); 
    364405    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     406    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    365407    // First and last pages. 
    366408    m_Document->goToLastPage (); 
    367409    CPPUNIT_ASSERT_EQUAL (5, m_Document->getCurrentPageNum ()); 
     410    CPPUNIT_ASSERT_EQUAL (5, m_Observer->getCurrentPage ()); 
    368411    m_Document->goToFirstPage (); 
    369412    CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     413    CPPUNIT_ASSERT_EQUAL (1, m_Observer->getCurrentPage ()); 
    370414    // Now, let's go to an specific page. If the page is beyond the 
    371415    // last page, then the current page will be the last. On the other 
     
    374418    m_Document->goToPage (3); 
    375419    CPPUNIT_ASSERT_EQUAL (3, m_Document->getCurrentPageNum ()); 
     420    CPPUNIT_ASSERT_EQUAL (3, m_Observer->getCurrentPage ()); 
    376421    m_Document->goToPage (2); 
    377422    CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     423    CPPUNIT_ASSERT_EQUAL (2, m_Observer->getCurrentPage ()); 
    378424    m_Document->goToPage (13); 
    379     CPPUNIT_ASSERT_EQUAL (5, m_Document->getCurrentPageNum ()); 
     425    CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     426    CPPUNIT_ASSERT_EQUAL (2, m_Observer->getCurrentPage ()); 
    380427    m_Document->goToPage (0); 
    381     CPPUNIT_ASSERT_EQUAL (1, m_Document->getCurrentPageNum ()); 
     428    CPPUNIT_ASSERT_EQUAL (2, m_Document->getCurrentPageNum ()); 
     429    CPPUNIT_ASSERT_EQUAL (2, m_Observer->getCurrentPage ()); 
    382430 
    383431    g_free (testFile); 
     
    395443    gchar *testFile = getTestFile ("test2.pdf"); 
    396444    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, NULL)); 
     445    while ( !m_Observer->loadFinished () ) { } 
    397446    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    398447    CPPUNIT_ASSERT_EQUAL (0, m_Document->getRotation ()); 
    399448    m_Document->rotateRight (); 
    400449    CPPUNIT_ASSERT_EQUAL (90, m_Document->getRotation ()); 
     450    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
    401451    m_Document->rotateLeft (); 
    402452    CPPUNIT_ASSERT_EQUAL (0, m_Document->getRotation ()); 
    403     m_Document->rotateRight (); 
     453    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
     454    m_Document->rotateRight (); 
     455    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
    404456    m_Document->rotateRight (); 
    405457    CPPUNIT_ASSERT_EQUAL (180, m_Document->getRotation ()); 
    406     m_Document->rotateRight (); 
     458    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
     459    m_Document->rotateRight (); 
     460    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
    407461    m_Document->rotateRight (); 
    408462    CPPUNIT_ASSERT_EQUAL (0, m_Document->getRotation ()); 
     463    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
    409464    m_Document->rotateLeft (); 
    410465    CPPUNIT_ASSERT_EQUAL (270, m_Document->getRotation ()); 
     466    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
    411467     
    412468    g_free (testFile); 
    413469    testFile = getTestFile ("test1.pdf"); 
     470    while ( !m_Observer->loadFinished () ) { } 
    414471    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, NULL)); 
    415472    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    416473    CPPUNIT_ASSERT_EQUAL (0, m_Document->getRotation ()); 
    417474    m_Document->rotateRight (); 
    418     m_Document->rotateRight (); 
     475    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
     476    m_Document->rotateRight (); 
     477    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
    419478    m_Document->rotateLeft (); 
    420479    CPPUNIT_ASSERT_EQUAL (90, m_Document->getRotation ()); 
     480    CPPUNIT_ASSERT (m_Observer->notifiedRotation ()); 
    421481     
    422482    g_free (testFile); 
     
    438498    gchar *testFile = getTestFile ("test2.pdf"); 
    439499    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, NULL)); 
     500    while ( !m_Observer->loadFinished () ) { } 
    440501    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    441502    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.0f, m_Document->getZoom (), DELTA); 
    442503    m_Document->zoomIn (); 
    443504    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.2f, m_Document->getZoom (), DELTA); 
     505    CPPUNIT_ASSERT (m_Observer->notifiedZoom ()); 
     506    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.2f, m_Observer->getZoom (), DELTA); 
    444507    m_Document->zoomIn (); 
    445508    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.44f, m_Document->getZoom (), DELTA); 
     509    CPPUNIT_ASSERT (m_Observer->notifiedZoom ()); 
     510    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.44f, m_Observer->getZoom (), DELTA); 
    446511    m_Document->zoomOut (); 
    447512    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.2f, m_Document->getZoom (), DELTA); 
     513    CPPUNIT_ASSERT (m_Observer->notifiedZoom ()); 
     514    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.2f, m_Observer->getZoom (), DELTA); 
    448515    m_Document->zoomIn (); 
    449516    m_Document->zoomIn (); 
    450517    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.728f, m_Document->getZoom (), DELTA); 
     518    CPPUNIT_ASSERT (m_Observer->notifiedZoom ()); 
     519    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.728f, m_Observer->getZoom (), DELTA); 
    451520 
    452521    // On this document we'll use the zoom to fit and zoom to width. 
     
    455524    testFile = getTestFile ("test1.pdf"); 
    456525    CPPUNIT_ASSERT (m_Document->loadFile (testFile, NULL, NULL)); 
     526    while ( !m_Observer->loadFinished () ) { } 
    457527    CPPUNIT_ASSERT (m_Document->isLoaded ()); 
    458528    CPPUNIT_ASSERT_DOUBLES_EQUAL (1.0f, m_Document->getZoom (), DELTA); 
    459529    m_Document->zoomToWidth (200);     
    460530    CPPUNIT_ASSERT_DOUBLES_EQUAL (0.3361f, m_Document->getZoom (), DELTA); 
     531    CPPUNIT_ASSERT (m_Observer->notifiedZoom ()); 
     532    CPPUNIT_ASSERT_DOUBLES_EQUAL (0.3361f, m_Observer->getZoom (), DELTA); 
    461533    m_Document->zoomToFit (100, 50);     
    462534    CPPUNIT_ASSERT_DOUBLES_EQUAL (0.0593f, m_Document->getZoom (), DELTA); 
     535    CPPUNIT_ASSERT (m_Observer->notifiedZoom ()); 
     536    CPPUNIT_ASSERT_DOUBLES_EQUAL (0.0593f, m_Observer->getZoom (), DELTA); 
    463537    m_Document->zoomToFit (50, 100);     
    464538    C