538 lines
16 KiB
C++
538 lines
16 KiB
C++
// 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 <gdkmm/pixbuf.h>
|
|
#include <glibmm/markup.h>
|
|
#include <glibmm/timer.h>
|
|
#include <glibmm/ustring.h>
|
|
#include <gtkmm/aboutdialog.h>
|
|
#include <gtkmm/messagedialog.h>
|
|
#include <gtkmm/menutoolbutton.h>
|
|
#include <gtkmm/filechooserdialog.h>
|
|
#include <gtkmm/main.h>
|
|
#include <gtkmm/menuitem.h>
|
|
#include <gtkmm/scrolledwindow.h>
|
|
#include <gtkmm/statusbar.h>
|
|
#include <gtkmm/stock.h>
|
|
|
|
#include <cassert>
|
|
#include <iostream>
|
|
|
|
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<Serializer*> 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<Serializer*>::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<Serializer*> 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(_("<b>No CPU policy is currently selected.</b>\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(_("<b>No CPU policy is currently selected.</b>\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<Xml> 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(_("<b>The selected user CPU policy stopped before returning:</b>\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(_("<b>The selected user CPU policy was malformed and didn't run:</b>\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(_("<b>No active policy selected:</b>\n") + Markup::escape_text(npe.what()),
|
|
true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
|
diag.run();
|
|
|
|
}
|
|
catch(const CPUPolicyException& cpe)
|
|
{
|
|
MessageDialog diag(_("<b>Unexpected error</b>:\n") + Markup::escape_text(cpe.what()),
|
|
true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
|
diag.run();
|
|
}
|
|
|
|
return false;
|
|
}
|