// 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 3 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, see http://www.gnu.org/licenses/. #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 #include using namespace sgpem; void GuiBuilder::on_edit_preferences_activate() { PreferencesEditor(); // Will run the dialog inside the constructor. } void GuiBuilder::on_simulation_jump_to_clicked() { // 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_ui = Gtk::Builder::create_from_file(UIDIR "/jump-to-dialog.ui"); JumpToDialog* jump_to_dialog = NULL; jump_to_dialog_ui->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(); ask_save(); sim.stop(); history.clear(); set_filename(); } void GuiBuilder::on_file_open_activate() { if (!_filename.empty()) // Please test the following line extensively: open_file (Glib::path_get_dirname(_filename)); else open_file (); } void GuiBuilder::on_file_open_example_activate() { open_file (EXAMPLESDIR); } void GuiBuilder::open_file(const std::string& basedir) { ask_save(); 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()); dialog.set_current_folder (basedir); //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) { set_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) { Gtk::MessageDialog error(get_initial_window(), _("No serializer available.\nThere's no registered serializer. Please check the loaded plugins."), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); error.run(); msg = _("ERROR: No registered serializer available"); } catch (SerializerError e) { Gtk::MessageDialog error(get_initial_window(), e.what(), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); error.run(); msg = _("ERROR: ") + Glib::ustring(e.what()); set_filename(); } 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) { Gtk::MessageDialog error(get_initial_window(), _("No serializer available.\nThere's no registered serializer. Please check the loaded plugins."), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); error.run(); msg = _("ERROR: No registered serializer available"); } catch (SerializerError e) { Gtk::MessageDialog error(get_initial_window(), e.what(), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); error.run(); 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) { std::string 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; set_filename(filename); serializer.save_snapshot(_filename, history); msg = _("File: ") + _filename + _(" saved."); } // end - if(result==Gtk::RESPONSE_OK) } catch (std::out_of_range e) { Gtk::MessageDialog error(get_initial_window(), _("No serializer available.\nThere's no registered serializer. Please check the loaded plugins."), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); error.run(); msg = _("ERROR: No registered serializer available"); } catch (SerializerError e) { Gtk::MessageDialog error(get_initial_window(), e.what(), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); error.run(); msg = _("ERROR: ") + Glib::ustring(e.what()); set_filename(); } 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() { using namespace Gtk; using Glib::RefPtr; RefPtr uimanager = RefPtr::cast_dynamic (_refXml->get_object("UIManager")); CheckMenuItem* continuous_mode = NULL; continuous_mode = dynamic_cast(uimanager->get_widget ("/MenuBar/Action.Simulation/Action.Simulation.ContinuousMode")); g_assert (continuous_mode != NULL); 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); } void GuiBuilder::ask_save() { History& history = Simulation::get_instance().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); want_to_save.set_default_response(Gtk::RESPONSE_YES); if(want_to_save.run() == Gtk::RESPONSE_YES) on_file_save_activate(); } } void GuiBuilder::set_filename(const std::string& filename) { static const Glib::ustring default_title = get_initial_window().get_title(); Glib::ustring title; _filename = filename; if(!_filename.empty()) title = Glib::path_get_basename(_filename) + " - "; title += default_title; get_initial_window().set_title(title); } GuiBuilder::GuiBuilder(const std::string& uifile) : _refXml(Gtk::Builder::create_from_file(uifile)), _controller(Simulation::get_instance(), _refXml), _holt_container(Simulation::get_instance()), _show_threads(true) { using namespace Gtk; using Glib::RefPtr; Window& main_window = get_initial_window(); main_window.signal_delete_event().connect(sigc::bind_return(sigc::hide(sigc::mem_fun(*this, &GuiBuilder::ask_save)), false)); // ---------------- Menu items ------------------ // Note: the Play, Pause and Stop menu items are already managed by sgpem::SimulationController. // file new dialog RefPtr::cast_dynamic (_refXml->get_object("Action.File.New")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_new_activate)); // file open dialog RefPtr::cast_dynamic (_refXml->get_object("Action.File.Open")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_open_activate)); // file open dialog for examples RefPtr::cast_dynamic (_refXml->get_object("Action.File.OpenExample")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_open_example_activate)); // file save dialog RefPtr::cast_dynamic (_refXml->get_object("Action.File.Save")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_save_activate)); // file save dialog RefPtr::cast_dynamic (_refXml->get_object("Action.File.SaveAs")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_file_saveas_activate)); RefPtr file_quit = RefPtr::cast_dynamic (_refXml->get_object("Action.File.Quit")); file_quit->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::ask_save)); file_quit->signal_activate().connect(sigc::ptr_fun(&Main::quit)); // preferences dialog RefPtr::cast_dynamic (_refXml->get_object("Action.Edit.Preferences")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_edit_preferences_activate)); // enable/disable show threads on widgets RefPtr::cast_dynamic (_refXml->get_object("Action.View.ShowThreads")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_view_show_threads_activate)); // show/hide holt graph window RefPtr::cast_dynamic (_refXml->get_object("Action.View.ShowHoltGraph")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_view_show_holt_graph_activate)); // show/hide statistics window RefPtr::cast_dynamic (_refXml->get_object("Action.View.ShowStatistics")) ->signal_activate().connect(sigc::mem_fun(*this, &GuiBuilder::on_view_show_statistics_activate)); RefPtr::cast_dynamic (_refXml->get_object("Action.Simulation.ContinuousMode")) ->signal_activate().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 AboutDialog* about_dialog = NULL; _refXml->get_widget("AboutDialog", about_dialog); RefPtr::cast_dynamic (_refXml->get_object("Action.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(UIDIR "/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)); // 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; }