Fawkes API  Fawkes Development Version
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 builder Gtk Builder
00047  * @param data_container pointer to the central instance of the
00048  * WorldInfoDataContainer
00049  */
00050 WorldInfoViewer::WorldInfoViewer(Glib::RefPtr<Gtk::Builder> builder,
00051                                  WorldInfoDataContainer* data_container )
00052 {
00053   builder->get_widget("wndMain", m_wnd_main);
00054   builder->get_widget("vbxField", m_vbx_field);
00055   builder->get_widget("trvRobots", m_trv_robots);
00056   builder->get_widget("stbStatus", m_stb_status);
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 
00108 /** Update the GUI.
00109  * @return always true
00110  */
00111 bool
00112 WorldInfoViewer::update()
00113 {
00114   bool robot_removed = false;
00115 
00116   if ( m_data_container->check_timeout() )
00117   {
00118     robot_removed = true;
00119     list<string> timedout_hosts = m_data_container->get_timedout_hosts();
00120 
00121 #ifdef DEBUG_PRINT
00122     printf( "Removing %zu timed out host.\n", timedout_hosts.size() );
00123 #endif /* DEBUG_PRINT */
00124     
00125     // remove timed out hosts
00126     for ( list<string>::iterator hit = timedout_hosts.begin();
00127           hit != timedout_hosts.end();
00128           ++hit )
00129     {
00130       m_field_view->remove_host( Glib::ustring( *hit ) );
00131 
00132       Gtk::TreeModel::Children children = m_robots_list->children();
00133       Gtk::TreeModel::iterator cit = children.begin();
00134       while ( cit != children.end() )
00135       {
00136         Gtk::TreeModel::Row row = *cit;
00137         if ( Glib::ustring( *hit ) == row[ m_robot_record.fqdn ] )
00138         { cit = m_robots_list->erase( cit ); }
00139         else
00140         { ++cit; }
00141       }
00142     }
00143   }
00144 
00145   // return if no new data is available
00146   if ( !m_data_container->new_data_available() )
00147   {
00148     if ( robot_removed )
00149     { m_field_view->queue_draw(); }
00150     return true;
00151   }
00152 
00153   list<string> hosts = m_data_container->get_hosts();
00154 
00155   // check that all hosts are in the treeview
00156   for ( list<string>::iterator hit = hosts.begin();
00157         hit != hosts.end();
00158         ++hit )
00159   {
00160     bool found = false;
00161     
00162     Gtk::TreeModel::Children children = m_robots_list->children();
00163     for ( Gtk::TreeModel::iterator i = children.begin();
00164           i != children.end();
00165           ++i )
00166     {
00167       Gtk::TreeModel::Row row = *i;
00168       if ( Glib::ustring( *hit ) == row[ m_robot_record.fqdn ] )
00169       { 
00170         found = true;
00171         break;
00172       }
00173     }
00174     
00175     if ( !found )
00176     {
00177       char* fqdn;
00178       char* hostname;
00179       char delim ='.';
00180       Glib::ustring fqdn_str = Glib::ustring( *hit );
00181 
00182       fqdn = strdup( hit->c_str() );
00183       hostname = strtok( fqdn, &delim );
00184       int i = atoi( hostname );
00185       
00186       Gtk::TreeModel::Row row = *m_robots_list->append();
00187     
00188       if ( 0 == i ) /* fqdn is not an IP address */
00189       { row[ m_robot_record.hostname ] = Glib::ustring( hostname ); }
00190       else
00191       { row[ m_robot_record.hostname ] = fqdn_str; }
00192       row[ m_robot_record.fqdn ]           = fqdn_str;
00193       row[ m_robot_record.show_pose ]      = m_field_view->toggle_show_pose( fqdn_str );
00194       row[ m_robot_record.show_ball ]      = m_field_view->toggle_show_ball( fqdn_str );
00195       row[ m_robot_record.show_opponents ] = m_field_view->toggle_show_opponents( fqdn_str );
00196       
00197       free(fqdn);
00198     }
00199   }
00200   
00201   m_field_view->queue_draw();
00202 
00203   return true;
00204 }
00205 
00206 /** Call this method whenever the game state changes. */
00207 void
00208 WorldInfoViewer::gamestate_changed()
00209 {
00210   char* status_string;
00211   if ( asprintf( &status_string, 
00212                  "Team color: %s  Goal color: %s  Mode: %s  Score: %d:%d  Half: %s",
00213                  m_data_container->get_own_team_color_string().c_str(),
00214                  m_data_container->get_own_goal_color_string().c_str(),
00215                  m_data_container->get_game_state_string().c_str(),
00216                  m_data_container->get_own_score(),
00217                  m_data_container->get_other_score(),
00218                  m_data_container->get_half_string().c_str() ) != -1 )
00219   {
00220     m_stb_status->remove_message(m_stb_message_id);
00221     m_stb_message_id = m_stb_status->push( Glib::ustring(status_string) );
00222     
00223     free(status_string);
00224   }
00225 }
00226 
00227 void
00228 WorldInfoViewer::on_show_pose_toggled( const Glib::ustring& path )
00229 {
00230   Gtk::TreeModel::Row row = *m_robots_list->get_iter( path );
00231   Glib::ustring fqdn = row[ m_robot_record.fqdn ];
00232   
00233   row[ m_robot_record.show_pose ] = m_field_view->toggle_show_pose( fqdn );
00234   
00235   m_field_view->queue_draw();
00236 }
00237 
00238 void
00239 WorldInfoViewer::on_show_ball_toggled( const Glib::ustring& path )
00240 {
00241   Gtk::TreeModel::Row row = *m_robots_list->get_iter( path );
00242   Glib::ustring fqdn = row[ m_robot_record.fqdn ];
00243   
00244   row[ m_robot_record.show_ball ] = m_field_view->toggle_show_ball( fqdn );
00245   
00246   m_field_view->queue_draw();
00247 }
00248 
00249 void
00250 WorldInfoViewer::on_show_opponents_toggled( const Glib::ustring& path )
00251 {
00252   Gtk::TreeModel::Row row = *m_robots_list->get_iter( path );
00253   Glib::ustring fqdn = row[ m_robot_record.fqdn ];
00254   
00255   row[ m_robot_record.show_opponents ] = m_field_view->toggle_show_opponents( fqdn );
00256   
00257   m_field_view->queue_draw();
00258 }