📄 fax_list.cpp
字号:
/* Copyright (C) 2001 2002 2003 Chris VineThis program is distributed under the General Public Licence, version 2.For particulars of this and relevant disclaimers see the fileCOPYING distributed with the source files.*/#include <vector>#include <cstdlib>#include <fstream>#include <iomanip>#include <list>#include <cstring>#include <unistd.h>#include <limits.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/wait.h>#include <dirent.h>#include <stdlib.h>#include <signal.h>#include <errno.h>#ifdef HAVE_PTHREAD_SIGMASK #include <pthread.h>#endif#include <gdkmm/pixbuf.h>#include <gdk/gdkkeysyms.h> // the key codes are here#include <gtkmm/main.h>#include <gtkmm/image.h>#include <gtkmm/stock.h>#include <gtkmm/tooltips.h>#include <glibmm/convert.h>#include <glibmm/timer.h>#include <glibmm/thread.h>#include "fax_list.h"#include "dialogs.h"#include "fax_list_icons.h"#include "pipes.h"#ifdef HAVE_STRINGSTREAM#include <sstream>#else#include <strstream>#endif#ifdef ENABLE_NLS#include <libintl.h>#endifint FaxListDialog::is_fax_received_list = 0;int FaxListDialog::is_fax_sent_list = 0;FaxListDialog::FaxListDialog(Mode mode_, const int standard_size_): Gtk::Window(Gtk::WINDOW_TOPLEVEL), mode(mode_), standard_size(standard_size_), fax_basename_sem(1), fax_list_box(false, 0), table(2, 1, false), close_button(Gtk::Stock::CLOSE), button_box(Gtk::BUTTONBOX_SPREAD) { // notify the existence of this object if (mode == received) is_fax_received_list++; else is_fax_sent_list++; fax_list_scroll_window.set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); fax_list_scroll_window.add(tree_view); fax_list_scroll_window.set_shadow_type(Gtk::SHADOW_IN); // create the tree model: list_store_r = Gtk::ListStore::create(model_columns); // connect it to the tree view tree_view.set_model(list_store_r); // add the columns of the tree model to tree view tree_view.append_column(gettext("Fax"), model_columns.fax_name); tree_view.append_column(gettext("Description"), model_columns.fax_description); // single line selection tree_view.get_selection()->set_mode(Gtk::SELECTION_SINGLE); // populate the fax list get_fax_list_rows(); // set up the tool bar tool_bar.set_orientation(Gtk::ORIENTATION_HORIZONTAL); tool_bar.set_toolbar_style(Gtk::TOOLBAR_ICONS); // first make the image widgets Gtk::Image* print_image_p = manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(print_xpm))); Gtk::Image* view_image_p = manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(view_xpm))); Gtk::Image* describe_image_p = manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(describe_xpm))); Gtk::Image* delete_image_p = manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(delete_xpm))); Gtk::Image* refresh_image_p = manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(refresh_xpm))); tool_bar.set_tooltips(true);#if GTKMM_VERSION >= 24 tool_bar.set_toolbar_style(Gtk::TOOLBAR_ICONS); Gtk::Tooltips* tooltips_p = tool_bar.get_tooltips_object(); tooltips_p->enable(); print_button_p = manage(new Gtk::ToolButton(*print_image_p)); tool_bar.append(*print_button_p, sigc::mem_fun(*this, &FaxListDialog::print_fax_prompt)); print_button_p->set_sensitive(false); print_button_p->set_tooltip(*tooltips_p, gettext("Print selected fax")); view_button_p = manage(new Gtk::ToolButton(*view_image_p)); tool_bar.append(*view_button_p, sigc::mem_fun(*this, &FaxListDialog::view_fax)); view_button_p->set_sensitive(false); view_button_p->set_tooltip(*tooltips_p, gettext("View selected fax")); describe_button_p = manage(new Gtk::ToolButton(*describe_image_p)); tool_bar.append(*describe_button_p, sigc::mem_fun(*this, &FaxListDialog::describe_fax_prompt)); describe_button_p->set_sensitive(false); describe_button_p->set_tooltip(*tooltips_p, gettext("Add/amend description for selected fax")); delete_button_p = manage(new Gtk::ToolButton(*delete_image_p)); tool_bar.append(*delete_button_p, sigc::mem_fun(*this, &FaxListDialog::delete_fax_prompt)); delete_button_p->set_sensitive(false); delete_button_p->set_tooltip(*tooltips_p, gettext("Delete selected fax")); Gtk::ToolButton* refresh_button_p = manage(new Gtk::ToolButton(*refresh_image_p)); tool_bar.append(*refresh_button_p, sigc::mem_fun(*this, &FaxListDialog::refresh_slot)); refresh_button_p->set_tooltip(*tooltips_p, gettext("Refresh fax list"));#else Gtk::Button* refresh_button_p; { using namespace Gtk::Toolbar_Helpers; ToolList& tool_list = tool_bar.tools(); tool_list.push_back(ButtonElem(*print_image_p, SigC::slot(*this, &FaxListDialog::print_fax_prompt), gettext("Print selected fax"))); print_button_p = static_cast<Gtk::Button*>(tool_list.back().get_widget()); print_button_p->set_relief(Gtk::RELIEF_NONE); print_button_p->set_sensitive(false); tool_list.push_back(ButtonElem(*view_image_p, SigC::slot(*this, &FaxListDialog::view_fax), gettext("View selected fax"))); view_button_p = static_cast<Gtk::Button*>(tool_list.back().get_widget()); view_button_p->set_relief(Gtk::RELIEF_NONE); view_button_p->set_sensitive(false); tool_list.push_back(ButtonElem(*describe_image_p, SigC::slot(*this, &FaxListDialog::describe_fax_prompt), gettext("Add/amend description for selected fax"))); describe_button_p = static_cast<Gtk::Button*>(tool_list.back().get_widget()); describe_button_p->set_relief(Gtk::RELIEF_NONE); describe_button_p->set_sensitive(false); tool_list.push_back(ButtonElem(*delete_image_p, SigC::slot(*this, &FaxListDialog::delete_fax_prompt), gettext("Delete selected fax"))); delete_button_p = static_cast<Gtk::Button*>(tool_list.back().get_widget()); delete_button_p->set_relief(Gtk::RELIEF_NONE); delete_button_p->set_sensitive(false); tool_list.push_back(ButtonElem(*refresh_image_p, SigC::slot(*this, &FaxListDialog::refresh_slot), gettext("Refresh fax list"))); refresh_button_p = static_cast<Gtk::Button*>(tool_list.back().get_widget()); }#endif button_box.add(close_button); table.attach(fax_list_scroll_window, 0, 1, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::EXPAND | Gtk::FILL, standard_size/3, standard_size/3); table.attach(button_box, 0, 1, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, standard_size/3, standard_size/3); fax_list_box.pack_start(tool_bar, false, false); fax_list_box.pack_start(table, true, true); // now connect up the signal which indicates a selection has been made tree_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &FaxListDialog::set_buttons_slot)); // connect up close_button close_button.signal_clicked().connect(sigc::mem_fun(*this, &FaxListDialog::close_slot)); close_button.set_flags(Gtk::CAN_DEFAULT); close_button.grab_focus(); table.set_border_width(standard_size/3); if (mode == received) set_title(gettext("efax-gtk: Received fax list")); else set_title(gettext("efax-gtk: Sent fax list")); //set_position(Gtk::WIN_POS_CENTER); add(fax_list_box); set_default_size(standard_size * 15, standard_size * 12); set_icon(prog_config.window_icon_r); show_all();#if GTKMM_VERSION < 24 refresh_button_p->set_relief(Gtk::RELIEF_NORMAL);#endif refresh_button_p->set_sensitive(true);}FaxListDialog::~FaxListDialog(void) { // notify the destruction of this object if (mode == received) is_fax_received_list--; else is_fax_sent_list--;}void FaxListDialog::get_fax_list_rows(void) { std::string dir(prog_config.homedir); if (mode == received) dir += "/faxin"; else dir += "/faxsent"; chdir(dir.c_str()); DIR* dir_p; if ((dir_p = opendir(dir.c_str())) == 0) { std::string msg("Can't open directory "); msg += dir; msg += '\n'; write_error(msg.c_str()); } else { struct dirent* direntry; struct stat statinfo; std::list<std::string> dir_list; // first populate dir_list with the directory names in $HOME/faxin while ((direntry = readdir(dir_p)) != 0) { stat(direntry->d_name, &statinfo); if (S_ISDIR(statinfo.st_mode) && std::strcmp(direntry->d_name, "oldfax") && std::strcmp(direntry->d_name, ".") && std::strcmp(direntry->d_name, "..") && (mode == sent || std::strcmp(direntry->d_name, prog_config.receive_dirname))) { dir_list.push_back(direntry->d_name); } } closedir(dir_p); // now insert the directory names in fax_list, with description (if any) // first clear the list store -- we need to clear it here before // testing for an empty dir_list, or on deleting the last fax in the list, // the clear won't take out the former last entry list_store_r->clear(); if (!dir_list.empty()) { // first sort them dir_list.sort(); // populate the list store, and get the fax description (if any) std::string filename; std::string line; std::ifstream file; std::list<std::string>::const_iterator iter; for (iter = dir_list.begin(); iter!= dir_list.end(); ++iter) { // get a list store row to insert the fax name Gtk::TreeModel::Row row = *(list_store_r->append()); row[model_columns.fax_name] = *iter; // now see if there is a description filename = dir + '/'; filename += *iter; filename += "/Description";#ifdef HAVE_IOS_NOCREATE file.open(filename.c_str(), std::ios::in | std::ios::nocreate);#else // we must have Std C++ so we probably don't need a ios::nocreate // flag on a read open to ensure uniqueness file.open(filename.c_str(), std::ios::in);#endif if (file) { while (std::getline(file, line) && line.empty()); } if (!line.empty()) { try { row[model_columns.fax_description] = Glib::locale_to_utf8(line); } catch (Glib::ConvertError&) { write_error("UTF-8 conversion error in FaxListDialog::get_fax_list_rows()\n"); } } filename = ""; line = ""; file.clear(); file.close(); } } } // reset current directory std::string temp(prog_config.homedir + "/faxin"); chdir(temp.c_str());}void FaxListDialog::close_slot(void) { hide_all(); delete this; // this is completely safe as the dialog is self-owning and modeless}bool FaxListDialog::on_delete_event(GdkEventAny*) { close_slot(); return true; // returning true prevents destroy sig being emitted}void FaxListDialog::set_buttons_slot(void) { // see if anything is selected if (tree_view.get_selection()->get_selected()) { print_button_p->set_sensitive(true); view_button_p->set_sensitive(true); describe_button_p->set_sensitive(true); delete_button_p->set_sensitive(true);#if GTKMM_VERSION < 24 print_button_p->set_relief(Gtk::RELIEF_NORMAL); view_button_p->set_relief(Gtk::RELIEF_NORMAL); describe_button_p->set_relief(Gtk::RELIEF_NORMAL); delete_button_p->set_relief(Gtk::RELIEF_NORMAL);#endif } else { print_button_p->set_sensitive(false); view_button_p->set_sensitive(false); describe_button_p->set_sensitive(false); delete_button_p->set_sensitive(false);#if GTKMM_VERSION < 24 print_button_p->set_relief(Gtk::RELIEF_NONE); view_button_p->set_relief(Gtk::RELIEF_NONE); describe_button_p->set_relief(Gtk::RELIEF_NONE); delete_button_p->set_relief(Gtk::RELIEF_NONE);#endif }}void FaxListDialog::describe_fax_prompt(void) { Gtk::TreeModel::iterator row_iter = tree_view.get_selection()->get_selected(); if (row_iter) { Glib::ustring description; description = (*row_iter)[model_columns.fax_description]; DescriptionDialog* dialog_p = new DescriptionDialog(standard_size, description, *this); dialog_p->accepted.connect(sigc::mem_fun(*this, &FaxListDialog::describe_fax)); // there is no memory leak -- the memory will be deleted when DescriptionDialog closes }}void FaxListDialog::describe_fax(const Glib::ustring& description) { Gtk::TreeModel::iterator row_iter = tree_view.get_selection()->get_selected(); if (row_iter) { (*row_iter)[model_columns.fax_description] = description; std::string filename(prog_config.homedir); if (mode == received) filename += "/faxin/"; else filename += "/faxsent/"; filename += (*row_iter)[model_columns.fax_name]; filename += "/Description"; std::ofstream file(filename.c_str(), std::ios::out); // this try()/catch() block is ultra-cautious - something has gone seriously // wrong with the program if the UTF-8 conversion fails since the source is // a Gtk::Entry object try { if (file) file << Glib::locale_from_utf8(description); else { std::string msg("Can't open file "); msg += filename; msg += '\n'; write_error(msg.c_str()); } } catch (Glib::ConvertError&) { write_error("UTF-8 conversion error in FaxListDialog::describe_fax()\n"); } }}void FaxListDialog::print_fax_prompt(void) { // we do not need a mutex before reading prog_config.print_popup, even though // it is also read in FaxListDialog::print_fax_thread(), because it is of type // bool which can be safely concurrently read in different threads and in any // event it is read in FaxListDialog::print_fax_thread() in a separate process // after fork()ing so there isn't even concurrent access if (prog_config.print_popup) { Gtk::TreeModel::iterator row_iter = tree_view.get_selection()->get_selected(); // we do not need a mutex before reading prog_config.print_cmd either // as although read in FaxListDialog::get_print_from_stdin_parms(), // the thread which executes that method cannot start until the prompt // dialog below is launched if (row_iter && !prog_config.print_cmd.empty()) { std::string faxnumber((*row_iter)[model_columns.fax_name]); Glib::ustring msg(gettext("Print fax ")); msg += faxnumber + gettext("?"); PromptDialog* dialog_p = new PromptDialog(msg, gettext("Print fax"), standard_size, *this); dialog_p->accepted.connect(sigc::mem_fun(*this, &FaxListDialog::print_fax)); // there is no memory leak -- the memory will be deleted when PromptDialog closes } } else print_fax();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -