Fawkes API  Fawkes Development Version
fuse_transfer_widget.cpp
1 
2 /***************************************************************************
3  * fuse_transfer_widget.cpp - Fuse transfer widget
4  *
5  * Created: Wed Mar 19 17:25:10 2008
6  * Copyright 2008 Daniel Beck
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include "fuse_transfer_widget.h"
24 #include "colormap_viewer_widget.h"
25 
26 #include <fvutils/net/fuse_client.h>
27 #include <fvutils/net/fuse_message.h>
28 #include <fvutils/net/fuse_lut_content.h>
29 #include <fvutils/net/fuse_lutlist_content.h>
30 
31 #include <fvmodels/color/lookuptable.h>
32 
33 #include <netinet/in.h>
34 #include <cstring>
35 
36 using namespace fawkes;
37 using namespace firevision;
38 
39 /** @class FuseTransferWidget "fuse_transfer_widget.h"
40  * This class implements the logic for a GUI that allows to transfer LUTs via FUSE.
41  *
42  * @author Daniel Beck
43  */
44 
45 /** Constructor. */
47 {
48  m_local_colormap_viewer = new ColormapViewerWidget();
49  m_remote_colormap_viewer = new ColormapViewerWidget();
50 
51  m_local_lut_list = Gtk::ListStore::create(m_lut_record);
52  m_remote_lut_list = Gtk::ListStore::create(m_lut_record);
53 
54  m_signal_update_local_lut_list.connect( sigc::mem_fun( *this, &FuseTransferWidget::update_local_lut_list) );
55  m_signal_update_remote_lut_list.connect( sigc::mem_fun( *this, &FuseTransferWidget::update_remote_lut_list) );
56  m_signal_get_lut_list.connect( sigc::mem_fun( *this, &FuseTransferWidget::get_lut_list) );
57  m_signal_delete_client.connect( sigc::mem_fun( *this, &FuseTransferWidget::delete_clients) );
58  m_signal_update_remote_lut.connect( sigc::mem_fun( *this, &FuseTransferWidget::update_remote_lut) );
59 
60  m_new_clients.clear();
61  m_delete_clients.clear();
62 
63  m_cur_client.active = false;
64 
65  m_btn_upload = 0;
66  m_btn_download = 0;
67  m_img_local = 0;
68  m_img_remote = 0;
69  m_trv_local_lut_list = 0;
70  m_trv_remote_lut_list = 0;
71 }
72 
73 /** Destructor. */
75 {
76  delete m_local_colormap_viewer;
77  delete m_remote_colormap_viewer;
78 
79  FuseClient* c;
80  m_new_clients.lock();
81  while (m_new_clients.size() != 0)
82  {
83  c = m_new_clients.front().client;
84  m_new_clients.pop();
85  c->disconnect();
86  c->cancel();
87  c->join();
88  delete c;
89  }
90  m_new_clients.unlock();
91 
92  if (m_cur_client.active)
93  {
94  m_cur_client.active = false;
95  m_delete_clients.push_locked(m_cur_client.client);
96  delete_clients();
97  }
98 }
99 
100 /** Tell the widget that a new FUSE service has been discovered.
101  * The widget will then attempt to connect to the host and list the available LUTs.
102  * @param name the name of the service
103  * @param host_name the name of the host the service is running on
104  * @param port the port
105  */
106 void
108  const char* host_name,
109  uint16_t port )
110 {
111  ClientData data;
112  data.client = 0;
113  data.service_name = std::string(name);
114  data.host_name = std::string(host_name);
115  data.port = port;
116  data.active = false;
117 
118  m_new_clients.push_locked(data);
119  m_signal_get_lut_list();
120 }
121 
122 /** Tell the widget that a service is not available any more.
123  * All entries in the list of remote LUTs for the corresponding service will be deleted.
124  * @param name the name of the service
125  */
126 void
128 {
129  Gtk::TreeModel::Children children = m_remote_lut_list->children();
130  Gtk::TreeModel::Children::iterator iter = children.begin();
131  while( iter != children.end() )
132  {
133  Gtk::TreeModel::Row row = *iter;
134  if (row[m_lut_record.service_name] == Glib::ustring(name))
135  {
136  iter = m_local_lut_list->erase(iter);
137  m_local_lut_list->row_deleted( m_local_lut_list->get_path(iter) );
138  }
139  else
140  {
141  ++iter;
142  }
143  }
144 }
145 
146 /** Set the current colormap.
147  * The current colormap is the local colormap that is currently trained.
148  * @param colormap the colormap
149  */
150 void
152 {
153  m_current_colormap = colormap;
154 
155  // delete existing "Current" row
156  Gtk::TreeModel::Children children = m_local_lut_list->children();
157  Gtk::TreeModel::Children::iterator iter = children.begin();
158  while ( iter != children.end() )
159  {
160  Gtk::TreeModel::Row row = *iter;
161  if (row[m_lut_record.filename] == "Current")
162  {
163  iter = m_local_lut_list->erase(iter);
164  m_local_lut_list->row_deleted( m_local_lut_list->get_path(iter) );
165  }
166  else
167  {
168  ++iter;
169  }
170  }
171 
172  Gtk::TreeModel::Row row = *m_local_lut_list->prepend();
173  row[m_lut_record.filename] = "Current";
174  row[m_lut_record.width] = colormap->width();
175  row[m_lut_record.height] = colormap->height();
176  row[m_lut_record.depth] = colormap->depth();
177 }
178 
179 void
180 FuseTransferWidget::update_local_lut_list()
181 {
182  if (m_trv_local_lut_list)
183  { m_trv_local_lut_list->queue_draw(); }
184 }
185 
186 void
187 FuseTransferWidget::update_remote_lut_list()
188 {
189  if (m_trv_remote_lut_list)
190  { m_trv_remote_lut_list->queue_draw(); }
191 }
192 
193 /** Set the button to trigger the LUT upload.
194  * @param btn the upload button
195  */
196 void
198 {
199  m_btn_upload = btn;
200  m_btn_upload->signal_clicked().connect( sigc::mem_fun( *this, &FuseTransferWidget::upload_lut) );
201 }
202 
203 /** Set the button to trigger the LUT download.
204  * @param btn the download button
205  */
206 void
208 {
209  m_btn_download = btn;
210 }
211 
212 /** Set the Image to display the local LUT.
213  * @param img the local LUT image
214  */
215 void
217 {
218  m_img_local = img;
219  m_local_colormap_viewer->set_colormap_img(m_img_local);
220 }
221 
222 /** Assign a Scale to switch between the layers of the loal colormap.
223  * @param scl a Gtk::Scale
224  */
225 void
227 {
228  m_local_colormap_viewer->set_layer_selector(scl);
229 }
230 
231 /** Set the Image to display the remote LUT.
232  * @param img the remote LUT Image
233  */
234 void
236 {
237  m_img_remote = img;
238  m_remote_colormap_viewer->set_colormap_img(m_img_remote);
239 }
240 
241 /** Assign a Scale to switch between the layers of the remote colormap.
242  * @param scl a Gtk::Scale
243  */
244 void
246 {
247  m_remote_colormap_viewer->set_layer_selector(scl);
248 }
249 
250 /** Set the TreeView for the list of local LUTs.
251  * @param trv the TreeView for the list of local LUTs
252  */
253 void
255 {
256  m_trv_local_lut_list = trv;
257  m_trv_local_lut_list->set_model(m_local_lut_list);
258  m_trv_local_lut_list->append_column("Filename", m_lut_record.filename);
259  m_trv_local_lut_list->append_column("Width", m_lut_record.width);
260  m_trv_local_lut_list->append_column("Height", m_lut_record.height);
261  m_trv_local_lut_list->append_column("Depth", m_lut_record.depth);
262  // m_trv_local_lut_list->append_column("BPC", m_lut_record.bytes_per_cell);
263 
264  m_trv_local_lut_list->signal_cursor_changed().connect( sigc::mem_fun( *this, &FuseTransferWidget::local_lut_selected) );
265 }
266 
267 /** Set the TreeView for the list of remote LUTs.
268  * @param trv the TreeView for the list of remote LUTs
269  */
270 void
272 {
273  m_trv_remote_lut_list = trv;
274  m_trv_remote_lut_list->set_model(m_remote_lut_list);
275  m_trv_remote_lut_list->append_column("Host", m_lut_record.host_name);
276  // m_trv_remote_lut_list->append_column("Port", m_lut_record.port);
277  m_trv_remote_lut_list->append_column("ID", m_lut_record.lut_id);
278  m_trv_remote_lut_list->append_column("Width", m_lut_record.width);
279  m_trv_remote_lut_list->append_column("Height", m_lut_record.height);
280  m_trv_remote_lut_list->append_column("Depth", m_lut_record.depth);
281  m_trv_remote_lut_list->append_column("BPC", m_lut_record.bytes_per_cell);
282 
283  m_trv_remote_lut_list->signal_cursor_changed().connect( sigc::mem_fun( *this, &FuseTransferWidget::remote_lut_selected) );
284 }
285 
286 void
287 FuseTransferWidget::get_lut_list()
288 {
289  if (m_cur_client.active)
290  // communication in progress
291  { return; }
292 
293  m_new_clients.lock();
294  if (m_new_clients.size() == 0)
295  {
296  m_new_clients.unlock();
297  return;
298  }
299 
300  m_cur_client = m_new_clients.front();
301  m_cur_client.active = true;
302  m_new_clients.pop();
303  m_new_clients.unlock();
304 
305  try
306  {
307  m_cur_client.client = new FuseClient( m_cur_client.host_name.c_str(),
308  m_cur_client.port, this );
309  m_cur_client.client->connect();
310  m_cur_client.client->start();
311  m_cur_client.client->enqueue(FUSE_MT_GET_LUT_LIST);
312  }
313  catch (Exception& e)
314  {
315  e.print_trace();
316  m_cur_client.client->cancel();
317  m_cur_client.client->join();
318  delete m_cur_client.client;
319  m_cur_client.active = false;
320  }
321 }
322 
323 void
324 FuseTransferWidget::delete_clients()
325 {
326  FuseClient* c;
327 
328  m_delete_clients.lock();
329  while (m_delete_clients.size() != 0)
330  {
331  c = m_delete_clients.front();
332  m_delete_clients.pop();
333 
334  c->disconnect();
335  c->cancel();
336  c->join();
337  delete c;
338  }
339  m_delete_clients.unlock();
340 }
341 
342 void
343 FuseTransferWidget::update_local_lut()
344 {
345  if ( !m_img_local )
346  { return; }
347 
348  m_local_colormap_viewer->draw();
349 }
350 
351 void
352 FuseTransferWidget::update_remote_lut()
353 {
354  if ( !m_img_remote )
355  { return; }
356 
357  m_remote_colormap_viewer->draw();
358 }
359 
360 void
361 FuseTransferWidget::upload_lut()
362 {
363  if ( !m_local_colormap )
364  { return; }
365 
366  // get current selection remote
367  Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_remote_lut_list->get_selection();
368 
369  if ( 1 != selection->count_selected_rows() )
370  {
371  printf("No remote lut selected\n");
372  return;
373  }
374 
375  Gtk::TreeModel::iterator i = selection->get_selected();
376  Glib::ustring hostname = (*i)[m_lut_record.host_name];
377  unsigned int port = (*i)[m_lut_record.port];
378  Glib::ustring lut_id = (*i)[m_lut_record.lut_id];
379 
380  printf("sending lut to %s:%d id %s\n", hostname.c_str(), port, lut_id.c_str());
381 
382  FuseLutContent* lut_content = new FuseLutContent( lut_id.c_str(),
383  m_local_colormap->get_buffer(),
384  m_local_colormap->width(),
385  m_local_colormap->height(),
386  m_local_colormap->depth(),
387  1 /* bytes per cell*/ );
388 
389  // create FUSE client
390  FuseClient* client = new FuseClient(hostname.c_str(), port, this);
391 
392  try
393  {
394  client->connect();
395  client->start();
396 
397  // send lut
398  client->enqueue( new FuseNetworkMessage(FUSE_MT_SET_LUT, lut_content) );
399 
400  // mark FUSE client for deletion
401  m_delete_clients.push_locked(client);
402  }
403  catch (Exception& e)
404  {
405  e.print_trace();
406  client->cancel();
407  client->join();
408  delete client;
409  }
410 }
411 
412 void
413 FuseTransferWidget::local_lut_selected()
414 {
415  Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_local_lut_list->get_selection();
416  if (selection->count_selected_rows() != 1)
417  { return; }
418 
419  Gtk::TreeModel::iterator it = selection->get_selected();
420  Glib::ustring filename = (*it)[m_lut_record.filename];
421 
422  if (filename == "Current")
423  {
424  m_local_colormap = m_current_colormap;
425  }
426  else
427  {
428  // TODO
429  }
430 
431  m_local_colormap_viewer->set_colormap(m_local_colormap);
432  update_local_lut();
433 }
434 
435 void
436 FuseTransferWidget::remote_lut_selected()
437 {
438  Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_remote_lut_list->get_selection();
439  if (selection->count_selected_rows() != 1)
440  { return; }
441 
442  Gtk::TreeModel::iterator it = selection->get_selected();
443  Glib::ustring host_name = (*it)[m_lut_record.host_name];
444  unsigned int port = (*it)[m_lut_record.port];
445  Glib::ustring lut_id = (*it)[m_lut_record.lut_id];
446 
447  FuseClient* c = new FuseClient(host_name.c_str(), port, this);
448  try
449  {
450  c->connect();
451  c->start();
452 
454  memset(lut_desc, 0, sizeof(FUSE_lutdesc_message_t));
455  strncpy(lut_desc->lut_id, lut_id.c_str(), LUT_ID_MAX_LENGTH);
456  c->enqueue(FUSE_MT_GET_LUT, lut_desc, sizeof(FUSE_lutdesc_message_t));
457 
458  m_delete_clients.push_locked(c);
459  }
460  catch (Exception& e)
461  {
462  e.print_trace();
463  c->cancel();
464  c->join();
465  delete c;
466  }
467 }
468 
469 void
471  uint32_t remote_version) throw()
472 {
473  printf("Invalid versions: local: %u remote: %u\n", local_version, remote_version);
474 }
475 
476 void
478 {
479 }
480 
481 void
483 {
484  if (m_cur_client.active)
485  {
486  m_delete_clients.push_locked(m_cur_client.client);
487  m_cur_client.active = false;
488  }
489 
490  m_signal_delete_client();
491 }
492 
493 void
495 {
496  switch ( m->type() )
497  {
498  case FUSE_MT_LUT_LIST:
499  try
500  {
501  FuseLutListContent* content = m->msgc<FuseLutListContent>();
502  if ( content->has_next() )
503  {
504  while ( content->has_next() )
505  {
506  // check whether there already is an entry for the given lut_id
507  FUSE_lutinfo_t* lut_info = content->next();
508  char lut_id[LUT_ID_MAX_LENGTH + 1];
509  lut_id[LUT_ID_MAX_LENGTH] = '\0';
510  strncpy(lut_id, lut_info->lut_id, LUT_ID_MAX_LENGTH);
511 
512  Gtk::TreeModel::Children children = m_remote_lut_list->children();
513  Gtk::TreeModel::Children::iterator iter = children.begin();
514  while ( iter != children.end() )
515  {
516  Gtk::TreeModel::Row row = *iter;
517  if ( row[m_lut_record.lut_id] == Glib::ustring(lut_id) )
518  { iter = m_remote_lut_list->erase(iter); }
519  else
520  { ++iter; }
521  }
522 
523  Gtk::TreeModel::Row row = *m_remote_lut_list->append();
524  row[m_lut_record.service_name] = Glib::ustring(m_cur_client.service_name);
525  row[m_lut_record.host_name] = Glib::ustring(m_cur_client.host_name);
526  row[m_lut_record.port] = m_cur_client.port;
527  row[m_lut_record.lut_id] = Glib::ustring(lut_id);
528  row[m_lut_record.width] = ntohl(lut_info->width);
529  row[m_lut_record.height] = ntohl(lut_info->height);
530  row[m_lut_record.depth] = ntohl(lut_info->depth);
531  row[m_lut_record.bytes_per_cell] = ntohl(lut_info->bytes_per_cell);
532  }
533  }
534  delete content;
535  }
536  catch (Exception& e)
537  {
538  e.print_trace();
539  }
540 
541  m_delete_clients.push_locked(m_cur_client.client);
542  m_cur_client.active = false;
543 
544  m_signal_update_remote_lut_list();
545  m_signal_get_lut_list();
546  m_signal_delete_client();
547 
548  break;
549 
550  case FUSE_MT_LUT:
551  try
552  {
553  FuseLutContent* lut_content = m->msgc<FuseLutContent>();
554 
555  if (m_remote_colormap)
556  { delete m_remote_colormap; }
557 
558  if ( lut_content->width() != 256 ||
559  lut_content->height() != 256 )
560  {
561  m_signal_delete_client();
562  break;
563  }
564 
565  m_remote_colormap = new YuvColormap( lut_content->depth() );
566  m_remote_colormap->set( lut_content->buffer() );
567 
568  delete lut_content;
569  }
570  catch (Exception& e)
571  {
572  e.print_trace();
573  }
574  m_remote_colormap_viewer->set_colormap(m_remote_colormap);
575  m_signal_update_remote_lut();
576  m_signal_delete_client();
577 
578  break;
579 
580  case FUSE_MT_SET_LUT_FAILED:
581  printf("LUT upload failed\n");
582 
583  case FUSE_MT_SET_LUT_SUCCEEDED:
584  printf("LUT upload succeeded\n");
585  m_signal_delete_client();
586  break;
587 
588  default:
589  printf("Unhandled message type\n");
590  }
591 }
uint32_t bytes_per_cell
bytes per cell
Definition: fuse.h:180
void fuse_connection_established()
Connection has been established.
void connect()
Connect.
void remove_fountain_service(const char *name)
Tell the widget that a service is not available any more.
FUSE lookup table content.
void disconnect()
Disconnect.
unsigned int depth() const
Depth of LUT.
void set_remote_layer_selector(Gtk::Scale *scl)
Assign a Scale to switch between the layers of the remote colormap.
void fuse_invalid_server_version(uint32_t local_version, uint32_t remote_version)
Invalid version string received.
virtual unsigned int width() const
Get width of colormap.
Definition: yuvcm.cpp:322
Fawkes library namespace.
void enqueue(FuseNetworkMessage *m)
Enqueue message.
unsigned int width() const
Width of LUT.
uint32_t height
height of LUT
Definition: fuse.h:178
FuseTransferWidget()
Constructor.
unsigned char * buffer() const
Get buffer.
FUSE_lutinfo_t * next()
Get next LUT info.
virtual ~FuseTransferWidget()
Destructor.
uint32_t width
width of LUT
Definition: fuse.h:177
YUV Colormap.
Definition: yuvcm.h:39
void set_remote_lut_list_trv(Gtk::TreeView *lut_list)
Set the TreeView for the list of remote LUTs.
unsigned int height() const
Height of LUT.
FUSE Network Message.
Definition: fuse_message.h:41
Base class for exceptions in Fawkes.
Definition: exception.h:36
void set_download_btn(Gtk::Button *btn_download)
Set the button to trigger the LUT download.
void set_local_img(Gtk::Image *img_local)
Set the Image to display the local LUT.
LUT info message.
Definition: fuse.h:175
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:176
FUSE lookup table list content.
void set_upload_btn(Gtk::Button *btn_upload)
Set the button to trigger the LUT upload.
virtual void set(unsigned int y, unsigned int u, unsigned int v, color_t c)
Set color class for given YUV value.
Definition: yuvcm.cpp:182
void fuse_inbound_received(firevision::FuseNetworkMessage *m)
Message received.
void set_current_colormap(firevision::YuvColormap *colormap)
Set the current colormap.
void cancel()
Cancel a thread.
Definition: thread.cpp:651
void add_fountain_service(const char *name, const char *host_name, uint16_t port)
Tell the widget that a new FUSE service has been discovered.
void set_remote_img(Gtk::Image *img_remote)
Set the Image to display the remote LUT.
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:619
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:161
virtual unsigned int depth() const
Get depth of colormap.
Definition: yuvcm.cpp:336
bool has_next()
Check if another LUT info is available.
void set_local_layer_selector(Gtk::Scale *scl)
Assign a Scale to switch between the layers of the loal colormap.
void join()
Join the thread.
Definition: thread.cpp:610
void fuse_connection_died()
Connection died.
uint32_t depth
depth of LUT
Definition: fuse.h:179
virtual unsigned int height() const
Get height of colormap.
Definition: yuvcm.cpp:329
Select a layer from a colormap and render it to a Gtk::Image.
LUT description message.
Definition: fuse.h:160
void set_local_lut_list_trv(Gtk::TreeView *lut_list)
Set the TreeView for the list of local LUTs.
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:511