root/trunk/src/JobPrint.cxx

Revision 262, 12.3 kB (checked in by jordi, 2 years ago)

Added some g_free calls.

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 <stdlib.h>
20 #include <cups/cups.h>
21 #include "epdfview.h"
22
23 using namespace ePDFView;
24
25 // Forward declaration.
26 static gboolean job_print_end (gpointer data);
27
28 ///
29 /// @brief Constructs a new JobPrint object.
30 ///
31 JobPrint::JobPrint ():
32     IJob ()
33 {
34     m_Collate = FALSE;
35     m_ColorModel = NULL;
36     m_CurrentPage = 1;
37     m_Document = NULL;
38     m_DocumentCopy = NULL;
39     m_NumberOfCopies = 1;
40     m_PageHeight = 0.1624f;
41     m_PageLayout = PRINT_PAGE_LAYOUT_PLAIN;
42     m_PageOrientation = PRINT_PAGE_ORIENTATION_PORTRAIT;
43     m_PageRange = NULL;
44     m_PageRangeString = NULL;
45     m_PageSet = PRINT_ALL_PAGE_SET;
46     m_PageWidth = 0.1147f;
47     m_PrinterName = NULL;
48     m_Resolution = NULL;
49     m_TempFileName = NULL;
50 }
51
52 ///
53 /// @brief Deletes all dynamically allocated memory by JobPrint.
54 ///
55 JobPrint::~JobPrint ()
56 {
57     delete m_DocumentCopy;
58     delete[] m_PageRange;
59     g_free (m_ColorModel);
60     g_free (m_PageRangeString);
61     g_free (m_PrinterName);
62     g_free (m_Resolution);
63     g_free (m_TempFileName);
64 }
65
66 gboolean
67 JobPrint::getCollate ()
68 {
69     return m_Collate;
70 }
71
72 const gchar *
73 JobPrint::getColorModel ()
74 {
75     return m_ColorModel;
76 }
77
78 guint
79 JobPrint::getCurrentPage ()
80 {
81     return m_CurrentPage;
82 }
83
84 guint
85 JobPrint::getNumberOfCopies ()
86 {
87     return m_NumberOfCopies;
88 }
89
90 IDocument &
91 JobPrint::getDocument ()
92 {
93     g_assert ( NULL != m_DocumentCopy && "The copy of the document is NULL.");
94
95     return *m_DocumentCopy;
96 }
97
98 gfloat
99 JobPrint::getPageHeight ()
100 {
101     return m_PageHeight;
102 }
103
104 PrintPageLayout
105 JobPrint::getPageLayout ()
106 {
107     return m_PageLayout;
108 }
109
110 PrintPageOrientation
111 JobPrint::getPageOrientation ()
112 {
113     return m_PageOrientation;
114 }
115
116 const gchar *
117 JobPrint::getPageRangeString ()
118 {
119     return m_PageRangeString;
120 }
121
122 PrintPageSet
123 JobPrint::getPageSet ()
124 {
125     return m_PageSet;
126 }
127
128 gfloat
129 JobPrint::getPageWidth ()
130 {
131     return m_PageWidth;
132 }
133
134 const gchar *
135 JobPrint::getPrinterName ()
136 {
137     return m_PrinterName;
138 }
139
140 const gchar *
141 JobPrint::getResolution ()
142 {
143     return m_Resolution;
144 }
145
146 const gchar *
147 JobPrint::getTempFileName ()
148 {
149     return m_TempFileName;
150 }
151
152 ///
153 /// @brief Renders a single page into a PostScript document.
154 ///
155 gboolean
156 JobPrint::run ()
157 {
158     // This only will only be executed the first time.
159     setUpPrint ();
160
161     guint currentPage = getCurrentPage ();
162     getDocument ().outputPostscriptPage (currentPage);
163
164     guint numPages = getDocument ().getNumPages ();
165     for (guint pageNum = currentPage ; pageNum < numPages ; ++pageNum )
166     {
167         if (m_PageRange[pageNum])
168         {
169             setCurrentPage (pageNum + 1);
170             break;
171         }
172     }
173
174     if ( getCurrentPage () == currentPage )
175     {
176         JOB_NOTIFIER (job_print_end, this);
177     }
178     else
179     {
180         IJob::enqueue (this);
181     }
182
183     return JOB_DELETE;
184 }
185
186 void
187 JobPrint::setCollate (gboolean collate)
188 {
189     m_Collate = collate;
190 }
191
192 void
193 JobPrint::setColorModel (const gchar *colorModel)
194 {
195     g_free (m_ColorModel);
196     m_ColorModel = g_strdup (colorModel);
197 }
198
199 void
200 JobPrint::setCurrentPage (guint pageNumber)
201 {
202     m_CurrentPage = pageNumber;
203 }
204
205 void
206 JobPrint::setDocument (IDocument *document)
207 {
208     m_Document = document;
209 }
210
211 void
212 JobPrint::setNumberOfCopies (guint copies)
213 {
214     m_NumberOfCopies = copies;
215 }
216
217 void
218 JobPrint::setPrinterName (const gchar *name)
219 {
220     g_free (m_PrinterName);
221     m_PrinterName = g_strdup (name);
222 }
223
224 void
225 JobPrint::setPageLayout (PrintPageLayout layout)
226 {
227     m_PageLayout = layout;
228 }
229
230 void
231 JobPrint::setPageOrientation (PrintPageOrientation orientation)
232 {
233     m_PageOrientation = orientation;
234 }
235
236 void
237 JobPrint::setPageRange (const gchar *range)
238 {
239     g_free (m_PageRangeString);
240     m_PageRangeString = g_strdup (range);
241 }
242
243 void
244 JobPrint::setPageSet (PrintPageSet set)
245 {
246     m_PageSet = set;
247 }
248
249 void
250 JobPrint::setPageSize (float pageWidth, float pageHeight)
251 {
252     m_PageWidth = pageWidth;
253     m_PageHeight = pageHeight;
254 }
255
256 void
257 JobPrint::setResolution (const gchar *resolution)
258 {
259     g_free (m_Resolution);
260     m_Resolution = g_strdup (resolution);
261 }
262
263 guint
264 JobPrint::setUpPageRange ()
265 {
266     // The pages range are in the format:
267     //  "a-b,c,d-e,f,g,h,i-j"
268     //
269     // What I will do here is traversing the string and looking for the
270     // following characters:
271     //      '-'             -   Tells a range of pages.
272     //      ','             -   Tells a single page.
273     //      Digit           -   Just accumule them.
274     //      Any non-digit   -   The number has finished.
275     //
276     // We assume the following:
277     //      1) There's at least one character string.
278     //      2) The string ends with the \0 character.
279
280     enum
281     {
282         COPY_SINGLE,
283         COPY_RANGE
284     } currentOperation = COPY_SINGLE;
285
286     const gint numPages = getDocument().getNumPages () - 1;
287     const gchar *stringStart = getPageRangeString ();
288     const gchar *stringEnd = stringStart;
289     guint pages[2] = {0, 0};
290     guint currentPageNum = 0;
291
292     do
293     {
294         if ( !g_ascii_isdigit (*stringEnd) )
295         {
296             // No more digits, get the number we have.
297             gchar *number = g_strndup (stringStart, stringEnd - stringStart);
298             if ( NULL != number )
299             {
300                 pages[currentPageNum] = CLAMP (atoi (number) - 1, 0, numPages);
301                 g_free (number);
302             }
303             else
304             {
305                 pages[currentPageNum] = 0;
306             }
307             stringStart = stringEnd;
308
309             // Now check what should we do with out digit.
310             switch (*stringEnd)
311             {
312                 case '-':
313                     // It's a range. Must get the second number.
314                     currentPageNum = 1;
315                     currentOperation = COPY_RANGE;
316                     stringStart++;
317                     break;
318
319                 case ',':
320                 default:
321                     // In any other case, just copy the single number of the
322                     // range and start again.
323                     if ( COPY_RANGE == currentOperation )
324                     {
325                         const int lastPage = MAX (pages[0], pages[1]);
326                         const int firstPage = MIN (pages[0], pages[1]);
327                         for (int pageNum = firstPage ; pageNum <= lastPage ;
328                              ++pageNum )
329                         {
330                             m_PageRange[pageNum] = TRUE;
331                         }
332                     }
333                     else
334                     {
335                         m_PageRange[pages[0]] = TRUE;
336                     }
337                     currentPageNum = 0;
338                     currentOperation = COPY_SINGLE;
339                     stringStart++;
340             }
341         }
342         ++stringEnd;
343     }
344     while ( '\0' != *stringEnd );
345
346     gchar *lastDigit = g_strndup (stringStart, stringEnd - stringStart);
347     if ( NULL != lastDigit )
348     {
349         pages[currentPageNum] = CLAMP (atoi (lastDigit) - 1, 0, numPages);
350         g_free (lastDigit);
351     }
352     else
353     {
354         pages[currentPageNum] = 0;
355     }
356
357     if ( COPY_RANGE == currentOperation )
358     {
359         const int lastPage = MAX (pages[0], pages[1]);
360         const int firstPage = MIN (pages[0], pages[1]);
361         for (int pageNum = firstPage ; pageNum <= lastPage ; ++pageNum )
362         {
363             m_PageRange[pageNum] = TRUE;
364         }
365     }
366     else
367     {
368         m_PageRange[pages[0]] = TRUE;
369     }
370
371     // Now check the page range set.
372     PrintPageSet pageSet = getPageSet ();
373     gint totalNumberOfPages = 0;
374     for ( gint pageNum = 0; pageNum <= numPages ; ++pageNum )
375     {
376         // Since the range is from 0 to numPages - 1, the checks for
377         // even or odd are reversed.
378         if ( pageNum % 2 == 0 && PRINT_EVEN_PAGE_SET == pageSet ||
379              pageNum % 2 != 0 && PRINT_ODD_PAGE_SET == pageSet )
380         {
381             m_PageRange[pageNum] = FALSE;
382         }
383
384         if ( m_PageRange[pageNum] )
385         {
386             totalNumberOfPages++;
387         }
388     }
389
390     return totalNumberOfPages;
391 }
392
393 void
394 JobPrint::setTempFileName (const gchar *fileName)
395 {
396     g_free (m_TempFileName);
397     m_TempFileName = g_strdup (fileName);
398 }
399
400 void
401 JobPrint::setUpPrint ()
402 {
403     if ( NULL != m_Document )
404     {
405         // Get a *copy* of the document. We don't want to open
406         // a new document while printing, do we?
407         m_DocumentCopy = m_Document->copy ();
408         m_Document = NULL;
409
410         // This array tells us which pages to export to postscript.
411         int numPages = getDocument ().getNumPages ();
412         m_PageRange = new gboolean[numPages];
413         for ( int currentPage = 0 ; currentPage < numPages ; ++currentPage )
414         {
415             m_PageRange[currentPage] = FALSE;
416         }
417         if ( NULL == getPageRangeString () )
418         {
419             gchar *pageRange = g_strdup_printf ("1-%d", numPages);
420             setPageRange (pageRange);
421             g_free (pageRange);
422         }
423         // Now get the real range to print.
424         gint numPagesToPrint = setUpPageRange ();
425
426         // Set the current page to the first page that must be rendered.
427         for (int currentPage = 0 ; currentPage < numPages ; ++currentPage )
428         {
429             if ( m_PageRange[currentPage] )
430             {
431                 setCurrentPage (currentPage + 1);
432                 break;
433             }
434         }
435
436         // Create a temporary file to store the postscript
437         gchar tempFileName[1024];
438         int cupsFile = cupsTempFd (tempFileName, 1024);
439         setTempFileName (tempFileName);
440         getDocument ().outputPostscriptBegin (tempFileName, numPagesToPrint,
441                                               getPageWidth (),
442                                               getPageHeight ());
443         close (cupsFile);
444     }
445 }
446
447 ////////////////////////////////////////////////////////////////
448 // Static threaded functions.
449 ////////////////////////////////////////////////////////////////
450
451 gboolean
452 job_print_end (gpointer data)
453 {
454     g_assert (NULL != data && "The data parameter is NULL.");
455
456     JobPrint *job = (JobPrint *)data;
457     job->getDocument().outputPostscriptEnd ();
458
459     // Add Cups options.
460     cups_option_t *options;
461     gint numOptions = 0;
462
463     gchar *numCopies = g_strdup_printf ("%d", job->getNumberOfCopies ());
464     numOptions = cupsAddOption ("copies", numCopies, numOptions, &options);
465     g_free (numCopies);
466
467     gchar *collate = g_strdup (job->getCollate() ? "True" : "False");
468     numOptions = cupsAddOption ("Collate", collate, numOptions, &options);
469     g_free (collate);
470
471     gchar *orientation = NULL;
472     if ( PRINT_PAGE_ORIENTATION_LANDSCAPE == job->getPageOrientation () )
473     {
474         orientation = g_strdup_printf ("4");
475     }
476     else
477     {
478         orientation = g_strdup_printf ("3");
479     }
480     numOptions = cupsAddOption ("orientation-requested", orientation,
481                                  numOptions, &options);
482     g_free (orientation);
483
484     gchar *layout = NULL;
485     switch (job->getPageLayout ())
486     {
487         case PRINT_PAGE_LAYOUT_2IN1:
488             layout = g_strdup_printf ("%d", 2);
489             break;
490
491         case PRINT_PAGE_LAYOUT_4IN1:
492             layout = g_strdup_printf ("%d", 4);
493             break;
494
495         default:
496             layout = g_strdup_printf ("%d", 1);
497     }
498     numOptions = cupsAddOption ("number-up", layout, numOptions, &options);
499     g_free (layout);
500     numOptions = cupsAddOption ("ColorModel", job->getColorModel (),
501                                 numOptions, &options);
502     numOptions = cupsAddOption ("resolution", job->getResolution (),
503                                 numOptions, &options);
504
505     cupsPrintFile (job->getPrinterName (), job->getTempFileName (),
506                    job->getDocument ().getFileName (), numOptions, options);
507
508     cupsFreeOptions (numOptions, options);
509
510     JOB_NOTIFIER_END ();
511
512     return FALSE;
513 }
Note: See TracBrowser for help on using the browser.