firestation.cpp

00001
00002 /***************************************************************************
00003  *  firestation.cpp - Firestation
00004  *
00005  *  Created: Wed Oct 10 14:19:30 2007
00006  *  Copyright  2007-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 "firestation.h"
00024 #include "mirror_calib.h"
00025 #include "color_train_widget.h"
00026 #include "fuse_transfer_widget.h"
00027
00028 #include <fvwidgets/fuse_image_list_widget.h>
00029 #include <gui_utils/avahi_dispatcher.h>
00030
00031 #include <cams/fileloader.h>
00032 #include <cams/shmem.h>
00033 #include <cams/net.h>
00034
00035 #include <fvutils/ipc/shm_image.h>
00036 #include <fvutils/color/conversions.h>
00037 #include <fvutils/color/yuv.h>
00038 #include <fvutils/colormap/yuvcm.h>
00039 #include <fvutils/scalers/lossy.h>
00040 #include <fvutils/system/camargp.h>
00041 #include <fvutils/writers/jpeg.h>
00042 #include <fvutils/writers/fvraw.h>
00043 #include <fvutils/draw/drawer.h>
00044
00045 #include <core/exception.h>
00046
00047 #include <gdkmm/pixbuf.h>
00048
00049 #include <arpa/inet.h>
00050
00051 #include <iostream>
00052
00053 using namespace std;
00054 using namespace fawkes;
00055 
00056 /** @class Firestation tools/firestation/firestation.h
00057  * Control GUI for vision related stuff.
00058  * @author Daniel Beck
00059  */
00060 
00061 /** Constructor.
00062  * @param ref_xml reference pointer to the glade file
00063  */
00064 Firestation::Firestation(Glib::RefPtr<Gnome::Glade::Xml> ref_xml)
00065 {
00066   // --- main window ------------------------------------------------
00067   m_wnd_main = dynamic_cast<Gtk::Window*>( get_widget(ref_xml, "wndMain") );
00068
00069   m_img_image = dynamic_cast<Gtk::Image*>( get_widget(ref_xml, "imgImage") );
00070   m_img_image->signal_size_allocate().connect( sigc::mem_fun(*this, &Firestation::resize_image) );
00071
00072   m_evt_image = dynamic_cast<Gtk::EventBox*>( get_widget(ref_xml, "evtImageEventBox") );
00073   m_evt_image->signal_button_press_event().connect( sigc::mem_fun(*this, &Firestation::image_click) );
00074
00075   m_trv_shm_image_ids = dynamic_cast<Gtk::TreeView*>( get_widget(ref_xml, "trvShmImageIds") );
00076
00077   m_stb_status = dynamic_cast<Gtk::Statusbar*>( get_widget(ref_xml, "stbStatus") );
00078
00079   m_ckb_cont_trans = dynamic_cast<Gtk::CheckButton*>( get_widget(ref_xml, "ckbContTrans") );
00080   m_ckb_cont_trans->signal_toggled().connect( sigc::mem_fun(*this, &Firestation::enable_cont_img_trans) );
00081
00082   m_spb_update_time = dynamic_cast<Gtk::SpinButton*>( get_widget(ref_xml, "spbUpdateTime") );
00083   // ----------------------------------------------------------------
00084
00085
00086   // --- toolbar widgets --------------------------------------------
00087   m_tbtn_exit = dynamic_cast<Gtk::ToolButton*>( get_widget(ref_xml, "tbtnExit") );
00088   m_tbtn_exit->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::exit) );
00089
00090   m_tbtn_close_camera = dynamic_cast<Gtk::ToolButton*>( get_widget(ref_xml, "tbtnCloseCamera") );
00091   m_tbtn_close_camera->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::close_camera) );
00092
00093   m_tbtn_update = dynamic_cast<Gtk::ToolButton*>( get_widget(ref_xml, "tbtnUpdate") );
00094   m_tbtn_update->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::update_image) );
00095
00096   m_tbtn_save = dynamic_cast<Gtk::ToolButton*>( get_widget(ref_xml, "tbtnSave") );
00097   m_tbtn_save->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::save_image) );
00098
00099   m_tbtn_open_file = dynamic_cast<Gtk::ToolButton*>( get_widget(ref_xml, "tbtnOpenFile") );
00100   m_tbtn_open_file->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::open_file) );
00101
00102   m_tbtn_open_folder = dynamic_cast<Gtk::ToolButton*>( get_widget(ref_xml, "tbtnOpenFolder") );
00103   m_tbtn_open_folder->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::open_folder) );
00104
00105   m_tbtn_open_shm = dynamic_cast<Gtk::ToolButton*>( get_widget(ref_xml, "tbtnOpenShm") );
00106   m_tbtn_open_shm->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::open_shm) );
00107
00108   m_tbtn_open_fuse = dynamic_cast<Gtk::ToolButton*>( get_widget(ref_xml, "tbtnOpenFuse") );
00109   m_tbtn_open_fuse->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::open_fuse) );
00110   // ----------------------------------------------------------------
00111
00112
00113   // --- dialogs ----------------------------------------------------
00114   ref_xml->get_widget("fcdOpenImage", m_fcd_open_image);
00115   if ( !m_fcd_open_image )
00116     {
00117       throw std::runtime_error("Couldn't find fcdOpenImage.");
00118     }
00119
00120   Gtk::FileFilter* filter_jpg = new Gtk::FileFilter();
00121   filter_jpg->set_name("JPEG");
00122   filter_jpg->add_pattern("*.jpg");
00123   filter_jpg->add_pattern("*.jpeg");
00124   m_fcd_open_image->add_filter(*filter_jpg);
00125
00126   Gtk::FileFilter* filter_fvraw = new Gtk::FileFilter();
00127   filter_fvraw->set_name("FVRaw");
00128   filter_fvraw->add_pattern("*.raw");
00129   filter_fvraw->add_pattern("*.fvraw");
00130   m_fcd_open_image->add_filter(*filter_fvraw);
00131
00132   ref_xml->get_widget("fcdSaveImage", m_fcd_save_image);
00133   if ( !m_fcd_save_image )
00134     {
00135       throw std::runtime_error("Couldn't find fcdSaveImage.");
00136     }
00137   m_fcd_save_image->add_filter(*filter_jpg);
00138   m_fcd_save_image->add_filter(*filter_fvraw);
00139
00140   ref_xml->get_widget("dlgOpenShm", m_dlg_open_shm);
00141   if (!m_dlg_open_shm)
00142     {
00143       throw std::runtime_error("Couldn't find dlgOpenShm.");
00144     }
00145
00146   ref_xml->get_widget("trvShmImageIds", m_trv_shm_image_ids);
00147   if ( !m_trv_shm_image_ids )
00148     {
00149       throw std::runtime_error("Couldn't find trvShmImageIds.");
00150     }
00151   m_shm_list_store = Gtk::ListStore::create(m_shm_columns);
00152   m_trv_shm_image_ids->set_model(m_shm_list_store);
00153   m_trv_shm_image_ids->append_column("#", m_shm_columns.m_id);
00154   m_trv_shm_image_ids->append_column("Name", m_shm_columns.m_name);
00155
00156
00157   ref_xml->get_widget("dlgOpenFuse", m_dlg_open_fuse);
00158   if (!m_dlg_open_fuse)
00159     {
00160       throw std::runtime_error("Couldn't find dlgOpenFuse.");
00161     }
00162
00163   ref_xml->get_widget("ckbFuseJpeg", m_ckb_fuse_jpeg);
00164   if (! m_ckb_fuse_jpeg )
00165     {
00166       throw std::runtime_error("Couldn't find ckbFuseJpeg.");
00167     }
00168
00169   ref_xml->get_widget("trvFuseServices", m_trv_fuse_services);
00170   if ( !m_trv_fuse_services )
00171     {
00172       throw std::runtime_error("Couldn't find trvFuseServices.");
00173     }
00174   m_fuse_tree_store = Gtk::TreeStore::create(m_fuse_columns);
00175   m_trv_fuse_services->set_model(m_fuse_tree_store);
00176   //  m_trv_fuse_services->append_column("#", m_fuse_columns.m_id);
00177   m_trv_fuse_services->append_column("Name", m_fuse_columns.m_name);
00178   // ----------------------------------------------------------------
00179
00180
00181   // --- color train widget -----------------------------------------
00182   m_ctw = new ColorTrainWidget(this);
00183   m_cmb_ct_type  = dynamic_cast<Gtk::ComboBox*>( get_widget(ref_xml, "cmbCtObjectType") );
00184   m_cmb_ct_type->signal_changed().connect(sigc::mem_fun(*this, &Firestation::ct_object_changed));
00185   m_cmb_ct_type->set_active(0);
00186
00187   m_btn_ct_start = dynamic_cast<Gtk::ToggleButton*>( get_widget(ref_xml, "btnCtStart") );
00188   m_btn_ct_start->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::ct_start) );
00189
00190   m_ctw->update_image().connect( sigc::mem_fun(*this, &Firestation::draw_image) );
00191   m_ctw->colormap_updated().connect( sigc::mem_fun(*this, &Firestation::on_colormap_updated) );
00192
00193   Gtk::Button* btn;
00194   btn = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCtUnselect") );
00195   m_ctw->set_reset_selection_btn(btn);
00196
00197   btn = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCtAdd") );
00198   m_ctw->set_add_to_colormap_btn(btn);
00199
00200   btn = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCtReset") );
00201   m_ctw->set_reset_colormap_btn(btn);
00202
00203   btn = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCtSaveHistos") );
00204   m_ctw->set_save_histos_btn(btn);
00205
00206   btn = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCtLoadHistos") );
00207   m_ctw->set_load_histos_btn(btn);
00208
00209   btn = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCtSaveColormap") );
00210   m_ctw->set_save_colormap_btn(btn);
00211
00212   btn = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCtLoadColormap") );
00213   m_ctw->set_load_colormap_btn(btn);
00214
00215   Gtk::Scale* scl;
00216   scl = dynamic_cast<Gtk::Scale*>( get_widget(ref_xml, "sclCtThreshold") );
00217   m_ctw->set_threshold_scl(scl);
00218
00219   scl = dynamic_cast<Gtk::Scale*>( get_widget(ref_xml, "sclCtMinProb") );
00220   m_ctw->set_min_prob_scl(scl);
00221
00222   scl = dynamic_cast<Gtk::Scale*>( get_widget(ref_xml, "sclCtLayerSelector") );
00223   m_ctw->set_cm_layer_selector(scl);
00224
00225   Gtk::Image* img;
00226   img = dynamic_cast<Gtk::Image*>( get_widget(ref_xml, "imgCtSegmentation") );
00227   m_ctw->set_segmentation_img(img);
00228
00229   img = dynamic_cast<Gtk::Image*>( get_widget(ref_xml, "imgCtColormap") );
00230   m_ctw->set_colormap_img(img);
00231
00232   Gtk::FileChooserDialog* fcd;
00233   fcd = dynamic_cast<Gtk::FileChooserDialog*>( get_widget(ref_xml, "fcdFilechooser") );
00234   m_ctw->set_filechooser_dlg(fcd);
00235
00236
00237   m_btn_ct_seg = dynamic_cast<Gtk::ToggleButton*>( get_widget(ref_xml, "btnCtSeg") );
00238   m_btn_ct_seg->signal_toggled().connect( sigc::mem_fun(*this, &Firestation::draw_image) );
00239   m_spbtn_depth = dynamic_cast<Gtk::SpinButton*>( get_widget(ref_xml, "spbtnCtCmDepth") );
00240   m_spbtn_width = dynamic_cast<Gtk::SpinButton*>( get_widget(ref_xml, "spbtnCtCmWidth") );
00241   m_spbtn_height = dynamic_cast<Gtk::SpinButton*>( get_widget(ref_xml, "spbtnCtCmHeight") );
00242   m_ctw->set_cm_selector(m_spbtn_depth, m_spbtn_width, m_spbtn_height);
00243   // ----------------------------------------------------------------
00244
00245
00246   // --- mirror calibration -----------------------------------------
00247   m_calib_tool = new MirrorCalibTool();
00248
00249 #ifndef HAVE_BULB_CREATOR
00250   Gtk::Notebook *nb = dynamic_cast<Gtk::Notebook*>( get_widget(ref_xml, "ntbOptions") );
00251   Gtk::HBox *box = dynamic_cast<Gtk::HBox*>( get_widget(ref_xml, "boxMirrorCalib") );
00252   nb->get_tab_label(*box)->set_sensitive(false);
00253   box->set_sensitive(false);
00254 #endif /* HAVE_BULB_CREATOR */
00255
00256   m_btn_mc_start = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnMcStart") );
00257   m_btn_mc_start->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_start) );
00258
00259   m_btn_mc_load = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCalibLoad") );
00260   m_btn_mc_load->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_load) );
00261
00262   m_btn_mc_save = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnCalibSave") );
00263   m_btn_mc_save->signal_clicked().connect( sigc::mem_fun(*this, &Firestation::mc_save) );
00264
00265   m_ent_mc_dist = dynamic_cast<Gtk::Entry*>( get_widget(ref_xml, "entCalibDist") );
00266   m_ent_mc_ori = dynamic_cast<Gtk::Entry*>( get_widget(ref_xml, "entCalibOri") );
00267
00268   m_fcd_mc_save = dynamic_cast<Gtk::FileChooserDialog*>( get_widget(ref_xml, "fcdCalibSave") );
00269   m_fcd_mc_load = dynamic_cast<Gtk::FileChooserDialog*>( get_widget(ref_xml, "fcdCalibLoad") );
00270   // ----------------------------------------------------------------
00271
00272
00273   // --- fuse transfer widget ---------------------------------------
00274   m_ftw = new FuseTransferWidget();
00275
00276   Gtk::TreeView* trv = dynamic_cast<Gtk::TreeView*>( get_widget(ref_xml, "trvFuseRemoteLuts") );
00277   m_ftw->set_remote_lut_list_trv(trv);
00278   trv = dynamic_cast<Gtk::TreeView*>( get_widget(ref_xml, "trvFuseLocalLuts") );
00279   m_ftw->set_local_lut_list_trv(trv);
00280   img = dynamic_cast<Gtk::Image*>( get_widget(ref_xml, "imgFuseLocal") );
00281   m_ftw->set_local_img(img);
00282   img = dynamic_cast<Gtk::Image*>( get_widget(ref_xml, "imgFuseRemote") );
00283   m_ftw->set_remote_img(img);
00284   btn = dynamic_cast<Gtk::Button*>( get_widget(ref_xml, "btnFuseUpload") );
00285   m_ftw->set_upload_btn(btn);
00286   scl = dynamic_cast<Gtk::Scale*>( get_widget(ref_xml, "sclLocalLayerSelector") );
00287   m_ftw->set_local_layer_selector(scl);
00288   scl = dynamic_cast<Gtk::Scale*>( get_widget(ref_xml, "sclRemoteLayerSelector") );
00289   m_ftw->set_remote_layer_selector(scl);
00290   // ----------------------------------------------------------------
00291
00292
00293   // --- fuse image list widget -------------------------------------
00294   m_filw = new FuseImageListWidget();
00295   trv = dynamic_cast<Gtk::TreeView*>( get_widget(ref_xml, "trvFuseImageList") );
00296   m_filw->set_image_list_trv(trv);
00297   Gtk::CheckButton* chk = dynamic_cast<Gtk::CheckButton*>( get_widget(ref_xml, "chkFuseImageListUpdate") );
00298   m_filw->set_auto_update_chk(chk);
00299   chk = dynamic_cast<Gtk::CheckButton*>( get_widget(ref_xml, "chkFuseCompression") );
00300   m_filw->set_toggle_compression_chk(chk);
00301   m_filw->image_selected().connect( sigc::mem_fun(*this, &Firestation::on_fuse_image_selected) );
00302   // ----------------------------------------------------------------
00303
00304   m_yuv_orig_buffer   = 0;
00305   m_yuv_draw_buffer   = 0;
00306   m_yuv_scaled_buffer = 0;
00307   m_rgb_scaled_buffer = 0;
00308
00309   m_img_width  = 0;
00310   m_img_height = 0;
00311   m_img_size   = 0;
00312   m_img_cs     = CS_UNKNOWN;
00313
00314   m_img_writer = 0;
00315   m_camera     = 0;
00316   m_shm_buffer = 0;
00317
00318   m_img_src = SRC_NONE;
00319   m_op_mode = MODE_VIEWER;
00320
00321   m_cont_img_trans = false;
00322
00323   m_max_img_width  = m_evt_image->get_width();
00324   m_max_img_height = m_evt_image->get_height();
00325   m_scaled_img_width  = m_evt_image->get_width();
00326   m_scaled_img_height = m_evt_image->get_height();
00327   m_scale_factor = 1.0;
00328
00329   m_avahi_thread = new AvahiThread();
00330   m_avahi_dispatcher = new AvahiDispatcher;
00331
00332   m_avahi_dispatcher->signal_service_added().connect( sigc::mem_fun( *this, &Firestation::on_service_added ) );
00333   m_avahi_dispatcher->signal_service_removed().connect( sigc::mem_fun( *this, &Firestation::on_service_removed ) );
00334
00335   m_avahi_thread->watch_service("_fountain._tcp", m_avahi_dispatcher);
00336   m_avahi_thread->start();
00337 }
00338 
00339 /** Destructor. */
00340 Firestation::~Firestation()
00341 {
00342   free(m_yuv_orig_buffer);
00343   free(m_yuv_draw_buffer);
00344   free(m_yuv_scaled_buffer);
00345   free(m_rgb_scaled_buffer);
00346
00347   delete m_camera;
00348   delete m_img_writer;
00349
00350   delete m_calib_tool;
00351   delete m_ctw;
00352   delete m_ftw;
00353   delete m_filw;
00354
00355   delete m_avahi_thread;
00356   delete m_avahi_dispatcher;
00357
00358   delete m_wnd_main;
00359   delete m_fcd_open_image;
00360   delete m_fcd_save_image;
00361   delete m_dlg_open_shm;
00362   delete m_dlg_open_fuse;
00363 }
00364
00365 Gtk::Widget*
00366 Firestation::get_widget(Glib::RefPtr<Gnome::Glade::Xml> ref_xml,
00367                         const char* widget_name) const
00368 {
00369   Gtk::Widget* widget;
00370   ref_xml->get_widget(widget_name, widget);
00371   if ( !widget )
00372     {
00373       std::string err_str = "Couldn't find widget ";
00374       err_str += std::string(widget_name);
00375       err_str += ".";
00376       throw runtime_error(err_str);
00377     }
00378
00379   return widget;
00380 }
00381 
00382 /** Returns reference to main window.
00383  * @return reference to main window
00384  */
00385 Gtk::Window&
00386 Firestation::get_window() const
00387 {
00388   return *m_wnd_main;
00389 }
00390 
00391 /** Exit routine. */
00392 void
00393 Firestation::exit()
00394 {
00395   m_avahi_thread->cancel();
00396   m_avahi_thread->join();
00397
00398   if (SRC_NONE != m_img_src)
00399     { m_camera->close(); }
00400
00401   m_wnd_main->hide();
00402 }
00403
00404 void
00405 Firestation::close_camera()
00406 {
00407   if (SRC_NONE == m_img_src)
00408     { return; }
00409
00410   m_img_src = SRC_NONE;
00411
00412   m_camera->close();
00413   delete m_camera;
00414   m_camera = 0;
00415
00416   m_img_width = 0;
00417   m_img_height = 0;
00418   m_img_cs = CS_UNKNOWN;
00419
00420   m_img_size = 0;
00421
00422   free(m_yuv_orig_buffer);
00423   free(m_yuv_draw_buffer);
00424
00425   m_yuv_orig_buffer = 0;
00426   m_yuv_draw_buffer = 0;
00427
00428   m_img_image->clear();
00429   m_img_image->set("gtk-missing-image");
00430
00431   m_ctw->set_src_buffer(NULL, 0, 0);
00432   m_ctw->set_draw_buffer(NULL);
00433 }
00434 
00435 /** Saves the current image. */
00436 void
00437 Firestation::save_image()
00438 {
00439   if (m_img_src == SRC_NONE)
00440     { return; }
00441
00442   m_fcd_save_image->set_transient_for(*this);
00443
00444   int result = m_fcd_save_image->run();
00445
00446   switch(result)
00447     {
00448     case(Gtk::RESPONSE_OK):
00449       {
00450         delete m_img_writer;
00451
00452         Glib::ustring filter_name = m_fcd_save_image->get_filter()->get_name();
00453         if ( Glib::ustring("JPEG") == filter_name )
00454           {
00455             m_img_writer = new JpegWriter();
00456           }
00457         else if( Glib::ustring("FVRaw") == filter_name )
00458           {
00459             m_img_writer = new FvRawWriter();
00460           }
00461         else
00462           {
00463             cout << "save_file(): unknown file format" << endl;
00464             break;
00465           }
00466
00467         std::string filename = m_fcd_save_image->get_filename();
00468         m_img_writer->set_filename( filename.c_str() );
00469         m_img_writer->set_dimensions(m_img_width, m_img_height);
00470         m_img_writer->set_buffer(m_img_cs, m_yuv_orig_buffer);
00471         m_img_writer->write();
00472
00473         std::cout << "Save file: " <<  filename << std::endl;
00474         break;
00475       }
00476
00477     case(Gtk::RESPONSE_CANCEL):
00478       break;
00479
00480     default:
00481       break;
00482     }
00483
00484   m_fcd_save_image->hide();
00485 }
00486 
00487 /** Reads in a new image for the current image source. */
00488 void
00489 Firestation::update_image()
00490 {
00491   if (m_img_src == SRC_NONE)
00492     { return; }
00493
00494   try
00495     {
00496       m_camera->capture();
00497       memcpy(m_yuv_orig_buffer, m_camera->buffer(), m_img_size);
00498       memcpy(m_yuv_draw_buffer, m_camera->buffer(), m_img_size);
00499       m_camera->dispose_buffer();
00500
00501       draw_image();
00502
00503       m_ctw->draw_segmentation_result();
00504     }
00505   catch (Exception& e)
00506     {
00507       e.print_trace();
00508     }
00509 }
00510
00511 bool
00512 Firestation::call_update_image()
00513 {
00514   if ( !m_cont_img_trans )
00515     { return false; }
00516
00517   update_image();
00518
00519   return true;
00520 }
00521
00522 void
00523 Firestation::enable_cont_img_trans()
00524 {
00525   if (m_cont_img_trans)
00526     {
00527       m_cont_img_trans = false;
00528       return;
00529     }
00530
00531   int timeout = (int) rint( m_spb_update_time->get_value() );
00532   sigc::connection conn = Glib::signal_timeout().connect( sigc::mem_fun(*this, &Firestation::call_update_image), timeout);
00533   m_cont_img_trans = true;
00534 }
00535 
00536 /** Reads in an image from a file. */
00537 void
00538 Firestation::open_file()
00539 {
00540   m_fcd_open_image->set_action(Gtk::FILE_CHOOSER_ACTION_OPEN);
00541   m_fcd_open_image->set_transient_for(*this);
00542
00543   int result = m_fcd_open_image->run();
00544
00545   switch(result)
00546     {
00547     case Gtk::RESPONSE_OK:
00548       {
00549         pre_open_img_src();
00550
00551         std::string filename = m_fcd_open_image->get_filename();
00552
00553         m_camera = new FileLoader( filename.c_str() );
00554         m_img_src = SRC_FILE;
00555         post_open_img_src();
00556
00557         break;
00558       }
00559
00560     case Gtk::RESPONSE_CANCEL:
00561       {
00562         break;
00563       }
00564
00565     default:
00566       {
00567         break;
00568       }
00569     }
00570
00571   m_fcd_open_image->hide();
00572 }
00573 
00574 /** Reads in images from a directory. */
00575 void
00576 Firestation::open_folder()
00577 {
00578   m_fcd_open_image->set_action(Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
00579   m_fcd_open_image->set_transient_for(*this);
00580
00581   int result = m_fcd_open_image->run();
00582
00583   switch(result)
00584     {
00585     case Gtk::RESPONSE_OK:
00586       {
00587         pre_open_img_src();
00588
00589         std::string extension;
00590         Glib::ustring filter_name = m_fcd_save_image->get_filter()->get_name();
00591         if ( Glib::ustring("JPEG") == filter_name )
00592           { extension = "jpg"; }
00593         else if ( Glib::ustring("FVRaw") == filter_name )
00594           { extension = "raw"; }
00595
00596         std::string folder = m_fcd_open_image->get_current_folder();
00597         char* as;
00598         if (asprintf(&as, "file:file:dir=%s:ext=%s", folder.c_str(), extension.c_str()) != -1) {
00599           CameraArgumentParser cap(as);
00600           m_camera = new FileLoader( &cap );
00601           m_img_src = SRC_FILE;
00602           post_open_img_src();
00603           free(as);
00604         } else {
00605           printf("Cannot open folder, asprintf() ran out of memory");
00606         }
00607
00608         break;
00609       }
00610
00611     case Gtk::RESPONSE_CANCEL:
00612       {
00613         break;
00614       }
00615
00616     default:
00617       {
00618         break;
00619       }
00620     }
00621
00622   m_fcd_open_image->hide();
00623 }
00624 
00625 /** Opens a SHM image. */
00626 void
00627 Firestation::open_shm()
00628 {
00629   unsigned int num_buffers = 0;
00630   SharedMemory::SharedMemoryIterator shmit;
00631   SharedMemoryImageBufferHeader* h = new SharedMemoryImageBufferHeader;
00632   shmit = SharedMemory::find(FIREVISION_SHM_IMAGE_MAGIC_TOKEN, h);
00633
00634   if (shmit == SharedMemory::end())
00635     {
00636       m_stb_status->push("No SHM images found");
00637       return;
00638     }
00639   else
00640     {
00641       m_shm_list_store->clear();
00642
00643       while ( shmit != SharedMemory::end() )
00644         {
00645           ++num_buffers;
00646           Gtk::TreeModel::Row row = *(m_shm_list_store->append());
00647           row[m_shm_columns.m_id] = num_buffers;
00648           const SharedMemoryImageBufferHeader* h = (SharedMemoryImageBufferHeader*)*shmit;
00649           row[m_shm_columns.m_name] = h->image_id();
00650           shmit++;
00651         }
00652     }
00653
00654   m_dlg_open_shm->set_transient_for(*this);
00655
00656   int result = m_dlg_open_shm->run();
00657
00658   switch(result)
00659     {
00660     case Gtk::RESPONSE_OK:
00661       {
00662         delete m_shm_buffer;
00663
00664         Gtk::TreeModel::Path path;
00665         Gtk::TreeViewColumn* column;
00666         m_trv_shm_image_ids->get_cursor(path, column);
00667
00668         Gtk::TreeModel::iterator iter = m_shm_list_store->get_iter(path);
00669
00670         if (iter)
00671           {
00672             Gtk::TreeModel::Row row = *iter;
00673             if (row)
00674               {
00675                 Glib::ustring name = row[m_shm_columns.m_name];
00676                 pre_open_img_src();
00677
00678                 try
00679                   {
00680                     m_camera = new SharedMemoryCamera( name.c_str() );
00681                   }
00682                 catch (Exception& e)
00683                   {
00684                     e.print_trace();
00685                   }
00686
00687                 m_img_src = SRC_SHM;
00688
00689                 post_open_img_src();
00690               }
00691           }
00692         else
00693           {
00694             std::cout << "invalid iter" << std::endl;
00695           }
00696
00697         break;
00698       }
00699
00700     case Gtk::RESPONSE_CANCEL:
00701       break;
00702
00703     default:
00704       break;
00705     }
00706
00707   m_dlg_open_shm->hide();
00708 }
00709 
00710 /** Connects to a FUSE server. */
00711 void
00712 Firestation::open_fuse()
00713 {
00714   Gtk::TreeModel::Children children = m_fuse_tree_store->children();
00715   if ( 0 == children.size() )
00716     {
00717       m_stb_status->push("No FUSE services found");
00718       return;
00719     }
00720
00721   m_trv_fuse_services->expand_all();
00722   m_dlg_open_fuse->set_transient_for(*this);
00723
00724   int result = m_dlg_open_fuse->run();
00725
00726   switch(result)
00727     {
00728     case Gtk::RESPONSE_OK:
00729       {
00730         Gtk::TreeModel::Path path;
00731         Gtk::TreeViewColumn* column;
00732         m_trv_fuse_services->get_cursor(path, column);
00733
00734         Gtk::TreeModel::iterator iter = m_fuse_tree_store->get_iter(path);
00735
00736         if (iter)
00737           {
00738             Gtk::TreeModel::Row row = *iter;
00739             if (row)
00740               {
00741                 Glib::ustring hostname = row[m_fuse_columns.m_service_hostname];
00742                 unsigned short int port = row[m_fuse_columns.m_service_port];
00743                 Glib::ustring image_id = row[m_fuse_columns.m_image_id];
00744                 bool jpeg = m_ckb_fuse_jpeg->get_active();
00745
00746                 pre_open_img_src();
00747
00748                 try
00749                   {
00750                     m_camera = new NetworkCamera(hostname.c_str(), port, image_id.c_str(), jpeg);
00751                     m_img_src = SRC_FUSE;
00752                     post_open_img_src();
00753                   }
00754                 catch (Exception& e)
00755                   {
00756                     m_img_src = SRC_NONE;
00757                     e.print_trace();
00758                   }
00759               }
00760           }
00761         else
00762           {
00763             std::cout << "invalid iter" << std::endl;
00764           }
00765
00766         break;
00767       }
00768
00769     case Gtk::RESPONSE_CANCEL:
00770       break;
00771
00772     default:
00773       break;
00774     }
00775
00776   m_dlg_open_fuse->hide();
00777 }
00778
00779 void
00780 Firestation::pre_open_img_src()
00781 {
00782   if (SRC_NONE != m_img_src)
00783     {
00784       m_camera->stop();
00785       m_camera->close();
00786
00787       delete m_camera;
00788       m_camera = 0;
00789
00790       m_img_src = SRC_NONE;
00791     }
00792 }
00793 
00794 /** Stuff that is executed after an image source has been selected. */
00795 void
00796 Firestation::post_open_img_src()
00797 {
00798   if (m_img_src == SRC_NONE) { return; }
00799
00800   try
00801     {
00802       m_camera->open();
00803       m_camera->start();
00804       m_camera->capture();
00805       m_img_width = m_camera->pixel_width();
00806       m_img_height = m_camera->pixel_height();
00807       m_img_cs = m_camera->colorspace();
00808
00809       m_img_size = colorspace_buffer_size( m_img_cs,
00810                                            m_img_width,
00811                                            m_img_height );
00812
00813       free(m_yuv_orig_buffer);
00814       free(m_yuv_draw_buffer);
00815
00816       m_yuv_orig_buffer = (unsigned char*) malloc(m_img_size);
00817       m_yuv_draw_buffer = (unsigned char*) malloc(m_img_size);
00818       memcpy(m_yuv_orig_buffer, m_camera->buffer(), m_img_size);
00819       memcpy(m_yuv_draw_buffer, m_camera->buffer(), m_img_size);
00820
00821       m_camera->dispose_buffer();
00822
00823       m_tbtn_update->set_sensitive(true);
00824       m_tbtn_save->set_sensitive(true);
00825
00826       draw_image();
00827
00828       m_ctw->set_src_buffer(m_yuv_orig_buffer, m_img_width, m_img_height);
00829       m_ctw->set_draw_buffer(m_yuv_draw_buffer);
00830       m_ctw->draw_segmentation_result();
00831     }
00832   catch (Exception& e)
00833     {
00834       e.print_trace();
00835       printf("Opening camera failed.\n");
00836     }
00837
00838 }
00839
00840 void
00841 Firestation::on_fuse_image_selected()
00842 {
00843   string host_name;
00844   unsigned short port;
00845   string image_id;
00846   bool compression;
00847
00848   m_filw->get_selected_image(host_name, port, image_id, compression);
00849
00850   pre_open_img_src();
00851
00852   try
00853     {
00854       m_camera = new NetworkCamera( host_name.c_str(), port, image_id.c_str(), compression );
00855       m_img_src = SRC_FUSE;
00856     }
00857   catch (Exception& e)
00858     {
00859       m_img_src = SRC_NONE;
00860       e.print_trace();
00861     }
00862
00863   post_open_img_src();
00864 }
00865
00866 void
00867 Firestation::on_colormap_updated()
00868 {
00869   m_ftw->set_current_colormap( m_ctw->get_colormap() );
00870 }
00871 
00872 /** Draws the image. */
00873 void
00874 Firestation::draw_image()
00875 {
00876   if ( m_img_src == SRC_NONE ) { return; }
00877
00878   LossyScaler scaler;
00879   scaler.set_original_buffer( m_yuv_draw_buffer );
00880   scaler.set_original_dimensions(m_img_width, m_img_height);
00881   scaler.set_scaled_dimensions(m_max_img_width, m_max_img_height);
00882
00883   unsigned int scaled_width  = scaler.needed_scaled_width();
00884   unsigned int scaled_height = scaler.needed_scaled_height();
00885
00886   if (scaled_width != m_scaled_img_width || scaled_height != m_scaled_img_height)
00887     {
00888       m_scaled_img_width  = scaled_width;
00889       m_scaled_img_height = scaled_height;
00890       m_scale_factor = scaler.get_scale_factor();
00891     }
00892
00893   free(m_rgb_scaled_buffer);
00894   free(m_yuv_scaled_buffer);
00895   m_yuv_scaled_buffer = (unsigned char*) malloc( colorspace_buffer_size( m_img_cs,
00896                                                                          m_scaled_img_width,
00897                                                                          m_scaled_img_height ) );
00898   scaler.set_scaled_buffer(m_yuv_scaled_buffer);
00899   scaler.scale();
00900
00901   if (m_btn_ct_seg->get_active()) {
00902     unsigned int sld_img_size = m_scaled_img_width * m_scaled_img_height;
00903     unsigned char u_seg = 255 / (unsigned int)pow(2, m_spbtn_width->get_value());
00904     unsigned char v_seg = 255 / (unsigned int)pow(2, m_spbtn_height->get_value());
00905     unsigned int u = 0;
00906     for (u = sld_img_size; u < sld_img_size + sld_img_size / 2; ++u) {
00907       m_yuv_scaled_buffer[u] = (m_yuv_scaled_buffer[u] / u_seg) * u_seg;
00908     }
00909
00910     for (; u < 2 * sld_img_size; ++u) {
00911       m_yuv_scaled_buffer[u] = (m_yuv_scaled_buffer[u] / v_seg) * v_seg;
00912     }
00913   }
00914
00915   if ( m_img_src == SRC_SHM )
00916     {
00917       SharedMemoryCamera* shm_camera = dynamic_cast<SharedMemoryCamera*>(m_camera);
00918       if ( shm_camera->shared_memory_image_buffer()->circle_found() )
00919         {
00920           Drawer drawer;
00921           drawer.set_buffer(m_yuv_scaled_buffer, m_scaled_img_width, m_scaled_img_height);
00922           drawer.set_color(YUV_t::white());
00923           unsigned int roi_x = (unsigned int) rint( shm_camera->shared_memory_image_buffer()->roi_x() * m_scale_factor );
00924           unsigned int roi_y = (unsigned int) rint( shm_camera->shared_memory_image_buffer()->roi_y() * m_scale_factor );
00925           unsigned int roi_width  = (unsigned int) rint( shm_camera->shared_memory_image_buffer()->roi_width() * m_scale_factor );
00926           unsigned int roi_height = (unsigned int) rint( shm_camera->shared_memory_image_buffer()->roi_height() * m_scale_factor );
00927           drawer.draw_rectangle( roi_x, roi_y, roi_width, roi_height );
00928         }
00929     }
00930
00931   m_rgb_scaled_buffer = (unsigned char*) malloc( colorspace_buffer_size( RGB,
00932                                                                          m_scaled_img_width,
00933                                                                          m_scaled_img_height ) );
00934
00935   convert( m_img_cs, RGB,
00936            m_yuv_scaled_buffer, m_rgb_scaled_buffer,
00937            m_scaled_img_width, m_scaled_img_height );
00938
00939   Glib::RefPtr<Gdk::Pixbuf> image = Gdk::Pixbuf::create_from_data( m_rgb_scaled_buffer,
00940                                                                    Gdk::COLORSPACE_RGB,
00941                                                                    false,
00942                                                                    8,
00943                                                                    m_scaled_img_width,
00944                                                                    m_scaled_img_height,
00945                                                                    3 * m_scaled_img_width );
00946
00947   m_img_image->set(image);
00948 }
00949 
00950 /** Signal handler that is called whenever the window size is changed.
00951  * @param allocation a Gtk allocation
00952  */
00953 void
00954 Firestation::resize_image(Gtk::Allocation& allocation)
00955 {
00956   unsigned int new_width = (unsigned int) allocation.get_width();
00957   unsigned int new_height = (unsigned int) allocation.get_height();
00958
00959   if (new_width != m_max_img_width ||  new_height != m_max_img_height)
00960     {
00961       m_max_img_width = new_width;
00962       m_max_img_height = new_height;
00963       draw_image();
00964     }
00965 }
00966 
00967 /** Handles mouse clicks in the image area.
00968  * @param event a Gtk event
00969  * @return true if signal was handled
00970  */
00971 bool
00972 Firestation::image_click(GdkEventButton* event)
00973 {
00974   unsigned int offset_x;
00975   unsigned int offset_y;
00976
00977   offset_x = (m_max_img_width - m_scaled_img_width) / 2;
00978   offset_y = (m_max_img_height - m_scaled_img_height) / 2;
00979
00980   offset_x = offset_x > m_max_img_width ? 0 : offset_x;
00981   offset_y = offset_y > m_max_img_height ? 0 : offset_y;
00982
00983   unsigned int image_x;
00984   unsigned int image_y;
00985
00986   image_x = (unsigned int)rint( (event->x - offset_x) / m_scale_factor);
00987   image_y = (unsigned int)rint( (event->y - offset_y) / m_scale_factor);
00988
00989   if ( image_x < 0 || image_x > m_img_width ||
00990        image_y < 0 || image_y > m_img_height )
00991     { return true; }
00992
00993   switch (m_op_mode)
00994     {
00995     case MODE_VIEWER:
00996       if (m_img_src != SRC_NONE)
00997         {
00998           switch( m_img_cs )
00999             {
01000             case YUV422_PLANAR:
01001               register unsigned char y;
01002               register unsigned char u;
01003               register unsigned char v;
01004               YUV422_PLANAR_YUV( m_yuv_orig_buffer,
01005                                  m_img_width,
01006                                  m_img_height,
01007                                  image_x,
01008                                  image_y,
01009                                  y, u, v );
01010               cout << "Y: " << (unsigned int)y
01011                    << " U: " << (unsigned int)u
01012                    << " V: " << (unsigned int)v << endl;
01013               break;
01014             default:
01015           cout << "Unhandled colorspace" << endl;
01016             }
01017         }
01018       break;
01019
01020     case MODE_COLOR_TRAIN:
01021       m_ctw->click(image_x, image_y, event->button);
01022       draw_image();
01023      break;
01024
01025     case MODE_MIRROR_CALIB:
01026       {
01027         m_calib_tool->step(image_x, image_y);
01028
01029         bool show;
01030         float next_dist;
01031         float next_ori;
01032         show = m_calib_tool->get_next(&next_dist, &next_ori);
01033
01034         if (show)
01035           {
01036             char* next_dist_char = (char*) malloc(10);
01037             char* next_ori_char = (char*) malloc(10);
01038
01039             sprintf(next_dist_char, "%2f", next_dist);
01040             sprintf(next_ori_char, "%2f", next_ori);
01041             m_ent_mc_dist->set_text(Glib::ustring(next_dist_char));
01042             m_ent_mc_ori->set_text(Glib::ustring(next_ori_char));
01043
01044             free(next_dist_char);
01045             free(next_ori_char);
01046           }
01047         else
01048           {
01049             m_ent_mc_dist->set_text("");
01050             m_ent_mc_ori->set_text("");
01051           }
01052
01053         break;
01054       }
01055
01056     case MODE_MIRROR_CALIB_EVAL:
01057       {
01058         float dist;
01059         float phi;
01060         m_calib_tool->eval(image_x, image_y, &dist, &phi);
01061         printf("Distance: %2f\t Phi: %2f\n", dist, phi);
01062         break;
01063       }
01064
01065     default:
01066       break;
01067     }
01068
01069   return true;
01070 }
01071 
01072 /** Starts the color training. */
01073 void
01074 Firestation::ct_start()
01075 {
01076   if (m_op_mode == MODE_COLOR_TRAIN)
01077     {
01078       m_op_mode = MODE_VIEWER;
01079       m_stb_status->push("Leaving color training mode");
01080     }
01081   else
01082     {
01083       if (m_img_src != SRC_NONE)
01084         {
01085           m_ctw->set_fg_object( ct_get_fg_object() );
01086
01087           m_op_mode = MODE_COLOR_TRAIN;
01088
01089           m_stb_status->push("Entering color training mode");
01090         }
01091     }
01092 }
01093
01094 hint_t
01095 Firestation::ct_get_fg_object()
01096 {
01097         int active = m_cmb_ct_type->get_active_row_number();
01098         switch(active)
01099         {
01100                 case 0: //Ball
01101                         return H_BALL;
01102
01103                 case 1: //Field
01104                         return H_FIELD;
01105
01106                 case 2: //Lines
01107                         return H_LINE;
01108
01109                 case 3: //Robot (Team A or all)
01110                         return H_ROBOT;
01111
01112                 case 4: //Robot (Team B)
01113                         return H_ROBOT_OPP;
01114
01115                 case 5: //Goal (yellow)
01116                         return H_GOAL_YELLOW;
01117
01118                 case 6: //Goal (sky-blue)
01119                         return H_GOAL_BLUE;
01120
01121                 case 7: //Background
01122                         return H_UNKNOWN;
01123
01124                 default:
01125                         printf("ct_get_fg_object(): UNKNOWN\n");
01126                         return H_UNKNOWN;
01127         }
01128 }
01129
01130 void
01131 Firestation::ct_object_changed()
01132 {
01133         hint_t object = ct_get_fg_object();
01134         m_ctw->set_fg_object(object);
01135 }
01136 
01137 /** Start the mirror calibration process. */
01138 void
01139 Firestation::mc_start()
01140 {
01141   if (m_op_mode == MODE_MIRROR_CALIB)
01142     {
01143       m_op_mode = MODE_VIEWER;
01144       m_stb_status->push("Leaving mirror calibration mode");
01145     }
01146   else
01147     {
01148       if (m_img_src != SRC_NONE)
01149         {
01150           m_calib_tool->set_img_dimensions(m_img_width, m_img_height);
01151           m_calib_tool->start();
01152
01153           m_op_mode = MODE_MIRROR_CALIB;
01154
01155           bool show;
01156           float next_dist;
01157           float next_ori;
01158           show = m_calib_tool->get_next(&next_dist, &next_ori);
01159
01160           if (show)
01161             {
01162               char* next_dist_char = (char*) malloc(10);
01163               char* next_ori_char = (char*) malloc(10);
01164
01165               sprintf(next_dist_char, "%2f", next_dist);
01166               sprintf(next_ori_char, "%2f", next_ori);
01167               m_ent_mc_dist->set_text(Glib::ustring(next_dist_char));
01168               m_ent_mc_ori->set_text(Glib::ustring(next_ori_char));
01169
01170               free(next_dist_char);
01171               free(next_ori_char);
01172             }
01173           else
01174             {
01175               m_ent_mc_dist->set_text("");
01176               m_ent_mc_ori->set_text("");
01177             }
01178
01179           m_stb_status->push("Entering mirror calibration mode");
01180         }
01181     }
01182 }
01183 
01184 /** Load mirror calibration data from a file. */
01185 void
01186 Firestation::mc_load()
01187 {
01188   m_fcd_mc_load->set_transient_for(*this);
01189
01190   Gtk::FileFilter filter_mirror;
01191   filter_mirror.set_name("Mirror Calibration");
01192   filter_mirror.add_pattern("*.mirror");
01193   filter_mirror.add_pattern("*.bulb");
01194   m_fcd_mc_load->add_filter(filter_mirror);
01195
01196   int result = m_fcd_mc_load->run();
01197
01198   switch(result)
01199     {
01200     case Gtk::RESPONSE_OK:
01201       {
01202         std::string filename = m_fcd_mc_load->get_filename();
01203         m_calib_tool->load( filename.c_str() );
01204         m_op_mode = MODE_MIRROR_CALIB_EVAL;
01205         break;
01206       }
01207     case Gtk::RESPONSE_CANCEL:
01208       break;
01209     default:
01210       break;
01211     }
01212
01213   m_fcd_mc_load->hide();
01214 }
01215 
01216 /** Save calibration data to a file. */
01217 void
01218 Firestation::mc_save()
01219 {
01220   m_fcd_mc_save->set_transient_for(*this);
01221
01222   int result = m_fcd_mc_save->run();
01223
01224   switch(result)
01225     {
01226     case(Gtk::RESPONSE_OK):
01227       {
01228         std::string filename = m_fcd_mc_save->get_filename();
01229
01230         m_calib_tool->save( filename.c_str() );
01231         break;
01232       }
01233
01234     case(Gtk::RESPONSE_CANCEL):
01235       break;
01236
01237     default:
01238       break;
01239     }
01240
01241   m_fcd_mc_save->hide();
01242
01243 }
01244
01245 void
01246 Firestation::on_service_added( NetworkService* service )
01247 {
01248   const char* host        = service->host();
01249   const char* name        = service->name();
01250   const char* type        = service->type();
01251   const char* domain      = service->domain();
01252   unsigned short int port = service->port();
01253
01254   std::vector<FUSE_imageinfo_t> image_list;
01255   NetworkCamera cam(host, port);
01256   try
01257     {
01258       cam.open();
01259       cam.start();
01260       image_list = cam.image_list();
01261     }
01262   catch (Exception& e)
01263     {
01264       e.append("Could not open camera on %s:%d", host, port);
01265       e.print_trace();
01266       return;
01267     }
01268   cam.close();
01269
01270 #ifdef DEBUG_PRINT
01271   printf("%zu images available on host %s.\n", image_list.size(), host);
01272 #endif /* DEBUG_PRINT */
01273
01274   std::vector<FUSE_imageinfo_t>::iterator fit;
01275
01276   Gtk::TreeModel::Children children = m_fuse_tree_store->children();
01277   Gtk::TreeModel::Row row = *(m_fuse_tree_store->append());
01278   row[m_fuse_columns.m_id] = children.size();
01279   row[m_fuse_columns.m_name] = Glib::ustring(name);
01280   row[m_fuse_columns.m_service_name] = Glib::ustring(name);
01281   row[m_fuse_columns.m_service_type] = Glib::ustring(type);
01282   row[m_fuse_columns.m_service_domain] = Glib::ustring(domain);
01283   row[m_fuse_columns.m_service_hostname] = Glib::ustring(host);
01284   row[m_fuse_columns.m_service_port] = port;
01285
01286   for (fit = image_list.begin(); fit != image_list.end(); ++fit)
01287     {
01288       Gtk::TreeModel::Row childrow = *(m_fuse_tree_store->append(row.children()));
01289       childrow[m_fuse_columns.m_name] = Glib::ustring(fit->image_id);
01290       childrow[m_fuse_columns.m_service_name] = Glib::ustring(name);
01291       childrow[m_fuse_columns.m_service_type] = Glib::ustring(type);
01292       childrow[m_fuse_columns.m_service_domain] = Glib::ustring(domain);
01293       childrow[m_fuse_columns.m_service_hostname] = Glib::ustring(host);
01294       childrow[m_fuse_columns.m_service_port] = port;
01295       childrow[m_fuse_columns.m_image_id] = Glib::ustring(fit->image_id);
01296       childrow[m_fuse_columns.m_image_width] = fit->width;
01297       childrow[m_fuse_columns.m_image_height] = fit->height;
01298       childrow[m_fuse_columns.m_image_colorspace] = Glib::ustring( colorspace_to_string((colorspace_t) fit->colorspace) );
01299     }
01300
01301   m_ftw->add_fountain_service(name, host, port);
01302   m_filw->add_fountain_service(name, host, port);
01303 }
01304
01305 void
01306 Firestation::on_service_removed( NetworkService* service )
01307 {
01308   const char* name   = service->name();
01309   const char* type   = service->type();
01310   const char* domain = service->domain();
01311
01312   Gtk::TreeModel::Children children = m_fuse_tree_store->children();
01313   Gtk::TreeModel::iterator rit;
01314   for (rit = children.begin(); rit != children.end(); ++rit)
01315     {
01316       Glib::ustring n = (*rit)[m_fuse_columns.m_service_name];
01317       Glib::ustring t = (*rit)[m_fuse_columns.m_service_type];
01318       Glib::ustring d = (*rit)[m_fuse_columns.m_service_domain];
01319
01320       if ( strcmp( n.c_str(), name) == 0 &&
01321            strcmp( t.c_str(), type) == 0 &&
01322            strcmp( d.c_str(), domain) == 0 )
01323         {
01324           m_fuse_tree_store->erase(rit);
01325         }
01326     }
01327
01328   m_ftw->remove_fountain_service(name);
01329   m_filw->remove_fountain_service(name);
01330 }