worldinfo_viewer.cpp

00001
00002 /***************************************************************************
00003  *  worldinfo_viewer.cpp -  World Info Viewer
00004  *
00005  *  Created: Wed April 09 20:13:08 2008
00006  *  Copyright  2008  Daniel Beck
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022
00023 #include "worldinfo_viewer.h"
00024 #include "field_view.h"
00025
00026 #include <worldinfo_utils/data_container.h>
00027 #include <blackboard/remote.h>
00028 #include <interfaces/BatteryInterface.h>
00029
00030 #include <vector>
00031 #include <map>
00032 #include <string>
00033 #include <cstdio>
00034 #include <cstring>
00035
00036 using namespace std;
00037 using namespace fawkes;
00038
00039 
00040 /** @class WorldInfoViewer <tools/worldinfo_viewer/worldinfo_viewer.h>
00041  * Main class of the WorldInfoViewer application.
00042  * @author Daniel Beck
00043  */
00044
00045 
00046 /** Constructor.
00047  * @param ref_xml reference to the Glade XML file
00048  * @param data_container pointer to the central instance of the
00049  * WorldInfoDataContainer
00050  */
00051 WorldInfoViewer::WorldInfoViewer( Glib::RefPtr<Gnome::Glade::Xml> ref_xml,
00052                                   WorldInfoDataContainer* data_container )
00053 {
00054   m_wnd_main   = dynamic_cast<Gtk::Window*>( get_widget(ref_xml, "wndMain") );
00055   m_vbx_field  = dynamic_cast<Gtk::VBox*>( get_widget(ref_xml, "vbxField") );
00056   m_trv_robots = dynamic_cast<Gtk::TreeView*>( get_widget(ref_xml, "trvRobots") );
00057   m_stb_status = dynamic_cast<Gtk::Statusbar*>( get_widget(ref_xml, "stbStatus") );
00058
00059   m_field_view = new FieldView( data_container, true, true, false );
00060   m_vbx_field->pack_start( *m_field_view );
00061   m_field_view->show();
00062
00063   m_robots_list = Gtk::ListStore::create( m_robot_record );
00064   m_trv_robots->set_model( m_robots_list );
00065   m_trv_robots->append_column( "Name", m_robot_record.hostname );
00066   m_trv_robots->append_column_editable( "Pose", m_robot_record.show_pose );
00067   m_trv_robots->append_column_editable( "Ball", m_robot_record.show_ball );
00068   m_trv_robots->append_column_editable( "Opponents", m_robot_record.show_opponents );
00069
00070   Gtk::CellRendererToggle* renderer;
00071   renderer = dynamic_cast< Gtk::CellRendererToggle* >( m_trv_robots->get_column_cell_renderer(1) );
00072   renderer->signal_toggled().connect( sigc::mem_fun( *this,
00073                                                      &WorldInfoViewer::on_show_pose_toggled ) );
00074   renderer = dynamic_cast< Gtk::CellRendererToggle* >( m_trv_robots->get_column_cell_renderer(2) );
00075   renderer->signal_toggled().connect( sigc::mem_fun( *this,
00076                                                      &WorldInfoViewer::on_show_ball_toggled ) );
00077   renderer = dynamic_cast< Gtk::CellRendererToggle* >( m_trv_robots->get_column_cell_renderer(3) );
00078   renderer->signal_toggled().connect( sigc::mem_fun( *this,
00079                                                      &WorldInfoViewer::on_show_opponents_toggled ) );
00080
00081   m_data_container = data_container;
00082
00083   m_stb_message_id = m_stb_status->push( "No game state information available." );
00084
00085   // create timer
00086   sigc::connection conn =
00087     Glib::signal_timeout().connect( sigc::mem_fun( *this, &WorldInfoViewer::update ), 200 );
00088 }
00089
00090 
00091 /** Destructor. */
00092 WorldInfoViewer::~WorldInfoViewer()
00093 {
00094   delete m_field_view;
00095   delete m_wnd_main;
00096 }
00097
00098 
00099 /** Obtain the main window of the application.
00100  * @return reference to the main window
00101  */
00102 Gtk::Window&
00103 WorldInfoViewer::get_window() const
00104 {
00105   return *m_wnd_main;
00106 }
00107
00108 Gtk::Widget*
00109 WorldInfoViewer::get_widget(Glib::RefPtr<Gnome::Glade::Xml> ref_xml,
00110                             const char* widget_name) const
00111 {
00112   Gtk::Widget* widget;
00113   ref_xml->get_widget(widget_name, widget);
00114   if ( !widget )
00115   {
00116     char* err_str;
00117     if (asprintf(&err_str, "Couldn't find widget %s", widget_name) != -1)
00118     {
00119       throw std::runtime_error(err_str);
00120       free(err_str);
00121     }
00122     else
00123     { throw std::runtime_error("Getting widget failed"); }
00124   }
00125
00126   return widget;
00127 }
00128
00129 
00130 /** Update the GUI */
00131 bool
00132 WorldInfoViewer::update()
00133 {
00134   bool robot_removed = false;
00135
00136   if ( m_data_container->check_timeout() )
00137   {
00138     robot_removed = true;
00139     list<string> timedout_hosts = m_data_container->get_timedout_hosts();
00140
00141 #ifdef DEBUG_PRINT
00142     printf( "Removing %zu timed out host.\n", timedout_hosts.size() );
00143 #endif /* DEBUG_PRINT */
00144
00145     // remove timed out hosts
00146     for ( list<string>::iterator hit = timedout_hosts.begin();
00147           hit != timedout_hosts.end();
00148           ++hit )
00149     {
00150       m_field_view->remove_host( Glib::ustring( *hit ) );
00151
00152       Gtk::TreeModel::Children children = m_robots_list->children();
00153       Gtk::TreeModel::iterator cit = children.begin();
00154       while ( cit != children.end() )
00155       {
00156         Gtk::TreeModel::Row row = *cit;
00157         if ( Glib::ustring( *hit ) == row[ m_robot_record.fqdn ] )
00158         { cit = m_robots_list->erase( cit ); }
00159         else
00160         { ++cit; }
00161       }
00162     }
00163   }
00164
00165   // return if no new data is available
00166   if ( !m_data_container->new_data_available() )
00167   {
00168     if ( robot_removed )
00169     { m_field_view->queue_draw(); }
00170     return true;
00171   }
00172
00173   list<string> hosts = m_data_container->get_hosts();
00174
00175   // check that all hosts are in the treeview
00176   for ( list<string>::iterator hit = hosts.begin();
00177         hit != hosts.end();
00178         ++hit )
00179   {
00180     bool found = false;
00181
00182     Gtk::TreeModel::Children children = m_robots_list->children();
00183     for ( Gtk::TreeModel::iterator i = children.begin();
00184           i != children.end();
00185           ++i )
00186     {
00187       Gtk::TreeModel::Row row = *i;
00188       if ( Glib::ustring( *hit ) == row[ m_robot_record.fqdn ] )
00189       {
00190         found = true;
00191         break;
00192       }
00193     }
00194
00195     if ( !found )
00196     {
00197       char* fqdn;
00198       char* hostname;
00199       char delim ='.';
00200       Glib::ustring fqdn_str = Glib::ustring( *hit );
00201
00202       fqdn = strdup( hit->c_str() );
00203       hostname = strtok( fqdn, &delim );
00204       int i = atoi( hostname );
00205
00206       Gtk::TreeModel::Row row = *m_robots_list->append();
00207
00208       if ( 0 == i ) /* fqdn is not an IP address */
00209       { row[ m_robot_record.hostname ] = Glib::ustring( hostname ); }
00210       else
00211       { row[ m_robot_record.hostname ] = fqdn_str; }
00212       row[ m_robot_record.fqdn ]           = fqdn_str;
00213       row[ m_robot_record.show_pose ]      = m_field_view->toggle_show_pose( fqdn_str );
00214       row[ m_robot_record.show_ball ]      = m_field_view->toggle_show_ball( fqdn_str );
00215       row[ m_robot_record.show_opponents ] = m_field_view->toggle_show_opponents( fqdn_str );
00216
00217       free(fqdn);
00218     }
00219   }
00220
00221   m_field_view->queue_draw();
00222
00223   return true;
00224 }
00225 
00226 /** Call this method whenever the game state changes. */
00227 void
00228 WorldInfoViewer::gamestate_changed()
00229 {
00230   char* status_string;
00231   if ( asprintf( &status_string,
00232                  "Team color: %s  Goal color: %s  Mode: %s  Score: %d:%d  Half: %s",
00233                  m_data_container->get_own_team_color_string().c_str(),
00234                  m_data_container->get_own_goal_color_string().c_str(),
00235                  m_data_container->get_game_state_string().c_str(),
00236                  m_data_container->get_own_score(),
00237                  m_data_container->get_other_score(),
00238                  m_data_container->get_half_string().c_str() ) != -1 )
00239   {
00240     m_stb_status->remove_message(m_stb_message_id);
00241     m_stb_message_id = m_stb_status->push( Glib::ustring(status_string) );
00242
00243     free(status_string);
00244   }
00245 }
00246
00247 void
00248 WorldInfoViewer::on_show_pose_toggled( const Glib::ustring& path )
00249 {
00250   Gtk::TreeModel::Row row = *m_robots_list->get_iter( path );
00251   Glib::ustring fqdn = row[ m_robot_record.fqdn ];
00252
00253   row[ m_robot_record.show_pose ] = m_field_view->toggle_show_pose( fqdn );
00254
00255   m_field_view->queue_draw();
00256 }
00257
00258 void
00259 WorldInfoViewer::on_show_ball_toggled( const Glib::ustring& path )
00260 {
00261   Gtk::TreeModel::Row row = *m_robots_list->get_iter( path );
00262   Glib::ustring fqdn = row[ m_robot_record.fqdn ];
00263
00264   row[ m_robot_record.show_ball ] = m_field_view->toggle_show_ball( fqdn );
00265
00266   m_field_view->queue_draw();
00267 }
00268
00269 void
00270 WorldInfoViewer::on_show_opponents_toggled( const Glib::ustring& path )
00271 {
00272   Gtk::TreeModel::Row row = *m_robots_list->get_iter( path );
00273   Glib::ustring fqdn = row[ m_robot_record.fqdn ];
00274
00275   row[ m_robot_record.show_opponents ] = m_field_view->toggle_show_opponents( fqdn );
00276
00277   m_field_view->queue_draw();
00278 }