fuse_transfer_widget.cpp

00001
00002 /***************************************************************************
00003  *  fuse_transfer_widget.cpp - Fuse transfer widget
00004  *
00005  *  Created: Wed Mar 19 17:25:10 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 <tools/firestation/fuse_transfer_widget.h>
00024 #include <tools/firestation/colormap_viewer_widget.h>
00025
00026 #include <fvutils/net/fuse_client.h>
00027 #include <fvutils/net/fuse_message.h>
00028 #include <fvutils/net/fuse_lut_content.h>
00029 #include <fvutils/net/fuse_lutlist_content.h>
00030
00031 #include <models/color/lookuptable.h>
00032
00033 #include <netinet/in.h>
00034 #include <cstring>
00035
00036 using namespace fawkes;
00037 
00038 /** @class FuseTransferWidget tools/firestation/fuse_transfer_widget.h
00039  * This class implements the logic for a GUI that allows to transfer LUTs via FUSE.
00040  *
00041  * @author Daniel Beck
00042  */
00043 
00044 /** Constructor. */
00045 FuseTransferWidget::FuseTransferWidget()
00046 {
00047   m_local_colormap_viewer  = new ColormapViewerWidget();
00048   m_remote_colormap_viewer = new ColormapViewerWidget();
00049
00050   m_local_lut_list  = Gtk::ListStore::create(m_lut_record);
00051   m_remote_lut_list = Gtk::ListStore::create(m_lut_record);
00052
00053   m_signal_update_local_lut_list.connect( sigc::mem_fun( *this, &FuseTransferWidget::update_local_lut_list) );
00054   m_signal_update_remote_lut_list.connect( sigc::mem_fun( *this, &FuseTransferWidget::update_remote_lut_list) );
00055   m_signal_get_lut_list.connect( sigc::mem_fun( *this, &FuseTransferWidget::get_lut_list) );
00056   m_signal_delete_client.connect( sigc::mem_fun( *this, &FuseTransferWidget::delete_clients) );
00057   m_signal_update_remote_lut.connect( sigc::mem_fun( *this, &FuseTransferWidget::update_remote_lut) );
00058
00059   m_new_clients.clear();
00060   m_delete_clients.clear();
00061
00062   m_cur_client.active = false;
00063
00064   m_btn_upload = 0;
00065   m_btn_download = 0;
00066   m_img_local = 0;
00067   m_img_remote = 0;
00068   m_trv_local_lut_list = 0;
00069   m_trv_remote_lut_list = 0;
00070 }
00071 
00072 /** Destructor. */
00073 FuseTransferWidget::~FuseTransferWidget()
00074 {
00075   delete m_local_colormap_viewer;
00076   delete m_remote_colormap_viewer;
00077
00078   FuseClient* c;
00079   m_new_clients.lock();
00080   while (m_new_clients.size() != 0)
00081     {
00082       c = m_new_clients.front().client;
00083       m_new_clients.pop();
00084       c->disconnect();
00085       c->cancel();
00086       c->join();
00087       delete c;
00088     }
00089   m_new_clients.unlock();
00090
00091   if (m_cur_client.active)
00092     {
00093       m_cur_client.active = false;
00094       m_delete_clients.push_locked(m_cur_client.client);
00095       delete_clients();
00096     }
00097 }
00098 
00099 /** Tell the widget that a new FUSE service has been discovered.
00100  * The widget will then attempt to connect to the host and list the available LUTs.
00101  * @param name the name of the service
00102  * @param host_name the name of the host the service is running on
00103  * @param port the port
00104  */
00105 void
00106 FuseTransferWidget::add_fountain_service( const char* name,
00107                                           const char* host_name,
00108                                           uint16_t port )
00109 {
00110   ClientData data;
00111   data.client = 0;
00112   data.service_name = std::string(name);
00113   data.host_name = std::string(host_name);
00114   data.port = port;
00115   data.active = false;
00116
00117   m_new_clients.push_locked(data);
00118   m_signal_get_lut_list();
00119 }
00120 
00121 /** Tell the widget that a service is not available any more.
00122  * All entries in the list of remote LUTs for the corresponding service will be deleted.
00123  * @param name the name of the service
00124  */
00125 void
00126 FuseTransferWidget::remove_fountain_service(const char* name)
00127 {
00128   Gtk::TreeModel::Children children = m_remote_lut_list->children();
00129   Gtk::TreeModel::Children::iterator iter = children.begin();
00130   while( iter != children.end() )
00131     {
00132       Gtk::TreeModel::Row row = *iter;
00133       if (row[m_lut_record.service_name] == Glib::ustring(name))
00134         {
00135           iter = m_local_lut_list->erase(iter);
00136           m_local_lut_list->row_deleted( m_local_lut_list->get_path(iter) );
00137         }
00138       else
00139         {
00140           ++iter;
00141         }
00142     }
00143 }
00144 
00145 /** Set the current colormap.
00146  * The current colormap is the local colormap that is currently trained.
00147  * @param colormap the colormap
00148  */
00149 void
00150 FuseTransferWidget::set_current_colormap(YuvColormap* colormap)
00151 {
00152   m_current_colormap = colormap;
00153
00154   // delete existing "Current" row
00155   Gtk::TreeModel::Children children = m_local_lut_list->children();
00156   Gtk::TreeModel::Children::iterator iter = children.begin();
00157   while ( iter != children.end() )
00158     {
00159       Gtk::TreeModel::Row row = *iter;
00160       if (row[m_lut_record.filename] == "Current")
00161         {
00162           iter = m_local_lut_list->erase(iter);
00163           m_local_lut_list->row_deleted( m_local_lut_list->get_path(iter) );
00164         }
00165       else
00166         {
00167           ++iter;
00168         }
00169     }
00170
00171   Gtk::TreeModel::Row row = *m_local_lut_list->prepend();
00172   row[m_lut_record.filename] = "Current";
00173   row[m_lut_record.width]    = colormap->width();
00174   row[m_lut_record.height]   = colormap->height();
00175   row[m_lut_record.depth]    = colormap->depth();
00176 }
00177
00178 void
00179 FuseTransferWidget::update_local_lut_list()
00180 {
00181   if (m_trv_local_lut_list)
00182     { m_trv_local_lut_list->queue_draw(); }
00183 }
00184
00185 void
00186 FuseTransferWidget::update_remote_lut_list()
00187 {
00188   if (m_trv_remote_lut_list)
00189     { m_trv_remote_lut_list->queue_draw(); }
00190 }
00191 
00192 /** Set the button to trigger the LUT upload.
00193  * @param btn the upload button
00194  */
00195 void
00196 FuseTransferWidget::set_upload_btn(Gtk::Button* btn)
00197 {
00198   m_btn_upload = btn;
00199   m_btn_upload->signal_clicked().connect( sigc::mem_fun( *this, &FuseTransferWidget::upload_lut) );
00200 }
00201 
00202 /** Set the button to trigger the LUT download.
00203  * @param btn the download button
00204  */
00205 void
00206 FuseTransferWidget::set_download_btn(Gtk::Button* btn)
00207 {
00208   m_btn_download = btn;
00209 }
00210 
00211 /** Set the Image to display the local LUT.
00212  * @param img the local LUT image
00213  */
00214 void
00215 FuseTransferWidget::set_local_img(Gtk::Image* img)
00216 {
00217   m_img_local = img;
00218   m_local_colormap_viewer->set_colormap_img(m_img_local);
00219 }
00220 
00221 /** Assign a Scale to switch between the layers of the loal colormap.
00222  * @param scl a Gtk::Scale
00223  */
00224 void
00225 FuseTransferWidget::set_local_layer_selector(Gtk::Scale* scl)
00226 {
00227   m_local_colormap_viewer->set_layer_selector(scl);
00228 }
00229 
00230 /** Set the Image to display the remote LUT.
00231  * @param img the remote LUT Image
00232  */
00233 void
00234 FuseTransferWidget::set_remote_img(Gtk::Image* img)
00235 {
00236   m_img_remote = img;
00237   m_remote_colormap_viewer->set_colormap_img(m_img_remote);
00238 }
00239 
00240 /** Assign a Scale to switch between the layers of the remote colormap.
00241  * @param scl a Gtk::Scale
00242  */
00243 void
00244 FuseTransferWidget::set_remote_layer_selector(Gtk::Scale* scl)
00245 {
00246   m_remote_colormap_viewer->set_layer_selector(scl);
00247 }
00248 
00249 /** Set the TreeView for the list of local LUTs.
00250  * @param trv the TreeView for the list of local LUTs
00251  */
00252 void
00253 FuseTransferWidget::set_local_lut_list_trv(Gtk::TreeView* trv)
00254 {
00255   m_trv_local_lut_list = trv;
00256   m_trv_local_lut_list->set_model(m_local_lut_list);
00257   m_trv_local_lut_list->append_column("Filename", m_lut_record.filename);
00258   m_trv_local_lut_list->append_column("Width", m_lut_record.width);
00259   m_trv_local_lut_list->append_column("Height", m_lut_record.height);
00260   m_trv_local_lut_list->append_column("Depth", m_lut_record.depth);
00261   //  m_trv_local_lut_list->append_column("BPC", m_lut_record.bytes_per_cell);
00262
00263   m_trv_local_lut_list->signal_cursor_changed().connect( sigc::mem_fun( *this, &FuseTransferWidget::local_lut_selected) );
00264 }
00265 
00266 /** Set the TreeView for the list of remote LUTs.
00267  * @param trv the TreeView for the list of remote LUTs
00268  */
00269 void
00270 FuseTransferWidget::set_remote_lut_list_trv(Gtk::TreeView* trv)
00271 {
00272   m_trv_remote_lut_list = trv;
00273   m_trv_remote_lut_list->set_model(m_remote_lut_list);
00274   m_trv_remote_lut_list->append_column("Host", m_lut_record.host_name);
00275   //  m_trv_remote_lut_list->append_column("Port", m_lut_record.port);
00276   m_trv_remote_lut_list->append_column("ID", m_lut_record.lut_id);
00277   m_trv_remote_lut_list->append_column("Width", m_lut_record.width);
00278   m_trv_remote_lut_list->append_column("Height", m_lut_record.height);
00279   m_trv_remote_lut_list->append_column("Depth", m_lut_record.depth);
00280   m_trv_remote_lut_list->append_column("BPC", m_lut_record.bytes_per_cell);
00281
00282   m_trv_remote_lut_list->signal_cursor_changed().connect( sigc::mem_fun( *this, &FuseTransferWidget::remote_lut_selected) );
00283 }
00284
00285 void
00286 FuseTransferWidget::get_lut_list()
00287 {
00288   if (m_cur_client.active)
00289     // communication in progress
00290     { return; }
00291
00292   m_new_clients.lock();
00293   if (m_new_clients.size() == 0)
00294     {
00295       m_new_clients.unlock();
00296       return;
00297     }
00298
00299   m_cur_client = m_new_clients.front();
00300   m_cur_client.active = true;
00301   m_new_clients.pop();
00302   m_new_clients.unlock();
00303
00304   try
00305     {
00306       m_cur_client.client = new FuseClient( m_cur_client.host_name.c_str(),
00307                                             m_cur_client.port, this );
00308       m_cur_client.client->connect();
00309       m_cur_client.client->start();
00310       m_cur_client.client->enqueue(FUSE_MT_GET_LUT_LIST);
00311     }
00312   catch (Exception& e)
00313     {
00314       e.print_trace();
00315       m_cur_client.client->cancel();
00316       m_cur_client.client->join();
00317       delete m_cur_client.client;
00318       m_cur_client.active = false;
00319     }
00320 }
00321
00322 void
00323 FuseTransferWidget::delete_clients()
00324 {
00325   FuseClient* c;
00326
00327   m_delete_clients.lock();
00328   while (m_delete_clients.size() != 0)
00329     {
00330       c = m_delete_clients.front();
00331       m_delete_clients.pop();
00332
00333       c->disconnect();
00334       c->cancel();
00335       c->join();
00336       delete c;
00337     }
00338   m_delete_clients.unlock();
00339 }
00340
00341 void
00342 FuseTransferWidget::update_local_lut()
00343 {
00344   if ( !m_img_local )
00345     { return; }
00346
00347   m_local_colormap_viewer->draw();
00348 }
00349
00350 void
00351 FuseTransferWidget::update_remote_lut()
00352 {
00353   if ( !m_img_remote )
00354     { return; }
00355
00356   m_remote_colormap_viewer->draw();
00357 }
00358
00359 void
00360 FuseTransferWidget::upload_lut()
00361 {
00362   if ( !m_local_colormap )
00363     { return; }
00364
00365   // get current selection remote
00366   Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_remote_lut_list->get_selection();
00367
00368   if ( 1 != selection->count_selected_rows() )
00369     {
00370       printf("No remote lut selected\n");
00371       return;
00372     }
00373
00374   Gtk::TreeModel::iterator i = selection->get_selected();
00375   Glib::ustring hostname = (*i)[m_lut_record.host_name];
00376   unsigned int port = (*i)[m_lut_record.port];
00377   Glib::ustring lut_id = (*i)[m_lut_record.lut_id];
00378
00379   printf("sending lut to %s:%d id %s\n", hostname.c_str(), port, lut_id.c_str());
00380
00381   FuseLutContent* lut_content = new FuseLutContent( lut_id.c_str(),
00382                                                     m_local_colormap->get_buffer(),
00383                                                     m_local_colormap->width(),
00384                                                     m_local_colormap->height(),
00385                                                     m_local_colormap->depth(),
00386                                                     1 /* bytes per cell*/ );
00387
00388   // create FUSE client
00389   FuseClient* client = new FuseClient(hostname.c_str(), port, this);
00390
00391   try
00392     {
00393       client->connect();
00394       client->start();
00395
00396       // send lut
00397       client->enqueue( new FuseNetworkMessage(FUSE_MT_SET_LUT, lut_content) );
00398
00399       // mark FUSE client for deletion
00400       m_delete_clients.push_locked(client);
00401     }
00402   catch (Exception& e)
00403     {
00404       e.print_trace();
00405       client->cancel();
00406       client->join();
00407       delete client;
00408     }
00409 }
00410
00411 void
00412 FuseTransferWidget::local_lut_selected()
00413 {
00414   Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_local_lut_list->get_selection();
00415   if (selection->count_selected_rows() != 1)
00416     { return; }
00417
00418   Gtk::TreeModel::iterator it = selection->get_selected();
00419   Glib::ustring filename = (*it)[m_lut_record.filename];
00420
00421   if (filename == "Current")
00422     {
00423       m_local_colormap = m_current_colormap;
00424     }
00425   else
00426     {
00427       // TODO
00428     }
00429
00430   m_local_colormap_viewer->set_colormap(m_local_colormap);
00431   update_local_lut();
00432 }
00433
00434 void
00435 FuseTransferWidget::remote_lut_selected()
00436 {
00437   Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_remote_lut_list->get_selection();
00438   if (selection->count_selected_rows() != 1)
00439     { return; }
00440
00441   Gtk::TreeModel::iterator it = selection->get_selected();
00442   Glib::ustring host_name = (*it)[m_lut_record.host_name];
00443   unsigned int port       = (*it)[m_lut_record.port];
00444   Glib::ustring lut_id    = (*it)[m_lut_record.lut_id];
00445
00446   FuseClient* c = new FuseClient(host_name.c_str(), port, this);
00447   try
00448     {
00449       c->connect();
00450       c->start();
00451
00452       FUSE_lutdesc_message_t* lut_desc = (FUSE_lutdesc_message_t*) malloc( sizeof(FUSE_lutdesc_message_t));
00453       memset(lut_desc, 0, sizeof(FUSE_lutdesc_message_t));
00454       strncpy(lut_desc->lut_id, lut_id.c_str(), LUT_ID_MAX_LENGTH);
00455       c->enqueue(FUSE_MT_GET_LUT, lut_desc, sizeof(FUSE_lutdesc_message_t));
00456
00457       m_delete_clients.push_locked(c);
00458     }
00459   catch (Exception& e)
00460     {
00461       e.print_trace();
00462       c->cancel();
00463       c->join();
00464       delete c;
00465     }
00466 }
00467
00468 void
00469 FuseTransferWidget::fuse_invalid_server_version(uint32_t local_version,
00470                                                 uint32_t remote_version) throw()
00471 {
00472   printf("Invalid versions: local: %u   remote: %u\n", local_version, remote_version);
00473 }
00474
00475 void
00476 FuseTransferWidget::fuse_connection_established () throw()
00477 {
00478 }
00479
00480 void
00481 FuseTransferWidget::fuse_connection_died() throw()
00482 {
00483   if (m_cur_client.active)
00484     {
00485       m_delete_clients.push_locked(m_cur_client.client);
00486       m_cur_client.active = false;
00487     }
00488
00489   m_signal_delete_client();
00490 }
00491
00492 void
00493 FuseTransferWidget::fuse_inbound_received (FuseNetworkMessage *m) throw()
00494 {
00495   switch ( m->type() )
00496     {
00497     case FUSE_MT_LUT_LIST:
00498       try
00499         {
00500           FuseLutListContent* content = m->msgc<FuseLutListContent>();
00501           if ( content->has_next() )
00502             {
00503               while ( content->has_next() )
00504                 {
00505                   // check whether there already is an entry for the given lut_id
00506                   FUSE_lutinfo_t* lut_info = content->next();
00507                   char lut_id[LUT_ID_MAX_LENGTH + 1];
00508                   lut_id[LUT_ID_MAX_LENGTH] = '\0';
00509                   strncpy(lut_id, lut_info->lut_id, LUT_ID_MAX_LENGTH);
00510
00511                   Gtk::TreeModel::Children children = m_remote_lut_list->children();
00512                   Gtk::TreeModel::Children::iterator iter = children.begin();
00513                   while ( iter != children.end() )
00514                     {
00515                       Gtk::TreeModel::Row row = *iter;
00516                       if ( row[m_lut_record.lut_id] == Glib::ustring(lut_id) )
00517                         { iter = m_remote_lut_list->erase(iter); }
00518                       else
00519                         { ++iter; }
00520                     }
00521
00522                   Gtk::TreeModel::Row row = *m_remote_lut_list->append();
00523                   row[m_lut_record.service_name]   = Glib::ustring(m_cur_client.service_name);
00524                   row[m_lut_record.host_name]      = Glib::ustring(m_cur_client.host_name);
00525                   row[m_lut_record.port]           = m_cur_client.port;
00526                   row[m_lut_record.lut_id]         = Glib::ustring(lut_id);
00527                   row[m_lut_record.width]          = ntohl(lut_info->width);
00528                   row[m_lut_record.height]         = ntohl(lut_info->height);
00529                   row[m_lut_record.depth]          = ntohl(lut_info->depth);
00530                   row[m_lut_record.bytes_per_cell] = ntohl(lut_info->bytes_per_cell);
00531                 }
00532             }
00533           delete content;
00534         }
00535       catch (Exception& e)
00536         {
00537           e.print_trace();
00538         }
00539
00540       m_delete_clients.push_locked(m_cur_client.client);
00541       m_cur_client.active = false;
00542
00543       m_signal_update_remote_lut_list();
00544       m_signal_get_lut_list();
00545       m_signal_delete_client();
00546
00547       break;
00548
00549     case FUSE_MT_LUT:
00550       try
00551         {
00552           FuseLutContent* lut_content = m->msgc<FuseLutContent>();
00553
00554           if (m_remote_colormap)
00555             { delete m_remote_colormap; }
00556
00557           if ( lut_content->width() != 256 ||
00558                lut_content->height() != 256 )
00559             {
00560               m_signal_delete_client();
00561               break;
00562             }
00563
00564           m_remote_colormap = new YuvColormap( lut_content->depth() );
00565           m_remote_colormap->set( lut_content->buffer() );
00566
00567           delete lut_content;
00568         }
00569       catch (Exception& e)
00570         {
00571           e.print_trace();
00572         }
00573       m_remote_colormap_viewer->set_colormap(m_remote_colormap);
00574       m_signal_update_remote_lut();
00575       m_signal_delete_client();
00576
00577       break;
00578
00579     case FUSE_MT_SET_LUT_FAILED:
00580       printf("LUT upload failed\n");
00581
00582     case FUSE_MT_SET_LUT_SUCCEEDED:
00583       printf("LUT upload succeeded\n");
00584       m_signal_delete_client();
00585       break;
00586
00587     default:
00588       printf("Unhandled message type\n");
00589     }
00590 }