// src/startgui.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 "configure_policy_dialog.hh" #include "gui_builder.hh" #include "graphical_preferences_editor.hh" #include "schedulables_tree_widget.hh" #include "simulation_widget.hh" #include "resources_widget.hh" #include "backend/cpu_policy_exception.hh" #include "backend/malformed_policy_exception.hh" #include "backend/null_policy_exception.hh" #include "backend/user_interrupt_exception.hh" #include "backend/cpu_policies_gatekeeper.hh" #include "backend/cpu_policy.hh" #include "backend/cpu_policy_manager.hh" #include "backend/resource_policies_gatekeeper.hh" #include "backend/resource_policy_manager.hh" #include "backend/resource_policy.hh" #include "backend/history.hh" #include "backend/policy_parameters.hh" #include "backend/simulation.hh" #include "backend/serializers_gatekeeper.hh" #include "backend/serializer.hh" #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? } 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); History& history = Simulation::get_instance().get_history(); // open file dialog... Gtk::FileChooserDialog dialog("Please choose a file", Gtk::FILE_CHOOSER_ACTION_OPEN); 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::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(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) { Glib::ustring filename = dialog.get_filename(); serializer.restore_snapshot(filename, history); msg = "File: " + filename + " loaded."; } // end - if(result==Gtk::RESPONSE_OK) } catch (std::out_of_range e) { msg = _("ERROR: No registered serializer available"); } catch (SerializerError e) { 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() { // _simulation_widget->change_scaling_mode(); } 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("Sgpem files"); filter_sgpem.add_pattern("*.xgp"); 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) { serializer.save_snapshot(dialog.get_filename(), history); msg = "File: " + dialog.get_filename() + " saved."; } // end - if(result==Gtk::RESPONSE_OK) } catch (std::out_of_range e) { msg = _("ERROR: No registered serializer available"); } catch (SerializerError e) { 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; CPUPolicy* policy = Simulation::get_instance().get_policy(); if(policy == NULL) { MessageDialog warn(_("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(), params); config_dialog.run(); } void GuiBuilder::on_configure_resource_policy() { using namespace Gtk; ResourcePolicy* policy = Simulation::get_instance().get_resource_policy(); if(policy == NULL) { MessageDialog warn(_("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(), params); config_dialog.run(); } GuiBuilder::GuiBuilder(const std::string& gladefile) : _refXml(Xml::create(gladefile)), _controller(Simulation::get_instance(), _refXml) { using namespace Gtk; //Window& main_window = get_initial_window(); // 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)); // Connect extra signals (decide where to do this... // here -- ugly -- derive widgets and then use // Glade::Xml::get_widget_derived -- better --) 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)); // ---------------- Toolbar buttons ------------------ // Note: the Play, Pause and Stop buttons are already managed by sgpem::SimulationController. // 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)); // 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)); // --------------------------------------------------- // 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); _simulation_widget = new SimulationWidget(Simulation::get_instance()); SimulationWidget* simulation_widget = manage(_simulation_widget); simulation_window->add(*simulation_widget); simulation_widget->show(); // ** FIXME: just to try; a proper way to select a policy has to be installed Simulation& sim = Simulation::get_instance(); CPUPoliciesGatekeeper& pgk = CPUPoliciesGatekeeper::get_instance(); CPUPolicy* policy = pgk.get_registered()[0]->get_avail_policies()[1]; // RoundRobin at the moment of writing std::cout << "Selected policy : " << policy->get_name() << std::endl; sim.set_policy(policy); // FIXME: dedicate a function to set resource policy // which includes the following default one ResourcePolicyManager & rpm = *ResourcePoliciesGatekeeper::get_instance().get_registered().at(0); Simulation::get_instance().set_resource_policy(rpm.get_avail_policies().at(0)); // end of include } 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; } // --------------------------------- SimulationController::SimulationController(Simulation& simulation, Glib::RefPtr refXml) : _sim(simulation), _break_requested(false) { using namespace Gtk; _sim.attach(*this); // Start, pause and stop simulation from the toolbar // TODO: can we use action groups instead of this? refXml->get_widget("ToolBar.Play", _toolbt_start); refXml->get_widget("ToolBar.Pause", _toolbt_pause); refXml->get_widget("ToolBar.Stop", _toolbt_stop); _toolbt_start->signal_clicked().connect(sigc::mem_fun(*this, &SimulationController::on_simulation_run)); _toolbt_pause->signal_clicked().connect(sigc::mem_fun(*this, &SimulationController::on_simulation_pause)); _toolbt_stop->signal_clicked().connect(sigc::mem_fun(*this, &SimulationController::on_simulation_stop)); } SimulationController::~SimulationController() { _sim.detach(*this); } void SimulationController::on_simulation_run() { // Sensitivities _toolbt_start->set_sensitive(false); _toolbt_pause->set_sensitive(true); _toolbt_stop->set_sensitive(true); _break_requested = false; // Used instead of simply calling "_sim.run()" to // have exception handling only in one place: run_simulation_adaptor(); } void SimulationController::on_simulation_pause() { // Sensitivities _toolbt_start->set_sensitive(true); _toolbt_pause->set_sensitive(false); _toolbt_stop->set_sensitive(true); _break_requested = true; _sim.pause(); } void SimulationController::on_simulation_stop() { // Sensitivities _toolbt_start->set_sensitive(true); _toolbt_pause->set_sensitive(false); _toolbt_stop->set_sensitive(false); _break_requested = true; _sim.stop(); } void SimulationController::update(const Simulation& simulation) { #ifndef NDEBUG std::cerr << "SimulationController::update(), simulation state == " << std::hex << simulation.get_state() << std::endl; #endif if(_break_requested) return; switch(simulation.get_state()) { case Simulation::state_stopped: on_simulation_stop(); return; case Simulation::state_paused: on_simulation_pause(); return; case Simulation::state_running: // Go on with the rest of the method... break; } // We should never enter here, if the code is correct: // a step by step simulation should always be in paused // or stopped state after performing a single step assert(simulation.get_mode() != Simulation::mode_step_by_step); switch(simulation.get_mode()) { case Simulation::mode_continuous: { int timeout = GlobalPreferences::get_instance().get_speed(); Glib::signal_timeout().connect(sigc::mem_fun(*this, &SimulationController::run_simulation_adaptor), timeout); } break; default: // Never gets here. break; } } bool SimulationController::run_simulation_adaptor() { using Gtk::MessageDialog; using namespace Glib; if(!_break_requested) try { _sim.run(); } catch(const UserInterruptException& uie) { // Show the user a dialog MessageDialog diag(_("The selected user CPU policy stopped before returning:\n") + Markup::escape_text(uie.what()), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); diag.run(); } catch(const MalformedPolicyException& mpe) { // Show user a dialog MessageDialog diag(_("The selected user CPU policy was malformed and didn't run:\n") + Markup::escape_text(mpe.what()), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); diag.run(); try { // Deactivate the policy _sim.set_policy(NULL); } catch(const CPUPolicyException& cpe) { // Fatal error. We should never get here. std::cerr << _(" [EE] Fatal error. Impossible to deactivate the policy in ") << __FILE__ << ":" << __LINE__ << std::endl << _(" [EE] ") << cpe.what() << std::endl; ; abort(); } } catch(const NullPolicyException& npe) { MessageDialog diag(_("No active policy selected:\n") + Markup::escape_text(npe.what()), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); diag.run(); } catch(const CPUPolicyException& cpe) { MessageDialog diag(_("Unexpected error:\n") + Markup::escape_text(cpe.what()), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); diag.run(); } return false; }