// src/gui_builder.cc - Copyright 2005, 2006, University // of Padova, dept. of Pure and Applied // Mathematics // // This file is part of SGPEMv2. // // This is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // SGPEMv2 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with SGPEMv2; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "config.h" #include "gettext.h" #include "gui_builder.hh" #include "configure_policy_dialog.hh" #include "graphical_preferences_editor.hh" #include "holt_container_window.hh" #include "holt_widget.hh" #include "ready_queue_widget.hh" #include "schedulables_tree_widget.hh" #include "schedulables_statistics_widget.hh" #include "simulation_widget.hh" #include "resources_widget.hh" #include "jump_to_dialog.hh" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace sgpem; using Gnome::Glade::Xml; void GuiBuilder::on_edit_preferences_activate() { new PreferencesEditor(); //FIXME: are we leaking this way? (definitely yes. use // a refptr member data?) } void GuiBuilder::on_simulation_jump_to_clicked() { using Gnome::Glade::Xml; // JumpTo spinbox Gtk::SpinButton* jump_to_spin; _refXml->get_widget("BottomHBox.JumpToSpin", jump_to_spin); int target_instant = jump_to_spin->get_value_as_int(); assert(target_instant > 0); Glib::RefPtr jump_to_dialog_glade = Xml::create(GLADEDIR "/jump-to-dialog.glade"); JumpToDialog* jump_to_dialog = NULL; jump_to_dialog_glade->get_widget_derived("JumpToDialog", jump_to_dialog); jump_to_dialog->set_transient_for(get_initial_window()); jump_to_dialog->set_target_instant(target_instant); jump_to_dialog->start(); } void GuiBuilder::on_view_show_threads_activate() { _show_threads = !_show_threads; _simulation_widget->set_show_threads(_show_threads); _simulation_widget->resize_redraw(); _holt_container.get_holt_widget().set_show_threads(_show_threads); _holt_container.get_holt_widget().update(Simulation::get_instance().get_history()); } void GuiBuilder::on_view_show_holt_graph_activate() { if(_holt_container.is_visible()) { _holt_container.hide(); } else { _holt_container.show(); } } void GuiBuilder::on_view_show_statistics_activate() { if(_statistics_container.get_main_window()->is_visible()) { _statistics_container.get_main_window()->hide(); } else { _statistics_container.get_main_window()->show(); } } void GuiBuilder::on_file_new_activate() { Simulation& sim = Simulation::get_instance(); History& history = sim.get_history(); const Environment& env = history.get_environment_at(0); if(!(_filename.empty() && env.get_processes().empty() && env.get_resources().empty())) { Gtk::MessageDialog want_to_save(get_initial_window(), _("Want to save?\nYou'll lose your changes if you don't."), true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); if(want_to_save.run() == Gtk::RESPONSE_YES) on_file_save_activate(); } sim.stop(); history.clear(); _filename = ""; } void GuiBuilder::on_file_open_activate() { Glib::ustring msg; try { std::vector serializers = SerializersGatekeeper::get_instance().get_registered(); // FIXME using the first serializer available, this // will need to be changed when multiple serializers will // be made available Serializer& serializer = *serializers.at(0); Simulation& sim = Simulation::get_instance(); // open file dialog... Gtk::FileChooserDialog dialog("Please choose a file", Gtk::FILE_CHOOSER_ACTION_OPEN); dialog.set_transient_for(get_initial_window()); if(!_filename.empty()) // Please test the following line extensively: dialog.set_current_folder(Glib::path_get_dirname(_filename)); //Add response buttons the the dialog: dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); //Add filters, so that only certain file types can be selected: for(std::vector::const_iterator iter=serializers.begin(); iter!=serializers.end(); iter++) { Serializer* ser = *iter; Gtk::FileFilter filter_sgpem; filter_sgpem.set_name(ser->get_filename_description()); filter_sgpem.add_pattern(Glib::ustring("*.") + ser->get_filename_extension()); dialog.add_filter(filter_sgpem); } Gtk::FileFilter filter_any; filter_any.set_name("Any files"); filter_any.add_pattern("*"); dialog.add_filter(filter_any); //Show the dialog and wait for a user response: int result = dialog.run(); if(result==Gtk::RESPONSE_OK) { _filename = dialog.get_filename(); sim.stop(); // It would work anyhow, but it'd look strange History& history = sim.get_history(); serializer.restore_snapshot(_filename, history); msg = "File: " + _filename + " loaded."; } // end - if(result==Gtk::RESPONSE_OK) } catch (std::out_of_range e) { // FIXME: this should be an error dialog msg = _("ERROR: No registered serializer available"); } catch (SerializerError e) { // FIXME: this should be an error dialog msg = _("ERROR: ") + Glib::ustring(e.what()); } if(!msg.empty()) { Gtk::Statusbar* sbar = _refXml->get_widget("MainStatusBar", sbar); sbar->push(msg); } } void GuiBuilder::on_file_save_activate() { if(_filename.empty()) { on_file_saveas_activate(); return; } // else: Glib::ustring msg; try { std::vector serializers = SerializersGatekeeper::get_instance().get_registered(); // FIXME using the first serializer available, this // will need to be changed when multiple serializers will // be made available Serializer& serializer = *serializers.at(0); History& history = Simulation::get_instance().get_history(); serializer.save_snapshot(_filename, history); msg = "File: " + _filename + " saved."; } catch (std::out_of_range e) { // FIXME: this should be an error dialog msg = _("ERROR: No registered serializer available"); } catch (SerializerError e) { // FIXME: this should be an error dialog msg = _("ERROR: ") + Glib::ustring(e.what()); } if(!msg.empty()) { Gtk::Statusbar* sbar = _refXml->get_widget("MainStatusBar", sbar); sbar->push(msg); } } void GuiBuilder::on_file_saveas_activate() { Glib::ustring msg; try { std::vector serializers = SerializersGatekeeper::get_instance().get_registered(); // FIXME using the first serializer available, this // will need to be changed when multiple serializers will // be made available Serializer& serializer = *serializers.at(0); History& history = Simulation::get_instance().get_history(); // open file dialog... Gtk::FileChooserDialog dialog("Please choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE); dialog.set_transient_for(get_initial_window()); //Add response buttons the the dialog: dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); //Add filters, so that only certain file types can be selected: Gtk::FileFilter filter_sgpem; filter_sgpem.set_name(serializer.get_filename_description()); filter_sgpem.add_pattern(Glib::ustring("*.") + serializer.get_filename_extension()); dialog.add_filter(filter_sgpem); Gtk::FileFilter filter_any; filter_any.set_name("Any files"); filter_any.add_pattern("*"); dialog.add_filter(filter_any); //Show the dialog and wait for a user response: int result = dialog.run(); if(result==Gtk::RESPONSE_OK) { _filename = dialog.get_filename(); // Append standard extension if none (or a different one) is provided std::string ext = std::string(".") + serializer.get_filename_extension(); if(_filename.size() < ext.size() || _filename.substr(_filename.size() - ext.size()) != ext) _filename += ext; serializer.save_snapshot(_filename, history); msg = "File: " + _filename + " saved."; } // end - if(result==Gtk::RESPONSE_OK) } catch (std::out_of_range e) { // FIXME: This should be an error dialog: msg = _("ERROR: No registered serializer available"); } catch (SerializerError e) { // FIXME: This should be an error dialog: msg = _("ERROR: ") + Glib::ustring(e.what()); } if(!msg.empty()) { Gtk::Statusbar* sbar = _refXml->get_widget("MainStatusBar", sbar); sbar->push(msg); } } void GuiBuilder::on_configure_cpu_policy() { using namespace Gtk; Simulation& sim = Simulation::get_instance(); CPUPolicy* policy = sim.get_policy(); if(policy == NULL) { MessageDialog warn(get_initial_window(), _("No CPU policy is currently selected.\nPlease choose one before trying to configure it."), true, MESSAGE_WARNING, BUTTONS_OK, true); warn.run(); } PolicyParameters& params = policy->get_parameters(); ConfigurePolicyDialog config_dialog(_("Configuring CPU Policy ") + policy->get_name(), get_initial_window(), policy->get_description(), params); if(config_dialog.run() == RESPONSE_OK) { sim.stop(); sim.get_history().reset(); } } void GuiBuilder::on_configure_resource_policy() { using namespace Gtk; Simulation& sim = Simulation::get_instance(); ResourcePolicy* policy = sim.get_resource_policy(); if(policy == NULL) { MessageDialog warn(get_initial_window(), _("No CPU policy is currently selected.\nPlease choose one before trying to configure it."), true, MESSAGE_WARNING, BUTTONS_OK, true); warn.run(); return; } PolicyParameters& params = policy->get_parameters(); ConfigurePolicyDialog config_dialog(_("Configuring CPU Policy ") + policy->get_name(), get_initial_window(), policy->get_description(), params); if(config_dialog.run() == RESPONSE_OK) { sim.stop(); sim.get_history().reset(); } } void GuiBuilder::populate_with_cpu_policies(Gtk::Menu& menu) { using namespace Gtk; // NOTE: Please note that this code relies on the fact that a given // policy never "disappears" at runtime. A *GatekeeperObserver should // be needed to avoid dangling pointers if this behaviour changes. typedef std::vector Managers; typedef std::vector Policies; RadioButtonGroup group; CPUPoliciesGatekeeper& pgk = CPUPoliciesGatekeeper::get_instance(); const Managers& managers = pgk.get_registered(); for(Iseq m_it = iseq(managers); m_it; ++m_it) { const Policies& policies = (*m_it)->get_avail_policies(); for(Iseq p_it = iseq(policies); p_it; ++p_it) { RadioMenuItem& menuitem = *manage(new RadioMenuItem(group, (*p_it)->get_name())); menuitem.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &GuiBuilder::on_selected_cpu_policy), *p_it)); menu.append(menuitem); menuitem.show(); } } // Activate the first policy available if possible Menu::MenuList& items = menu.items(); if(!items.empty()) menu.activate_item(items.front()); } void GuiBuilder::on_selected_cpu_policy(CPUPolicy* pol) { using namespace Gtk; Statusbar* sbar; _refXml->get_widget("MainStatusBar", sbar); try { Simulation::get_instance().set_policy(pol); if(pol != NULL) { sbar->push(_("Selected CPU policy ") + pol->get_name()); return; } } catch(CPUPolicyException& e) { Simulation::get_instance().set_policy(NULL); MessageDialog error(get_initial_window(), Glib::ustring(_("Impossible to select this CPU Policy.\n")) + e.what(), true, MESSAGE_ERROR, BUTTONS_OK, true); error.run(); } // If we got here, no policy is selected. sbar->push(_("No CPU policy selected. Please select one.")); } void GuiBuilder::populate_with_resource_policies(Gtk::Menu& menu) { using namespace Gtk; // NOTE: Please note that this code relies on the fact that a given // policy never "disappears" at runtime. A *GatekeeperObserver should // be needed to avoid dangling pointers if this behaviour changes. typedef std::vector Managers; typedef std::vector Policies; RadioButtonGroup group; ResourcePoliciesGatekeeper& pgk = ResourcePoliciesGatekeeper::get_instance(); const Managers& managers = pgk.get_registered(); for(Iseq m_it = iseq(managers); m_it; ++m_it) { const Policies& policies = (*m_it)->get_avail_policies(); for(Iseq p_it = iseq(policies); p_it; ++p_it) { RadioMenuItem& menuitem = *manage(new RadioMenuItem(group, (*p_it)->get_name())); menuitem.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &GuiBuilder::on_selected_resource_policy), *p_it)); menu.append(menuitem); menuitem.show(); } } // Activate the first policy available if possible Menu::MenuList& items = menu.items(); if(!items.empty()) menu.activate_item(items.front()); } void GuiBuilder::on_selected_resource_policy(ResourcePolicy* pol) { using namespace Gtk; Simulation::get_instance().set_resource_policy(pol); Statusbar* sbar; _refXml->get_widget("MainStatusBar", sbar); if(pol == NULL) sbar->push(_("Current resource policy deselected.")); else sbar->push(_("Selected resource policy ") + pol->get_name()); } void GuiBuilder::on_toggle_simulation_mode() { Gtk::CheckMenuItem* continuous_mode; _refXml->get_widget("MenuItem.Simulation.ContinuousMode", continuous_mode); if(continuous_mode->get_active() == true) Simulation::get_instance().set_mode(Simulation::mode_continuous); else Simulation::get_instance().set_mode(Simulation::mode_step_by_step); } GuiBuilder::GuiBuilder(const std::string& gladefile) : _refXml(Xml::create(gladefile)), _controller(Simulation::get_instance(), _refXml), _holt_container(Simulation::get_instance()), _show_threads(true) { using namespace Gtk; // ---------------- Menu items ------------------ // Note: the Play, Pause and Stop menu items are already managed by sgpem::SimulationController. // file new dialog MenuItem* file_new = NULL; _refXml->get_widget("MenuItem.File.New", file_new); file_new->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_new_activate)); // file open dialog MenuItem* file_open = NULL; _refXml->get_widget("MenuItem.File.Open", file_open); file_open->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_open_activate)); // file save dialog MenuItem* file_save = NULL; _refXml->get_widget("MenuItem.File.Save", file_save); file_save->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_save_activate)); // file save dialog MenuItem* file_saveas = NULL; _refXml->get_widget("MenuItem.File.SaveAs", file_saveas); file_saveas->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_saveas_activate)); MenuItem* file_quit = NULL; _refXml->get_widget("MenuItem.File.Quit", file_quit); file_quit->signal_activate().connect(sigc::ptr_fun(&Main::quit)); // preferences dialog MenuItem* edit_preferences; _refXml->get_widget("MenuItem.Edit.Preferences", edit_preferences); edit_preferences->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_edit_preferences_activate)); // enable/disable show threads on widgets MenuItem* show_threads; _refXml->get_widget("MenuItem.View.ShowThreads", show_threads); show_threads->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_view_show_threads_activate)); // show/hide holt graph window MenuItem* show_holt_graph; _refXml->get_widget("MenuItem.View.ShowHoltGraph", show_holt_graph); show_holt_graph->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_view_show_holt_graph_activate)); // show/hide statistics window MenuItem* show_statistics_graph; _refXml->get_widget("MenuItem.View.ShowStatistics", show_statistics_graph); show_statistics_graph->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_view_show_statistics_activate)); CheckMenuItem* continuous_mode; _refXml->get_widget("MenuItem.Simulation.ContinuousMode", continuous_mode); continuous_mode->signal_toggled().connect(sigc::mem_fun(*this, &GuiBuilder::on_toggle_simulation_mode)); // ---------------- Toolbar buttons ------------------ // Note: the Play, Pause and Stop buttons are already managed by sgpem::SimulationController. // Open file ToolButton* toolb_open; _refXml->get_widget("ToolBar.Open", toolb_open); toolb_open->signal_clicked().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_open_activate)); // Save file ToolButton* toolb_save; _refXml->get_widget("ToolBar.Save", toolb_save); toolb_save->signal_clicked().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_save_activate)); // Configure CPU Policy MenuToolButton* cpu_policies_tb_menu; _refXml->get_widget("ToolBar.PolicySelector", cpu_policies_tb_menu); cpu_policies_tb_menu->signal_clicked().connect(sigc::mem_fun(*this, &GuiBuilder::on_configure_cpu_policy)); cpu_policies_tb_menu->set_menu(*manage(new Menu())); populate_with_cpu_policies(*cpu_policies_tb_menu->get_menu()); // Configure Resource Policy MenuToolButton* res_policies_tb_menu; _refXml->get_widget("ToolBar.ResourceScheduling", res_policies_tb_menu); res_policies_tb_menu->signal_clicked().connect(sigc::mem_fun(*this, &GuiBuilder::on_configure_resource_policy)); res_policies_tb_menu->set_menu(*manage(new Menu())); populate_with_resource_policies(*res_policies_tb_menu->get_menu()); // --------------------------------------------------- // About dialog MenuItem* help_about; _refXml->get_widget("MenuItem.Help.About", help_about); AboutDialog* about_dialog = NULL; _refXml->get_widget("AboutDialog", about_dialog); help_about->signal_activate().connect(sigc::mem_fun(*about_dialog, &Window::show)); about_dialog->set_wrap_license(true); about_dialog->set_logo(Gdk::Pixbuf::create_from_file(GLADEDIR "/logo.png")); // Insert the schedulables TreeView custom widget ScrolledWindow* schedulables_sw = NULL; _refXml->get_widget("SchedulablesScrolledWindow", schedulables_sw); SchedulablesTreeWidget* scheds_tree = manage(new SchedulablesTreeWidget()); schedulables_sw->add(*scheds_tree); // we have to remember to manually show custom added widgets: scheds_tree->show(); // Resources ListView widget ResourcesWidget* resources_widget = NULL; _refXml->get_widget_derived("Resources.Tree", resources_widget); resources_widget->show(); // Main simulation widget ScrolledWindow* simulation_window = NULL; _refXml->get_widget("SimulationScrolledWindow", simulation_window); //SimulationWidget& simulation_widget = *manage(new SimulationWidget(Simulation::get_instance())); _simulation_widget = manage(new SimulationWidget(Simulation::get_instance())); simulation_window->add(*_simulation_widget); _simulation_widget->set_show_threads(_show_threads); _simulation_widget->show(); // ReadyQueue custom label widget ReadyQueueWidget& rq_widget = *manage(new ReadyQueueWidget(Simulation::get_instance().get_history())); HBox* bottomhbox; _refXml->get_widget("BottomHBox", bottomhbox); bottomhbox->pack_start(rq_widget); rq_widget.show(); // JumpTo button Button* simulation_jump_to = NULL; _refXml->get_widget("BottomHBox.JumpToButton", simulation_jump_to); simulation_jump_to->signal_clicked().connect(sigc::mem_fun(*this, &GuiBuilder::on_simulation_jump_to_clicked)); Window& main_window = get_initial_window(); // HoltGraph container window _holt_container.set_transient_for(main_window); _holt_container.get_holt_widget().set_show_threads(_show_threads); _statistics_container.get_main_window()->set_transient_for(main_window); } GuiBuilder::~GuiBuilder() {} Gtk::Window& GuiBuilder::get_initial_window() const { Gtk::Window* main_window = NULL; _refXml->get_widget("MainWindow", main_window); return *main_window; } void GuiBuilder::open_file(const std::string& filename) { // FIXME: to be written. // Debug line (erase me when done): std::cout << _("Filename to open: ") << filename << std::endl; }