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