📄 socket_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 <sys/types.h>#include <unistd.h>#include <cstdlib>#include <vector>#include <gdkmm/pixbuf.h>#include <gtkmm/image.h>#include <gtkmm/stock.h>#include <gtkmm/label.h>#include <gtkmm/tooltips.h>#include <glibmm/timer.h>#include <glibmm/convert.h>#include "socket_list.h"#include "dialogs.h"#include "socket_list_icons.h"#ifdef HAVE_STRINGSTREAM#include <sstream>#else#include <strstream>#endif#ifdef ENABLE_NLS#include <libintl.h>#endifint SocketListDialog::is_socket_list = 0;SocketListDialog::SocketListDialog(std::pair<Shared_ptr<FilenamesList>, Shared_ptr<Glib::Mutex::Lock> > filenames_pair, const int standard_size_): Gtk::Window(Gtk::WINDOW_TOPLEVEL), standard_size(standard_size_), socket_list_box(false, 0), table(2, 1, false), close_button(Gtk::Stock::CLOSE), button_box(Gtk::BUTTONBOX_SPREAD) { // notify the existence of this object is_socket_list++; socket_list_scroll_window.set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); socket_list_scroll_window.add(tree_view); socket_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 first column of the tree model to tree view // (the second column is hidden and just contains data (a file name) to // which the first column relates) tree_view.append_column(gettext("Queued print jobs"), model_columns.fax_label); // single line selection tree_view.get_selection()->set_mode(Gtk::SELECTION_SINGLE); // populate the socket file list set_socket_list_rows(filenames_pair); // 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* view_image_p = manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(view_xpm))); Gtk::Image* remove_image_p = manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(remove_xpm))); Gtk::Image* send_image_p = manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(send_fax_xpm))); tool_bar.set_tooltips(true); Gtk::HBox* send_hbox_p = manage(new Gtk::HBox); Gtk::Label* send_label_p = manage(new Gtk::Label(gettext("Enter selected fax to send"))); send_hbox_p->pack_start(*send_image_p, Gtk::PACK_SHRINK, 4); send_hbox_p->pack_start(*send_label_p, Gtk::PACK_SHRINK, 4);#if GTKMM_VERSION >= 24 tool_bar.set_toolbar_style(Gtk::TOOLBAR_ICONS); Gtk::Tooltips* tooltips_p = tool_bar.get_tooltips_object(); tooltips_p->enable(); view_button_p = manage(new Gtk::ToolButton(*view_image_p)); tool_bar.append(*view_button_p, sigc::mem_fun(*this, &SocketListDialog::view_file)); view_button_p->set_sensitive(false); view_button_p->set_tooltip(*tooltips_p, gettext("View selected file")); remove_button_p = manage(new Gtk::ToolButton(*remove_image_p)); tool_bar.append(*remove_button_p, sigc::mem_fun(*this, &SocketListDialog::remove_file_prompt)); remove_button_p->set_sensitive(false); remove_button_p->set_tooltip(*tooltips_p, gettext("Remove selected file from list")); send_button_p = manage(new Gtk::ToolButton(*send_hbox_p)); tool_bar.append(*send_button_p, sigc::mem_fun(*this, &SocketListDialog::send_fax_slot)); send_button_p->set_sensitive(false); send_button_p->set_tooltip(*tooltips_p, gettext("Choose the selected fax for sending"));#else { using namespace Gtk::Toolbar_Helpers; send_button.add(*send_hbox_p); ToolList& tool_list = tool_bar.tools(); tool_list.push_back(ButtonElem(*view_image_p, SigC::slot(*this, &SocketListDialog::view_file), gettext("View selected file"))); 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(*remove_image_p, SigC::slot(*this, &SocketListDialog::remove_file_prompt), gettext("Remove selected file from list"))); remove_button_p = static_cast<Gtk::Button*>(tool_list.back().get_widget()); remove_button_p->set_relief(Gtk::RELIEF_NONE); remove_button_p->set_sensitive(false); tool_list.push_back(Element(send_button, gettext("Choose the selected fax for sending"))); send_button.signal_clicked().connect(SigC::slot(*this, &SocketListDialog::send_fax_slot)); send_button.set_relief(Gtk::RELIEF_NONE); send_button.set_sensitive(false); }#endif button_box.add(close_button); table.attach(socket_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); socket_list_box.pack_start(tool_bar, false, false); socket_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, &SocketListDialog::set_buttons_slot)); close_button.signal_clicked().connect(sigc::mem_fun(*this, &SocketListDialog::close_slot)); close_button.set_flags(Gtk::CAN_DEFAULT); table.set_border_width(standard_size/3); set_title(gettext("efax-gtk: Queued faxes from socket")); //set_position(Gtk::WIN_POS_CENTER); add(socket_list_box); set_default_size(standard_size * 15, standard_size * 12); set_icon(prog_config.window_icon_r); show_all();#if GTKMM_VERSION >= 24 tool_bar.set_size_request(send_button_p->get_width() + view_button_p->get_width() + remove_button_p->get_width() + 12, send_button_p->get_height());#endif}SocketListDialog::~SocketListDialog(void) { // notify the destruction of this object is_socket_list--;}void SocketListDialog::send_fax_slot(void) { std::pair<Glib::ustring, std::string> fax_to_send; Gtk::TreeModel::iterator row_iter = tree_view.get_selection()->get_selected(); if (row_iter) { fax_to_send.first = (*row_iter)[model_columns.fax_label]; fax_to_send.second = (*row_iter)[model_columns.fax_filename]; selected_fax(fax_to_send); }}void SocketListDialog::close_slot(void) { hide_all(); dialog_closed(); delete this; // this is completely safe as the dialog is self-owning and modeless}bool SocketListDialog::on_delete_event(GdkEventAny*) { close_slot(); return true; // returning true prevents destroy sig being emitted}void SocketListDialog::set_socket_list_rows(std::pair<Shared_ptr<FilenamesList>, Shared_ptr<Glib::Mutex::Lock> > filenames_pair) { FilenamesList::const_iterator iter; list_store_r->clear(); for (iter = filenames_pair.first->begin(); iter != filenames_pair.first->end(); ++iter) { // iter->first will contain the temporary file name created by mkstemp // in void Socket_server::accept_client() // iter->second will contain the print job number assigned by // Socket_serve::add_file() // get a list store row to insert the file name Gtk::TreeModel::Row row = *(list_store_r->append()); // manufacture the fax label#ifdef HAVE_STRINGSTREAM std::ostringstream strm; strm << gettext("PRINT JOB: ") << iter->second; row[model_columns.fax_label] = strm.str();#else std::ostrstream strm; strm << gettext("PRINT JOB: ") << iter->second << std::ends; const char* fax_label_p = strm.str(); row[model_columns.fax_label] = fax_label_p; delete[] fax_label_p;#endif // insert the fax filename (this is a hidden column, which will not // be displayed in the tree view) row[model_columns.fax_filename] = iter->first; }}void SocketListDialog::set_buttons_slot(void) { // see if anything is selected if (tree_view.get_selection()->get_selected()) { view_button_p->set_sensitive(true); remove_button_p->set_sensitive(true);#if GTKMM_VERSION >= 24 send_button_p->set_sensitive(true);#else view_button_p->set_relief(Gtk::RELIEF_NORMAL); remove_button_p->set_relief(Gtk::RELIEF_NORMAL); send_button.set_sensitive(true); send_button.set_relief(Gtk::RELIEF_NORMAL);#endif } else { view_button_p->set_sensitive(false); remove_button_p->set_sensitive(false);#if GTKMM_VERSION >= 24 send_button_p->set_sensitive(false);#else view_button_p->set_relief(Gtk::RELIEF_NONE); remove_button_p->set_relief(Gtk::RELIEF_NONE); send_button.set_sensitive(false); send_button.set_relief(Gtk::RELIEF_NONE);#endif }}std::pair<const char*, char* const*> SocketListDialog::get_view_file_parms(const string& file_name) { std::vector<std::string> view_parms; std::string view_cmd; std::string view_name; std::string::size_type end_pos; try { // lock the Prog_config object to stop it being accessed in // FaxListDialog::get_ps_viewer_parms() while we are accessing it here // (this is ultra cautious as it is only copied/checked for emptiness // there) Glib::Mutex::Lock lock(*prog_config.mutex_p); view_cmd = Glib::filename_from_utf8(prog_config.ps_view_cmd); } catch (Glib::ConvertError&) { write_error("UTF-8 conversion error in SocketListDialog::view_file()\n"); return std::pair<const char*, char* const*>(0,0); } if ((end_pos = view_cmd.find_first_of(' ')) != std::string::npos) { // we have parms view_name.assign(view_cmd, 0, end_pos); view_parms.push_back(view_name); // find start of next parm std::string::size_type start_pos = view_cmd.find_first_not_of(' ', end_pos); while (start_pos != std::string::npos) { end_pos = view_cmd.find_first_of(' ', start_pos); if (end_pos != std::string::npos) { view_parms.push_back(view_cmd.substr(start_pos, end_pos - start_pos)); start_pos = view_cmd.find_first_not_of(' ', end_pos); // prepare for next interation } else { view_parms.push_back(view_cmd.substr(start_pos, view_cmd.size() - start_pos)); start_pos = end_pos; } } } else { // just a view command without parameters to be passed view_name = view_cmd; view_parms.push_back(view_name); } view_parms.push_back(file_name); char** exec_parms = new char*[view_parms.size() + 1]; char** temp_pp = exec_parms; std::vector<std::string>::const_iterator iter; for (iter = view_parms.begin(); iter != view_parms.end(); ++iter, ++temp_pp) { *temp_pp = new char[iter->size() + 1]; std::strcpy(*temp_pp, iter->c_str()); } *temp_pp = 0; char* prog_name = new char[view_name.size() + 1]; std::strcpy(prog_name, view_name.c_str()); return std::pair<const char*, char* const*>(prog_name, exec_parms);}void SocketListDialog::view_file(void) { Gtk::TreeModel::iterator row_iter = tree_view.get_selection()->get_selected(); bool is_ps_view_cmd_empty; { // lock the Prog_config object to stop it being accessed in // FaxListDialog::get_ps_viewer_parms() while we are accessing it here // (this is ultra cautious as it is only copied/checked for emptiness // there) Glib::Mutex::Lock lock(*prog_config.mutex_p); is_ps_view_cmd_empty = prog_config.ps_view_cmd.empty(); } if (row_iter && !is_ps_view_cmd_empty) { const std::string file_name((*row_iter)[model_columns.fax_filename]); // get the arguments for the exec() call below (because this is a // multi-threaded program, we must do this before fork()ing because // we use functions to get the arguments which are not async-signal-safe) std::pair<const char*, char* const*> view_file_parms(get_view_file_parms(file_name)); if (view_file_parms.first) { // this will be 0 if get_view_file_parms() // threw a Glib::ConvertError) pid_t pid = fork(); if (pid == -1) { write_error("Fork error - exiting\n"); std::exit(FORK_ERROR); } if (!pid) { // child process - as soon as everything is set up we are going to do an exec() connect_to_stderr(); execvp(view_file_parms.first, view_file_parms.second); // if we reached this point, then the execvp() call must have failed // report error and end process - use _exit() and not exit() write_error("Can't find the postscript viewer program - please check your installation\n" "and the PATH environmental variable\n"); _exit(0); } // end of view program process // release the memory allocated on the heap for // the redundant view_file_parms // we are in the main parent process here - no worries about // only being able to use async-signal-safe functions delete_parms(view_file_parms); } }}void SocketListDialog::delete_parms(std::pair<const char*, char* const*> parms_pair) { delete[] parms_pair.first; char* const* temp_pp = parms_pair.second; for(; *temp_pp != 0; ++temp_pp) { delete[] *temp_pp; } delete[] parms_pair.second;}void SocketListDialog::remove_file_prompt(void) { Gtk::TreeModel::iterator row_iter = tree_view.get_selection()->get_selected(); if (row_iter) { Glib::ustring msg(gettext("Remove ")); msg += (*row_iter)[model_columns.fax_label] + gettext(" from the list?"); PromptDialog* dialog_p = new PromptDialog(msg, gettext("Remove queued fax"), standard_size, *this); dialog_p->accepted.connect(sigc::mem_fun(*this, &SocketListDialog::remove_file)); // there is no memory leak -- the memory will be deleted when PromptDialog closes }}void SocketListDialog::remove_file(void) { Gtk::TreeModel::iterator row_iter = tree_view.get_selection()->get_selected(); if (row_iter) { remove_from_socket_server_filelist((*row_iter)[model_columns.fax_filename]); // the last call will cause the Socket_server object to invoke // Socket_server::Glib::Dispatcher::filelist_changed_notify() which // will in turn cause the MainWindow object to invoke // set_socket_list_rows() above and so refresh the socket file // list. The server object will also clean up by deleting the temporary // file it created. We do not need to do anything else here. }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -