Logo Search packages:      
Sourcecode: passepartout version File versions  Download package

printdialog.cc

///
// Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING
///
#include "printdialog.h"
#include "widget/subpanel.h"
#include "widget/wmisc.h"
#include "widget/usererror.h"
#include <fstream>

#include <gtkmm/table.h>
#include <gtkmm/separator.h>
#include <gtkmm/stock.h>
#include <gtkmm/sizegroup.h>

#include "util/warning.h"
#include "util/filesys.h"
#include "util/os.h"
#include "util/tempfile.h"

#include "config.h"
#include "docview.h"
#include "document/document.h"
#include "widget/errordialog.h"

namespace {
  const Glib::ustring  ps_format("PostScript"),
    eps_format("Encapsulated PostScript (EPS)"),
    pdf_format("Portable Document Format (PDF)");
}

PrintDialog::PrintDialog(Gtk::Window &parent, 
                     DocumentView &_document_view):
  DialogWrap("Print", parent), 
  using_button("Print _using:", true), file_button("Print _to file:", true),
  all_button("_All", true), current_button("Cu_rrent", true), 
  from_button("Fro_m:", true), 
  fonts_button("_Include fonts", true),
  gray_button("_Grayscale", true),
  from_spinner(0, false), to_spinner(0, false),
  document_view(_document_view),
  file_entry("Print To File")
{
  set_resizable(false);

  {
    Gtk::RadioButton::Group group = using_button.get_group();
    file_button.set_group(group);
  }

  {
    Gtk::RadioButton::Group group = all_button.get_group();
    current_button.set_group(group);
    from_button.set_group(group);
  }
  
  Glib::RefPtr<Gtk::SizeGroup>  sizegroup = 
    Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
  sizegroup->add_widget(using_button);
  sizegroup->add_widget(file_button);

  Gtk::HBox *format_menu_box = manage(new Gtk::HBox(false, double_space));
  Gtk::Label *format_menu_label = manage(new Gtk::Label("_Format: ",
                                                        0.0, 0.5, true));
  format_menu_label->set_mnemonic_widget(format_menu);
  format_menu_box->pack_start(*format_menu_label, Gtk::PACK_SHRINK);
  {
    using namespace Gtk;
    using namespace Menu_Helpers;

    Menu *menu = manage(new Menu());
    MenuList& menu_list = menu->items();
    menu_list.push_back(MenuElem(ps_format));
    menu_list.push_back(MenuElem(eps_format));
    menu_list.push_back(MenuElem(pdf_format));

    format_menu.set_menu(*menu);
  }
  format_menu.get_menu()->signal_selection_done().connect
    (slot(*this, &PrintDialog::update));
  format_menu_box->pack_start(format_menu, Gtk::PACK_EXPAND_WIDGET);

  Gtk::HBox *using_box = manage(new Gtk::HBox(false, double_space));
  using_box->pack_start(using_button, Gtk::PACK_SHRINK);
  using_box->pack_start(using_entry, Gtk::PACK_EXPAND_WIDGET);
    
  Gtk::HBox *file_box = manage(new Gtk::HBox(false, double_space));
  file_box->pack_start(file_button, Gtk::PACK_SHRINK);
  file_box->pack_start(file_entry, Gtk::PACK_EXPAND_WIDGET);

  Gtk::HBox *from_to_box = manage(new Gtk::HBox(false, double_space));
  from_to_box->pack_start(from_button, Gtk::PACK_SHRINK);
  from_to_box->pack_start(from_spinner, Gtk::PACK_SHRINK);
  from_to_box->pack_start(*manage(new Gtk::Label("to:")), 
                   Gtk::PACK_SHRINK);
  from_to_box->pack_start(to_spinner, Gtk::PACK_SHRINK);

  SubPanel *pages_box = manage(new SubPanel("Pages"));
  this->pages_box = pages_box;
  pages_box->pack_start(all_button, Gtk::PACK_SHRINK);
  pages_box->pack_start(current_button, Gtk::PACK_SHRINK);
  pages_box->pack_start(*from_to_box, Gtk::PACK_SHRINK);

  Gtk::VBox *format_box = manage(new Gtk::VBox(false, single_space));
  format_box->pack_start(fonts_button, Gtk::PACK_SHRINK);
  fonts_button.set_active(); // include fonts by default
  format_box->pack_start(gray_button, Gtk::PACK_SHRINK);

  Gtk::HBox *foo_box = manage(new Gtk::HBox(false, double_space));
  foo_box->pack_start(*pages_box, Gtk::PACK_EXPAND_WIDGET);
  foo_box->pack_start(*manage(new Gtk::VSeparator()));
  foo_box->pack_start(*format_box, Gtk::PACK_SHRINK);

  Gtk::VBox *vbox = manage(new Gtk::VBox(false, double_space));
  vbox->set_border_width(border_width);
  //set_border_width(border_width);

  vbox->pack_start(*format_menu_box, Gtk::PACK_SHRINK);
  vbox->pack_start(*using_box, Gtk::PACK_SHRINK);
  vbox->pack_start(*file_box, Gtk::PACK_SHRINK);
  vbox->pack_start(*foo_box, Gtk::PACK_SHRINK, single_space);

  get_vbox()->pack_start(*vbox);
  get_vbox()->show_all();
  get_action_area()->show_all();

  using_entry.set_text(config.PrintCommand.values.front());
  using_button.set_active(true);

  using_button.signal_clicked().connect(slot(*this, &PrintDialog::update));
  // If there are only two buttons in a group, you only need to connect one.
  // If there are more, you need to connect them all. That is annoying.
  all_button.signal_clicked().connect(slot(*this, &PrintDialog::update));
  current_button.signal_clicked().connect(slot(*this, &PrintDialog::update));
  from_button.signal_clicked().connect(slot(*this, &PrintDialog::update));

  add_button(Gtk::Stock::CANCEL, 0);
  add_button(Gtk::Stock::PRINT, 1)->grab_default();
}

void PrintDialog::show_it() {
  DocRef document = document_view.get_document();
  if(!document)
    return;
  int first = document->get_first_page_num();
  int last = first + ((int) document->get_num_of_pages()) - 1;
  save_state(); 
  from_spinner.limits(first, last);  
  to_spinner.limits(first, last);
  from_spinner.set(first);
  to_spinner.set(last);
  show();
  // Gtk::Entry::set_position doesn't seem to work 
  // unless the entry is shown first
  const std::string &filename = 
    document_view.get_document_meta().get_filename();
  if(filename.empty())     // the document has not been saved 
    file_entry.entry.set_text("pptout.foo");
  else
    file_entry.entry.set_text(filename);
  update();
}

Glib::ustring PrintDialog::get_format() const {
  if(const Gtk::Label* label
     = dynamic_cast<const Gtk::Label*>(format_menu.get_child()))
    return label->get_text();
  else {
    warning << "OptionMenu child is not a Label" << std::endl;
    return "poop";
  }
}

void PrintDialog::set_format(const Glib::ustring &format) {
  using namespace Gtk::Menu_Helpers;
  MenuList::iterator i;
  const MenuList &items = format_menu.get_menu()->items();
  int j;
  for(i = items.begin(), j = 0; i != items.end(); i++, j++) {
    const Gtk::Label *label = dynamic_cast<Gtk::Label*>(i->get_child());
    if(label && label->get_text() == format) {
      format_menu.set_history(j);
      return;
    }
  }
}

void PrintDialog::on_response(int response_id) {
  Glib::RefPtr<Gdk::Window> window = get_window();
  if(response_id == 0) {
    restore_state();
    hide();
  } else if(response_id == 1) { 
    try { 
      DocRef document = document_view.get_document();
      if(document) {
      int first = document->get_first_page_num();
      int last = first + document->get_num_of_pages() - 1;
      if(current_button.get_active()) {
        first = last = document_view.get_current_page_num();
      } else if(from_button.get_active()) {
        first = int(from_spinner.get());
        last = int(to_spinner.get());
        if(last < first)
          throw UserError("Bad page interval",
                      "\"From\" page number must be lower\n"
                      "than \"To\" page number");
        // We could make this error impossible to cause, 
        // but I don't like putting leash and collar on the user.
      }
      // else all_button is active
        std::ofstream out;
        std::auto_ptr<Tempfile> tempfile;
        bool print_to_file = file_button.get_active();
      if(print_to_file) {
          out.open(file_entry.entry.get_text().c_str());
        } else {
          tempfile.reset(new Tempfile);
          out.open(tempfile->get_filename().c_str());
        }
        if(!out) throw UserError("Failed to open file for printing:\n"
                                 + file_entry.entry.get_text(),
                                 "Check if you have permission "
                                 "to write to this file");
        window->set_cursor(Gdk::WATCH);
        // make sure the cursor is updated
        while(Gtk::Main::events_pending())
          Gtk::Main::iteration();
        Glib::ustring format = get_format();
        if(format == pdf_format) {
          PDF::Document::Ptr result = PDF::Document::create();
          document->print_pdf(result, first, last);
          result->write(out);
          int failed_chars = result->getNumOfFailedChars();
          /// \todo show warning dialog instead
          if(failed_chars)
            ErrorDialog::instance().show_warning
              ("Failed to print " + tostr(failed_chars) + " characters",
               "This was probably caused by using characters not "
               "present in the MacRoman encoding together with Type1 fonts.\n"
               "Passepartout currently lacks full Unicode support for Type1 "
               "fonts when printing to PDF.");
        } else if(format == eps_format)
          document->print(out,
                          // only the current page
                          document_view.get_current_page_num(),
                          document_view.get_current_page_num(),
                          true,
                          fonts_button.get_active(), gray_button.get_active());
        else // ps
          document->print(out, first, last,
                          false,
                          fonts_button.get_active(), gray_button.get_active());
        window->set_cursor();
        if(!print_to_file) { // pipe to a program
          std::string stdout_data, stderr_data;
        int status;
        std::string command = using_entry.get_text() 
          + " < " + tempfile->get_filename();
        command = "sh -c \"" + command + '\"';
        try {
          debug << command << std::endl;
          Glib::spawn_command_line_sync(command,
                                &stdout_data, &stderr_data, &status);
          debug << status << std::endl;
          debug << stderr_data << std::endl;
        } catch(const Glib::SpawnError &e) {
          // Glib::SpawnError is not a std::exception
          throw UserError("Failed to run: "
                      + using_entry.get_text(),
                      e.what());
        }
        if(status != 0)
          throw UserError("Failed to print using: "
                      + using_entry.get_text(),
                      stderr_data);
      }
      hide();
      }
    }
    catch(...) {
      window->set_cursor(); // restore normal cursor
      throw;
    }
  }
}

void PrintDialog::save_state() {
  saved_using_text = using_entry.get_text();
  saved_file_text = file_entry.entry.get_text();
  saved_file_not_using = file_button.get_active();
  saved_gray = gray_button.get_active();
  saved_fonts = fonts_button.get_active();
  saved_format = get_format();
}

void PrintDialog::restore_state() {
  using_entry.set_text(saved_using_text);
  file_entry.entry.set_text(saved_file_text);
  file_button.set_active(saved_file_not_using);
  gray_button.set_active(saved_gray);
  fonts_button.set_active(saved_fonts);
  set_format(saved_format);
}

void PrintDialog::update() {
  using_entry.set_sensitive(using_button.get_active());
  file_entry.set_sensitive(file_button.get_active());
  from_spinner.set_sensitive(from_button.get_active());
  to_spinner.set_sensitive(from_button.get_active());
  Glib::ustring format = get_format();
  // always include fonts in PDFs
  fonts_button.set_sensitive(format != pdf_format);
  // grayscale should apply to pdf too, eventually
  gray_button.set_sensitive(format != pdf_format);
  // eps format always prints the current page only
  pages_box->set_sensitive(format != eps_format);
  std::string suffix = ".ps";
  if(format == pdf_format) suffix = ".pdf";
  else if(format == eps_format) suffix = ".eps";
  file_entry.entry.set_text(no_suffix(file_entry.entry.get_text()) + suffix);
}

Generated by  Doxygen 1.6.0   Back to index