/* Copyright (C) 2006 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <glibmm/object.h>

#include <gtkmm/pagesetup.h>
#include <gtkmm/printcontext.h>
#include <gtkmm/printoperationpreview.h>
#include <gtkmm/printsettings.h>
#include <gtkmm/window.h>

_DEFS(gtkmm,gtk)
_PINCLUDE(glibmm/private/object_p.h)
_PINCLUDE(gtk/gtkprintoperation.h)

namespace Gtk
{

_WRAP_ENUM(PrintStatus, GtkPrintStatus)
_WRAP_ENUM(PrintOperationResult, GtkPrintOperationResult)
_WRAP_ENUM(PrintOperationAction, GtkPrintOperationAction)
_WRAP_GERROR(PrintError, GtkPrintError, GTK_PRINT_ERROR)

/** @defgroup Printing Printing
 */

/** PrintOperation is the high-level, portable printing API. It looks a bit different than other 
 * GTK+ dialogs such as the FileChooser, since some platforms don't expose enough infrastructure 
 * to implement a good print dialog. On such platforms, PrintOperation uses the native print 
 * dialog. On platforms which do not provide a native print dialog, GTK+ uses its own, see PrintUnixDialog.
 *
 * The typical way to use the high-level printing API is to create a PrintOperation object 
 * when the user chooses to print. Then you set some properties on it,such as the page size, any PrintSettings 
 * from previous print operations, the number of  pages, the current page, etc.
 *
 * Then you start the print operation by calling run(). It will then show a dialog to 
 * let the user select a printer and options. When the user finishes the dialog various signals will be 
 * emitted by the PrintOperation for you to handle, the main one being draw_page. You should then 
 * render the page on the provided PrintContext using Cairo.
 *
 * @newin2p10
 *
 * @ingroup Printing
 */
class PrintOperation :
  public Glib::Object,
  public PrintOperationPreview
{
  _CLASS_GOBJECT(PrintOperation, GtkPrintOperation, GTK_PRINT_OPERATION, Glib::Object, GObject)
  _IMPLEMENTS_INTERFACE(PrintOperationPreview)

protected:
  _CTOR_DEFAULT

public:
  _WRAP_CREATE()

  _WRAP_METHOD(void set_default_page_setup(const Glib::RefPtr<PageSetup>& default_page_setup),
               gtk_print_operation_set_default_page_setup)
  _WRAP_METHOD(Glib::RefPtr<PageSetup> get_default_page_setup() const, gtk_print_operation_get_default_page_setup)

  _WRAP_METHOD(void set_print_settings(const Glib::RefPtr<PrintSettings>& print_settings),
               gtk_print_operation_set_print_settings)
  _WRAP_METHOD(Glib::RefPtr<PrintSettings> get_print_settings() const, gtk_print_operation_get_print_settings, refreturn)

  _WRAP_METHOD(void set_job_name(const Glib::ustring& job_name), gtk_print_operation_set_job_name)
  _WRAP_METHOD(void set_n_pages(int n_pages), gtk_print_operation_set_n_pages)
  _WRAP_METHOD(void set_current_page(int current_page), gtk_print_operation_set_current_page)
  _WRAP_METHOD(void set_use_full_page(bool use_full_page = true), gtk_print_operation_set_use_full_page)
  _WRAP_METHOD(void set_unit(Unit unit), gtk_print_operation_set_unit)
  _WRAP_METHOD(void set_export_filename(const std::string& filename), gtk_print_operation_set_export_filename)
  _WRAP_METHOD(void set_track_print_status(bool track_status = true), gtk_print_operation_set_track_print_status)
  _WRAP_METHOD(void set_show_progress (bool show_progress = true), gtk_print_operation_set_show_progress)
  _WRAP_METHOD(void set_allow_async(bool allow_async = true), gtk_print_operation_set_allow_async)
  _WRAP_METHOD(void set_custom_tab_label(const Glib::ustring& label), gtk_print_operation_set_custom_tab_label)

  #m4 _CONVERSION(`GtkPrintOperationAction',`PrintOperationAction',`($2)$3')

  #ifdef GLIBMM_EXCEPTIONS_ENABLED
  PrintOperationResult run(PrintOperationAction action = PRINT_OPERATION_ACTION_PRINT_DIALOG);
  #else
  PrintOperationResult run(PrintOperationAction action, std::auto_ptr<Glib::Error>& error);
  #endif //GLIBMM_EXCEPTIONS_ENABLED

  _WRAP_METHOD(PrintOperationResult run(PrintOperationAction action, Window& parent), gtk_print_operation_run, errthrow)
  _WRAP_METHOD(PrintStatus get_status() const, gtk_print_operation_get_status)
  _WRAP_METHOD(Glib::ustring get_status_string() const, gtk_print_operation_get_status_string)
  _WRAP_METHOD(void cancel(), gtk_print_operation_cancel)
  _WRAP_METHOD(bool is_finished() const, gtk_print_operation_is_finished)

  _IGNORE(gtk_print_run_page_setup_dialog, gtk_print_run_page_setup_dialog_async)

  #m4 _CONVERSION(`GtkPrintOperationResult',`PrintOperationResult',`($2)$3')

  _IGNORE(gtk_print_operation_get_error)

  //TODO: point out in the docs that the PrintOperationResult enum may also indicate
  // that an error occurred, and in that case it is up to him to handle it.
  _WRAP_SIGNAL(void done(PrintOperationResult result), "done")

  //#m4 _CONVERSION(`GtkPrintContext*',`const Glib::RefPtr<PrintContext>&',`Glib::wrap($3, true)')
  _WRAP_SIGNAL(void begin_print(const Glib::RefPtr<PrintContext>& context), "begin_print")
  _WRAP_SIGNAL(bool paginate(const Glib::RefPtr<PrintContext>& context), "paginate")

  #m4 _CONVERSION(`GtkPageSetup*',`const Glib::RefPtr<PageSetup>&',`Glib::wrap($3, true)')
  _WRAP_SIGNAL(void request_page_setup(const Glib::RefPtr<PrintContext>& context, int page_no, const Glib::RefPtr<PageSetup>& setup), "request_page_setup")
  _WRAP_SIGNAL(void draw_page(const Glib::RefPtr<PrintContext>& context, int page_nr), "draw_page")
  _WRAP_SIGNAL(void end_print(const Glib::RefPtr<PrintContext>& context), "end_print")
  _WRAP_SIGNAL(void status_changed(), "status_changed")

  _WRAP_SIGNAL(Widget* create_custom_widget(), "create_custom_widget")

  _WRAP_SIGNAL(void custom_widget_apply(Widget* widget), "custom_widget_apply")

  #m4 _CONVERSION(`GtkPrintOperationPreview*', `const Glib::RefPtr<PrintOperationPreview>&', `Glib::wrap($3, true)')
  #m4 _CONVERSION(`const Glib::RefPtr<PrintOperationPreview>&', `GtkPrintOperationPreview*', `($3)->gobj()')

  #m4 _CONVERSION(`Window*',`GtkWindow*',`Glib::unwrap($3)')

  //TODO: This is causing crashes. Is it still causing crashes? murrayc.
  _WRAP_SIGNAL(bool preview(const Glib::RefPtr<PrintOperationPreview>& preview, const Glib::RefPtr<PrintContext>& context, Window* parent), "preview")

  _WRAP_PROPERTY("default_page_setup", Glib::RefPtr<PageSetup>)
  _WRAP_PROPERTY("print_settings", Glib::RefPtr<PrintSettings>)
  _WRAP_PROPERTY("job_name", Glib::ustring)
  _WRAP_PROPERTY("n_pages", int)
  _WRAP_PROPERTY("current_page", int)
  _WRAP_PROPERTY("use_full_page", bool)
  _WRAP_PROPERTY("unit", Unit)
  _WRAP_PROPERTY("show_progress", bool)
  _WRAP_PROPERTY("allow_async", bool)
  _WRAP_PROPERTY("export_filename", std::string)
  _WRAP_PROPERTY("status", PrintStatus)
  _WRAP_PROPERTY("status_string", Glib::ustring)
  _WRAP_PROPERTY("custom_tab_label", Glib::ustring)
};

  //TODO: Make these static members of a class instead of non-class functions?

  //Note: gtk_run_page_setup_dialog() can take a null page_setup object, but the application should always 
  //store and reuse a page_setup object, so I see no need to provide an overload for that. murrayc.
  //TODO: The parent parameter may also be null, so maybe we should add an overload for that.

  /** Runs a page setup dialog, letting the user modify the values from page_setup. 
   * If the user cancels the dialog, the returned PageSetup is identical to that passed in @a page_setup, 
   * otherwise it contains the modifications done in the dialog.
   * 
   * Note that this function may use a recursive mainloop to show the page setup dialog. 
   * See run_page_setup_dialog_async() if this is a problem.
   *
   * @param parent Transient parent.
   * @param page_setup An existing GtkPageSetup.
   * @param settings Print settings.
   * @result A new PageSetup object.
   *
   * @since 2.10
   */
  Glib::RefPtr<PageSetup> run_page_setup_dialog(Window& parent,
                                                const Glib::RefPtr<const PageSetup>& page_setup,
                                                const Glib::RefPtr<const PrintSettings>& print_settings);

  /** For example, 
   * void on_setup_done(const Glib::RefPtr<PageSetup>& page_setup);
   */
  typedef sigc::slot< void, const Glib::RefPtr<PageSetup>& > SlotPrintSetupDone;

  /** Runs a page setup dialog, letting the user modify the values from page_setup.
   *
   * In contrast to run_page_setup_dialog(), this function returns after showing the 
   * page setup dialog on platforms that support this, and calls the @a slot from a 
   * signal handler for the ::response signal of the dialog.
   *
   * @param parent Transient parent.
   * @param page_setup An existing GtkPageSetup.
   * @param settings Print settings.
   * @result A new PageSetup object.
   * @param slot
   *
   * @since 2.10
   */
  void run_page_setup_dialog_async(Window& parent,
                                   const Glib::RefPtr<const PageSetup>& page_setup,
                                   const Glib::RefPtr<const PrintSettings>& print_settings,
                                   const SlotPrintSetupDone& slot);

} // namespace Gtk
