1 // ePDFView - A lightweight PDF Viewer.
2 // Copyright (C) 2006, 2007, 2009 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 "epdfview.h"
19
20 using namespace ePDFView;
21
22 G_LOCK_DEFINE_STATIC (cancelJob);
23 G_LOCK_DEFINE_STATIC (freeResults);
24
25 ///
26 /// @brief Constructs a new FindPter object.
27 ///
28 /// @param document The document to find text from.
29 ///
FindPter(IDocument * document)30 FindPter::FindPter (IDocument *document)
31 {
32 g_assert (NULL != document && "Tried to set a NULL document.");
33
34 m_CurrentMatch = NULL;
35 m_Document = document;
36 m_FindPage = 0;
37 m_FindResults = NULL;
38 m_Job = NULL;
39 m_View = NULL;
40 }
41
42 ///
43 /// @brief Destroys all dynamically allocated memory for FindPter.
44 ///
~FindPter()45 FindPter::~FindPter ()
46 {
47 m_Document = NULL;
48 // This also deletes the find results.
49 cancelJob ();
50 }
51
52 ///
53 /// @brief Cancels the find job.
54 ///
55 void
cancelJob()56 FindPter::cancelJob ()
57 {
58 G_LOCK (cancelJob);
59 if ( NULL != m_Job )
60 {
61 m_Job->cancel ();
62 m_Job->enqueue ();
63 // When the job is cancelled, it will just delete itself.
64 m_Job = NULL;
65 }
66 freeFindResults ();
67 G_UNLOCK (cancelJob);
68 }
69
70 ///
71 /// @brief The Close button has been clicked.
72 ///
73 void
closeActivated()74 FindPter::closeActivated ()
75 {
76 getView ().hide ();
77 cancelJob ();
78 m_Document->notifyFindChanged (m_FindPage, NULL);
79 }
80
81 ///
82 /// @brief The Find Next button has been clicked.
83 ///
84 void
findNextActivated()85 FindPter::findNextActivated ()
86 {
87 m_CurrentMatch = g_list_next (m_CurrentMatch);
88 if ( NULL != m_CurrentMatch )
89 {
90 DocumentRectangle *rect = ((DocumentRectangle *)m_CurrentMatch->data);
91 m_Document->notifyFindChanged (m_FindPage, rect);
92 m_Document->goToPage (m_FindPage);
93 }
94 else
95 {
96 G_LOCK (cancelJob);
97 if ( NULL != m_Job )
98 {
99 if ( FIND_DIRECTION_BACKWARDS == m_Job->getDirection () )
100 {
101 m_Job->setCurrentPage (m_Job->getCurrentPage () + 2);
102 }
103 m_Job->setDirection (FIND_DIRECTION_FORWARDS);
104 m_Job->enqueue ();
105 }
106 G_UNLOCK (cancelJob);
107 }
108 }
109
110 ///
111 /// @brief The Find Previous button has been clicked.
112 ///
113 void
findPreviousActivated()114 FindPter::findPreviousActivated ()
115 {
116 m_CurrentMatch = g_list_previous (m_CurrentMatch);
117 if ( NULL != m_CurrentMatch )
118 {
119 DocumentRectangle *rect = ((DocumentRectangle *)m_CurrentMatch->data);
120 m_Document->notifyFindChanged (m_FindPage, rect);
121 m_Document->goToPage (m_FindPage);
122 }
123 else
124 {
125 G_LOCK (cancelJob);
126 if ( NULL != m_Job )
127 {
128 if ( FIND_DIRECTION_FORWARDS == m_Job->getDirection () )
129 {
130 m_Job->setCurrentPage (m_Job->getCurrentPage () - 2);
131 }
132 m_Job->setDirection (FIND_DIRECTION_BACKWARDS);
133 m_Job->enqueue ();
134 }
135 G_UNLOCK (cancelJob);
136 }
137 }
138
139 ///
140 /// @brief Deletes all saved results.
141 ///
142 void
freeFindResults()143 FindPter::freeFindResults ()
144 {
145 G_LOCK (freeResults);
146 for ( GList *item = g_list_first (m_FindResults) ; NULL != item ;
147 item = g_list_next (item) )
148 {
149 DocumentRectangle *rect = (DocumentRectangle *)item->data;
150 delete rect;
151 }
152 g_list_free (m_FindResults);
153 m_FindResults = NULL;
154 G_UNLOCK (freeResults);
155 }
156
157 ///
158 /// @brief Gets the view that the presenter is controlling.
159 ///
160 /// @return The view that the presenter is controlling.
161 ///
162 IFindView &
getView()163 FindPter::getView ()
164 {
165 g_assert (NULL != m_View && "Tried to get a NULL view.");
166
167 return *m_View;
168 }
169
170 ///
171 /// @brief The find has searched on all pages.
172 ///
173 void
notifyFindFinished(gboolean endOfSearch)174 FindPter::notifyFindFinished (gboolean endOfSearch )
175 {
176 G_LOCK (cancelJob);
177 if ( NULL != m_Job )
178 {
179 IFindView &view = getView ();
180 if ( endOfSearch && NULL == m_FindResults )
181 {
182 view.sensitiveFindNext (FALSE);
183 view.sensitiveFindPrevious (FALSE);
184 G_UNLOCK (cancelJob);
185 cancelJob ();
186 G_LOCK (cancelJob);
187 view.setInformationText (_("No Results Found!"));
188 m_Document->notifyFindFinished ();
189 // Clear any previously set rectangle.
190 m_Document->notifyFindChanged (m_FindPage, NULL);
191 }
192 else
193 {
194 gchar *infoText =
195 g_strdup_printf (_("Searching in page %d of %d..."),
196 m_Job->getCurrentPage (),
197 m_Document->getNumPages ());
198 view.setInformationText (infoText);
199 g_free (infoText);
200 m_Job->enqueue ();
201 }
202 }
203 G_UNLOCK (cancelJob);
204 }
205
206 ///
207 /// @brief The find found results.
208 ///
209 /// @param pageNum The number of the page that found results.
210 /// @param results The results that found.
211 /// @param direction The direction it was searching pages when found results.
212 ///
213 void
notifyFindResults(gint pageNum,GList * results,FindDirection direction)214 FindPter::notifyFindResults (gint pageNum, GList *results,
215 FindDirection direction)
216 {
217 m_FindPage = pageNum;
218 freeFindResults ();
219 G_LOCK (freeResults);
220 m_FindResults = results;
221 G_UNLOCK (freeResults);
222 if ( FIND_DIRECTION_FORWARDS == direction )
223 {
224 m_CurrentMatch = g_list_first (m_FindResults);
225 }
226 else
227 {
228 m_CurrentMatch = g_list_last (m_FindResults);
229 }
230 DocumentRectangle *rect = (DocumentRectangle *)m_CurrentMatch->data;
231 m_Document->notifyFindChanged (m_FindPage, rect);
232 m_Document->goToPage (m_FindPage);
233
234 IFindView &view = getView ();
235 view.setInformationText ("");
236 view.sensitiveFindNext (TRUE);
237 view.sensitiveFindPrevious (TRUE);
238 }
239
240 ///
241 /// @brief Sets the view that the presenter will control.
242 ///
243 /// @param view The view that the presenter will control.
244 ///
245 void
setView(IFindView * view)246 FindPter::setView (IFindView *view)
247 {
248 g_assert ( NULL != view && "Tried to set a NULL view.");
249
250 m_View = view;
251 m_View->setPresenter (this);
252 m_View->sensitiveFindNext (FALSE);
253 m_View->sensitiveFindPrevious (FALSE);
254 m_View->setInformationText ("");
255 }
256
257 ///
258 /// @brief The text to find has been changed.
259 ///
260 /// This is called by the view when the text to find has been modified. This
261 /// function checks if the text is empty and sets the sensitivity of Find Next
262 /// and Find Previous button according.
263 ///
264 void
textToFindChanged()265 FindPter::textToFindChanged ()
266 {
267 cancelJob ();
268
269 const gchar *textToFind = getView ().getTextToFind ();
270 if ( 0 != g_ascii_strcasecmp ("", textToFind ) )
271 {
272 // Inform all observers.
273 m_Document->notifyFindStarted ();
274
275 // Queue a find job.
276 m_Job = new JobFind ();
277 m_Job->setDocument (m_Document);
278 m_Job->setStartingPage (m_Document->getCurrentPageNum ());
279 m_Job->setTextToFind (textToFind);
280 m_Job->setFindPter (this);
281 m_Job->enqueue ();
282 }
283 else
284 {
285 IFindView &view = getView ();
286 view.sensitiveFindNext (FALSE);
287 view.sensitiveFindPrevious (FALSE);
288 // Clear any previously set rectangle.
289 m_Document->notifyFindChanged (m_FindPage, NULL);
290 }
291 }
292