c++-gtk-utils
text_print_manager.h
Go to the documentation of this file.
1 /* Copyright (C) 2007 to 2011 Chris Vine
2 
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public License
9  as published by the Free Software Foundation; either version 2.1 of
10  the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License, version 2.1, for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License, version 2.1, along with this library (see the file LGPL.TXT
19  which came with this source code package in the c++-gtk-utils
20  sub-directory); if not, write to the Free Software Foundation, Inc.,
21  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23 */
24 
25 #ifndef CGU_TEXT_PRINTMANAGER_H
26 #define CGU_TEXT_PRINTMANAGER_H
27 
28 #include <vector>
29 #include <string>
30 #include <memory>
31 
32 #include <gtk/gtk.h>
33 #include <pango/pango-layout.h>
34 #include <glib-object.h>
35 
36 
40 #include <c++-gtk-utils/notifier.h>
41 #include <c++-gtk-utils/mutex.h>
43 
44 
45 namespace Cgu {
46 
47 #ifndef DOXYGEN_PARSING
48 
49 // deleter functor for SharedHandle
50 class TPMPangoLayoutIterFree {
51 public:
52  void operator()(PangoLayoutIter* obj_p) {
53  if (obj_p) {
54  pango_layout_iter_free(obj_p);
55  }
56  }
57 };
58 
59 typedef SharedHandle<PangoLayoutIter*, TPMPangoLayoutIterFree> TPMPangoLayoutIterSharedHandle;
60 
61 #endif // DOXYGEN_PARSING
62 
63 /**
64  * @class TextPrintManager text_print_manager.h c++-gtk-utils/text_print_manager.h
65  * @brief A class to print plain text using the GTK+ print system.
66  *
67  * The TextPrintManager class prints text (say, from a GtkTextBuffer
68  * object or from a plain text file) using the GTK+ printer interface.
69  * To obtain a TextPrintManager object, call
70  * TextPrintManager::create_manager(). TextPrintManager::set_text()
71  * passes the text to be printed. The text passed with
72  * TextPrintManager::set_text() must form valid UTF-8 (all ASCII
73  * characters form valid UTF-8). To print the text entered, call
74  * TextPrintManager::print(). The TextPrintManager::view() and
75  * TextPrintManager::print_to_file() methods are also available.
76  *
77  * The TextPrintManager::page_setup() method can be used as a callback
78  * to display a document page setup dialog prior to printing, and this
79  * method should only be called in the thread in which the main GTK+
80  * event loop runs. It is a static method (a TextPrintManager object
81  * does not need to have been created before it is called).
82  *
83  * Once TextPrintManager::print(), TextPrintManager::view() or
84  * TextPrintManager::print_to_file() has been called, the
85  * TextPrintManager class owns a reference to itself and so manages
86  * its own lifetime - so once one of the methods has been called it
87  * doesn't matter if the IntrusivePtr object returned by
88  * TextPrintManager::create_manager() goes out of scope (however, once
89  * TextPrintManager::print(), TextPrintManager::view() or
90  * TextPrintManager::print_to_file() has been called, the object will
91  * not be deleted until both printing has completed or failed AND the
92  * IntrusivePtr object returned by TextPrintManager::create_manager()
93  * has gone out of scope or has been reset()).
94  *
95  * Normally, a user would probably only want to use any one
96  * TextPrintManager object to print a single print job (it has been
97  * designed with that in mind). Nevertheless, if a reference to the
98  * object is kept alive via an active IntrusivePtr object, it can be
99  * used to print more than one print job. However, if that is done it
100  * is not possible to called TextPrintManager::print()
101  * TextPrintManager::view(), TextPrintManager::print_to_file() or
102  * TextPrintManager::set_text() until the previous print job (if any)
103  * has been dispatched to the GTK+ print system (or cancelled). If
104  * the TextPrintManager object is not ready because it is in the
105  * middle of handling an earlier print job, then the call to
106  * TextPrintManager::print(), TextPrintManager::view(),
107  * TextPrintManager::print_to_file() or TextPrintManager::set_text()
108  * will return false; if however the new print job was successfully
109  * started or text successfully set, they will return true. It is not
110  * necessary to check the return value of these methods for the first
111  * print job despatched by any one TextPrintManager object.
112  *
113  * TextPrintManager::print_to_file() will also return false if no file
114  * name to which to print was specified.
115  */
116 
118  enum Mode {print_mode, view_mode, file_mode} mode;
119 
120  Thread::Mutex mutex;
121  GtkWindow* parent_p;
122  GobjHandle<PangoLayout> text_layout_h;
123  int current_line;
124  TPMPangoLayoutIterSharedHandle current_line_iter_h;
125  std::unique_ptr<std::string> text_u;
126  std::string file_name;
127  std::vector<int> pages;
128  Notifier print_notifier;
129  std::string font_family;
130  int font_size;
131  bool ready;
132  bool cancelled_when_drawing;
133 
134  GobjHandle<GtkWidget> font_entry_h;
135  GobjHandle<GtkWidget> font_size_spin_button_h;
136 
137  static GobjHandle<GtkPrintSettings> print_settings_h;
138  static GobjHandle<GtkPageSetup> page_setup_h;
139  static std::string default_font_family;
140  static int default_font_size;
141 
142  void paginate(GtkPrintContext*);
143  void print_text();
144  void begin_print_impl(GtkPrintOperation*, GtkPrintContext*);
145  void draw_page_impl(GtkPrintOperation*, GtkPrintContext*, int);
146  GObject* create_custom_widget_impl(GtkPrintOperation*);
147  static void strip(std::string&);
148 
149  // private constructor
150  TextPrintManager() {}
151 public:
152 #ifndef DOXYGEN_PARSING
153  // this helper class avoids exposing GObject callbacks with C
154  // linkage to the global namespace
155  class CB;
156  friend class CB;
157 #endif
158 /**
159  * This class cannot be copied: it is intended to be held by
160  * IntrusivePtr. The copy constructor is deleted.
161  */
162  TextPrintManager(const TextPrintManager&) = delete;
163 
164 /**
165  * This class cannot be copied: it is intended to be held by
166  * IntrusivePtr. The assignment operator is deleted.
167  */
168  TextPrintManager& operator=(const TextPrintManager&) = delete;
169 
170 /**
171  * Creates a new TextPrintManager object. No GTK+/GDK functions are
172  * called by this method, and it is thread safe provided that, if it
173  * is called in a thread other than the one in which the GTK+ event
174  * loop runs, Cgu::Notifier::init() has previously been called in the
175  * GTK+ event loop thread.
176  * @param parent The parent of the print dialog which will be created
177  * by the TextPrintManager object (optional, NULL may be passed).
178  * @param font_family If a particular font is wanted, then this can be
179  * entered as the font_family and font_size arguments to this method..
180  * If the default of an empty string for font_family is used, then
181  * printing will use the previous font family setting (if any), or if
182  * not a font of "Mono". The font passed in this method can in any
183  * event be overridden from the "Print font" page in the print dialog.
184  * @param font_size If a particular font is wanted, then this can be
185  * entered as the font_family and font_size arguments to this method..
186  * If the default of 0 for font_size is used, then printing will use
187  * the previous font size setting (if any), or if not a size of
188  * 10. The font passed in this method can in any event be overridden
189  * from the "Print font" page in the print dialog. If a font size is
190  * passed as an argument, then the value must be 0 (default) or
191  * between 8 and 24 (actual).
192  * @exception std::bad_alloc This method might throw std::bad_alloc if
193  * memory is exhausted and the system throws in that case.
194  * @exception Cgu::Thread::MutexError This method might throw
195  * Cgu::Thread::MutexError if initialisation of the contained mutex
196  * fails. (It is often not worth checking for this, as it means
197  * either memory is exhausted or pthread has run out of other
198  * resources to create new mutexes.)
199  * @exception Cgu::PipeError This method might throw Cgu::PipeError if
200  * the contained Notifier object is the first Notifier object in the
201  * program to be constructed and Cgu::Notifier::init() has not
202  * previously been called.
203  */
204  static Cgu::IntrusivePtr<Cgu::TextPrintManager> create_manager(GtkWindow* parent = 0,
205  const std::string& font_family = "",
206  int font_size = 0);
207 
208 /**
209  * Runs a page set-up dialog. (If no settings are set using this
210  * dialog, then page defaults will be used with a page margin of 15
211  * millimetres.) In a multi-threaded program, this must be called in
212  * the thread in which the main GTK+ event loop runs. If the program
213  * by which it is called calls GTK+ directly in more than one thread
214  * and thus employs gdk_threads_enter()/gdk_threads_leave() (rather
215  * than, say, Cgu::Notifier or Cgu::Callback::post()), it must also be
216  * surrounded by gdk_threads_enter()/gdk_threads_leave() if called
217  * otherwise than in a GTK+ signal handler. (The best approach
218  * however is for a program only to address GTK+/GDK in the main
219  * program thread, for which purpose this library provides various
220  * functions and classes for inter-thread communication, such as
221  * Cgu::Notifier and Cgu::Callback::post().) It will not throw.
222  * @param parent The parent of the page set-up dialog which will be
223  * created by the TextPrintManager object (optional, NULL may be
224  * passed).
225  */
226  static void page_setup(GtkWindow* parent = 0);
227 
228 /**
229  * Sets the text to be printed. This method is thread-safe and may be
230  * called in any thread. No GTK+/GDK functions are called. It will
231  * not throw.
232  * @param text The text to be printed. It must be in valid UTF-8
233  * format. Ownership is taken of the text string (a move operation is
234  * carried out) unless false is returned.
235  * @return Returns true, unless the same TextPrintManager object is
236  * being used to print more than one print job and when this method is
237  * called it is already printing another print job (in which case it
238  * returns false). If it returns false, ownership is not taken of the
239  * text string (it can be reused).
240  * @note If the library is compiled using the --with-auto-ptr
241  * configuration option, then this function's signature is bool
242  * set_text(std::auto_ptr<std::string>& text) in order to retain
243  * compatibility with the 1.2 series of the library.
244  */
245  // for efficiency reasons (the string could hold a lot of text and we do not
246  // want more copies than necessary hanging around) the text is passed by
247  // reference (by std::unique_ptr<>). We pass by std::unique_ptr so that the
248  // string cannot be modified after it has been passed to the TextPrintManager
249  // object - we take ownership of it
250 #ifdef CGU_USE_AUTO_PTR
251  bool set_text(std::auto_ptr<std::string>& text);
252 #else
253  bool set_text(std::unique_ptr<std::string>& text);
254 #endif
255 
256 /**
257  * Prints the text set with set_text(). This method is thread-safe
258  * and may be called in any thread (it hands off its work to the main
259  * program thread via a Cgu::Notifier object), unless the program by
260  * which it is called calls GTK+ directly in more than one thread and
261  * thus employs gdk_threads_enter()/gdk_threads_leave() (rather than,
262  * say, Cgu::Notifier or Cgu::Callback::post()), in which case it must
263  * be called in the main GUI thread only and surrounded by
264  * gdk_threads_enter()/gdk_threads_leave() if called otherwise than in
265  * a GTK+ signal handler. (The best approach however is for a program
266  * only to address GTK+/GDK in the main program thread, for which
267  * purpose this library provides various functions and classes for
268  * inter-thread communication, such as Cgu::Notifier and
269  * Cgu::Callback::post().)
270  * @return Returns true, unless the same TextPrintManager object is
271  * being used to print more than one print job and when this method is
272  * called it is already printing another print job (in which case it
273  * returns false).
274  * @exception std::bad_alloc This method might throw std::bad_alloc if
275  * memory is exhausted and the system throws in that case, but only if
276  * it is called in the main program thread. Otherwise it will not
277  * throw.
278  */
279  bool print();
280 
281 /**
282  * Provides a print pre-view of the text set with set_text(). This
283  * method is thread-safe and may be called in any thread (it hands off
284  * its work to the main program thread via a Cgu::Notifier object),
285  * unless the program by which it is called calls GTK+ directly in
286  * more than one thread and thus employs
287  * gdk_threads_enter()/gdk_threads_leave() (rather than, say,
288  * Cgu::Notifier or Cgu::Callback::post()), in which case it must be
289  * called in the main GUI thread only and surrounded by
290  * gdk_threads_enter()/gdk_threads_leave() if called otherwise than in
291  * a GTK+ signal handler. (The best approach however is for a program
292  * only to address GTK+/GDK in the main program thread, for which
293  * purpose this library provides various functions and classes for
294  * inter-thread communication, such as Cgu::Notifier and
295  * Cgu::Callback::post().)
296  * @return Returns true, unless the same TextPrintManager object is
297  * being used to print more than one print job and when this method is
298  * called it is already printing another print job (in which case it
299  * returns false).
300  * @exception std::bad_alloc This method might throw std::bad_alloc if
301  * memory is exhausted and the system throws in that case, but only if
302  * it is called in the main program thread. Otherwise it will not
303  * throw.
304  */
305  bool view();
306 
307 /**
308  * Prints the text set with set_text() to file. This method is
309  * thread-safe and may be called in any thread (it hands off its work
310  * to the main program thread via a Cgu::Notifier object), unless the
311  * program by which it is called calls GTK+ directly in more than one
312  * thread and thus employs gdk_threads_enter()/gdk_threads_leave()
313  * (rather than, say, Cgu::Notifier or Cgu::Callback::post()), in
314  * which case it must be called in the main GUI thread only and
315  * surrounded by gdk_threads_enter()/gdk_threads_leave() if called
316  * otherwise than in a GTK+ signal handler. (The best approach
317  * however is for a program only to address GTK+/GDK in the main
318  * program thread, for which purpose this library provides various
319  * functions and classes for inter-thread communication, such as
320  * Cgu::Notifier and Cgu::Callback::post().)
321  * @param filename The filename of the file to which the text is to be
322  * printed.
323  * @return Returns true, unless the same TextPrintManager object is
324  * being used to print more than one print job and when this method is
325  * called it is already printing another print job, or no filename to
326  * print was specified (in either of which case it returns false).
327  * @exception std::bad_alloc This method might throw std::bad_alloc if
328  * memory is exhausted and the system throws in that case.
329  */
330  bool print_to_file(const char* filename);
331 
332 /**
333  * The destructor will not throw. It is thread safe (the
334  * TextPrintManager object may be destroyed in any thread), and does
335  * not call any GTK+/GDK functions.
336  */
338 
339 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
341 #endif
342 };
343 
344 } // namespace Cgu
345 
346 #endif // TEXT_PRINTMANAGER_H