Fawkes API
Fawkes Development Version
|
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 }