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 
25 #include "colormap_viewer_widget.h"
26 
27 #include <fvmodels/color/lookuptable.h>
28 #include <fvutils/net/fuse_client.h>
29 #include <fvutils/net/fuse_lut_content.h>
30 #include <fvutils/net/fuse_lutlist_content.h>
31 #include <fvutils/net/fuse_message.h>
32 #include <netinet/in.h>
33 
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(
55  sigc::mem_fun(*this, &FuseTransferWidget::update_local_lut_list));
56  m_signal_update_remote_lut_list.connect(
57  sigc::mem_fun(*this, &FuseTransferWidget::update_remote_lut_list));
58  m_signal_get_lut_list.connect(sigc::mem_fun(*this, &FuseTransferWidget::get_lut_list));
59  m_signal_delete_client.connect(sigc::mem_fun(*this, &FuseTransferWidget::delete_clients));
60  m_signal_update_remote_lut.connect(sigc::mem_fun(*this, &FuseTransferWidget::update_remote_lut));
61 
62  m_new_clients.clear();
63  m_delete_clients.clear();
64 
65  m_cur_client.active = false;
66 
67  m_btn_upload = 0;
68  m_btn_download = 0;
69  m_img_local = 0;
70  m_img_remote = 0;
71  m_trv_local_lut_list = 0;
72  m_trv_remote_lut_list = 0;
73 }
74 
75 /** Destructor. */
77 {
78  delete m_local_colormap_viewer;
79  delete m_remote_colormap_viewer;
80 
81  m_new_clients.lock();
82  while (m_new_clients.size() != 0) {
83  FuseClient *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  m_cur_client.active = false;
94  m_delete_clients.push_locked(m_cur_client.client);
95  delete_clients();
96  }
97 }
98 
99 /** Tell the widget that a new FUSE service has been discovered.
100  * The widget will then attempt to connect to the host and list the available LUTs.
101  * @param name the name of the service
102  * @param host_name the name of the host the service is running on
103  * @param port the port
104  */
105 void
106 FuseTransferWidget::add_fountain_service(const char *name, const char *host_name, uint16_t port)
107 {
108  ClientData data;
109  data.client = 0;
110  data.service_name = std::string(name);
111  data.host_name = std::string(host_name);
112  data.port = port;
113  data.active = false;
114 
115  m_new_clients.push_locked(data);
116  m_signal_get_lut_list();
117 }
118 
119 /** Tell the widget that a service is not available any more.
120  * All entries in the list of remote LUTs for the corresponding service will be deleted.
121  * @param name the name of the service
122  */
123 void
125 {
126  Gtk::TreeModel::Children children = m_remote_lut_list->children();
127  Gtk::TreeModel::Children::iterator iter = children.begin();
128  while (iter != children.end()) {
129  Gtk::TreeModel::Row row = *iter;
130  if (row[m_lut_record.service_name] == Glib::ustring(name)) {
131  iter = m_local_lut_list->erase(iter);
132  m_local_lut_list->row_deleted(m_local_lut_list->get_path(iter));
133  } else {
134  ++iter;
135  }
136  }
137 }
138 
139 /** Set the current colormap.
140  * The current colormap is the local colormap that is currently trained.
141  * @param colormap the colormap
142  */
143 void
145 {
146  m_current_colormap = colormap;
147 
148  // delete existing "Current" row
149  Gtk::TreeModel::Children children = m_local_lut_list->children();
150  Gtk::TreeModel::Children::iterator iter = children.begin();
151  while (iter != children.end()) {
152  Gtk::TreeModel::Row row = *iter;
153  if (row[m_lut_record.filename] == "Current") {
154  iter = m_local_lut_list->erase(iter);
155  m_local_lut_list->row_deleted(m_local_lut_list->get_path(iter));
156  } else {
157  ++iter;
158  }
159  }
160 
161  Gtk::TreeModel::Row row = *m_local_lut_list->prepend();
162  row[m_lut_record.filename] = "Current";
163  row[m_lut_record.width] = colormap->width();
164  row[m_lut_record.height] = colormap->height();
165  row[m_lut_record.depth] = colormap->depth();
166 }
167 
168 void
169 FuseTransferWidget::update_local_lut_list()
170 {
171  if (m_trv_local_lut_list) {
172  m_trv_local_lut_list->queue_draw();
173  }
174 }
175 
176 void
177 FuseTransferWidget::update_remote_lut_list()
178 {
179  if (m_trv_remote_lut_list) {
180  m_trv_remote_lut_list->queue_draw();
181  }
182 }
183 
184 /** Set the button to trigger the LUT upload.
185  * @param btn the upload button
186  */
187 void
189 {
190  m_btn_upload = btn;
191  m_btn_upload->signal_clicked().connect(sigc::mem_fun(*this, &FuseTransferWidget::upload_lut));
192 }
193 
194 /** Set the button to trigger the LUT download.
195  * @param btn the download button
196  */
197 void
199 {
200  m_btn_download = btn;
201 }
202 
203 /** Set the Image to display the local LUT.
204  * @param img the local LUT image
205  */
206 void
208 {
209  m_img_local = img;
210  m_local_colormap_viewer->set_colormap_img(m_img_local);
211 }
212 
213 /** Assign a Scale to switch between the layers of the loal colormap.
214  * @param scl a Gtk::Scale
215  */
216 void
218 {
219  m_local_colormap_viewer->set_layer_selector(scl);
220 }
221 
222 /** Set the Image to display the remote LUT.
223  * @param img the remote LUT Image
224  */
225 void
227 {
228  m_img_remote = img;
229  m_remote_colormap_viewer->set_colormap_img(m_img_remote);
230 }
231 
232 /** Assign a Scale to switch between the layers of the remote colormap.
233  * @param scl a Gtk::Scale
234  */
235 void
237 {
238  m_remote_colormap_viewer->set_layer_selector(scl);
239 }
240 
241 /** Set the TreeView for the list of local LUTs.
242  * @param trv the TreeView for the list of local LUTs
243  */
244 void
246 {
247  m_trv_local_lut_list = trv;
248  m_trv_local_lut_list->set_model(m_local_lut_list);
249  m_trv_local_lut_list->append_column("Filename", m_lut_record.filename);
250  m_trv_local_lut_list->append_column("Width", m_lut_record.width);
251  m_trv_local_lut_list->append_column("Height", m_lut_record.height);
252  m_trv_local_lut_list->append_column("Depth", m_lut_record.depth);
253  // m_trv_local_lut_list->append_column("BPC", m_lut_record.bytes_per_cell);
254 
255  m_trv_local_lut_list->signal_cursor_changed().connect(
256  sigc::mem_fun(*this, &FuseTransferWidget::local_lut_selected));
257 }
258 
259 /** Set the TreeView for the list of remote LUTs.
260  * @param trv the TreeView for the list of remote LUTs
261  */
262 void
264 {
265  m_trv_remote_lut_list = trv;
266  m_trv_remote_lut_list->set_model(m_remote_lut_list);
267  m_trv_remote_lut_list->append_column("Host", m_lut_record.host_name);
268  // m_trv_remote_lut_list->append_column("Port", m_lut_record.port);
269  m_trv_remote_lut_list->append_column("ID", m_lut_record.lut_id);
270  m_trv_remote_lut_list->append_column("Width", m_lut_record.width);
271  m_trv_remote_lut_list->append_column("Height", m_lut_record.height);
272  m_trv_remote_lut_list->append_column("Depth", m_lut_record.depth);
273  m_trv_remote_lut_list->append_column("BPC", m_lut_record.bytes_per_cell);
274 
275  m_trv_remote_lut_list->signal_cursor_changed().connect(
276  sigc::mem_fun(*this, &FuseTransferWidget::remote_lut_selected));
277 }
278 
279 void
280 FuseTransferWidget::get_lut_list()
281 {
282  if (m_cur_client.active)
283  // communication in progress
284  {
285  return;
286  }
287 
288  m_new_clients.lock();
289  if (m_new_clients.size() == 0) {
290  m_new_clients.unlock();
291  return;
292  }
293 
294  m_cur_client = m_new_clients.front();
295  m_cur_client.active = true;
296  m_new_clients.pop();
297  m_new_clients.unlock();
298 
299  try {
300  m_cur_client.client = new FuseClient(m_cur_client.host_name.c_str(), m_cur_client.port, this);
301  m_cur_client.client->connect();
302  m_cur_client.client->start();
303  m_cur_client.client->enqueue(FUSE_MT_GET_LUT_LIST);
304  } catch (Exception &e) {
305  e.print_trace();
306  m_cur_client.client->cancel();
307  m_cur_client.client->join();
308  delete m_cur_client.client;
309  m_cur_client.active = false;
310  }
311 }
312 
313 void
314 FuseTransferWidget::delete_clients()
315 {
316  m_delete_clients.lock();
317  while (m_delete_clients.size() != 0) {
318  FuseClient *c = m_delete_clients.front();
319  m_delete_clients.pop();
320 
321  c->disconnect();
322  c->cancel();
323  c->join();
324  delete c;
325  }
326  m_delete_clients.unlock();
327 }
328 
329 void
330 FuseTransferWidget::update_local_lut()
331 {
332  if (!m_img_local) {
333  return;
334  }
335 
336  m_local_colormap_viewer->draw();
337 }
338 
339 void
340 FuseTransferWidget::update_remote_lut()
341 {
342  if (!m_img_remote) {
343  return;
344  }
345 
346  m_remote_colormap_viewer->draw();
347 }
348 
349 void
350 FuseTransferWidget::upload_lut()
351 {
352  if (!m_local_colormap) {
353  return;
354  }
355 
356  // get current selection remote
357  Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_remote_lut_list->get_selection();
358 
359  if (1 != selection->count_selected_rows()) {
360  printf("No remote lut selected\n");
361  return;
362  }
363 
364  Gtk::TreeModel::iterator i = selection->get_selected();
365  Glib::ustring hostname = (*i)[m_lut_record.host_name];
366  unsigned int port = (*i)[m_lut_record.port];
367  Glib::ustring lut_id = (*i)[m_lut_record.lut_id];
368 
369  printf("sending lut to %s:%u id %s\n", hostname.c_str(), port, lut_id.c_str());
370 
371  FuseLutContent *lut_content = new FuseLutContent(lut_id.c_str(),
372  m_local_colormap->get_buffer(),
373  m_local_colormap->width(),
374  m_local_colormap->height(),
375  m_local_colormap->depth(),
376  1 /* bytes per cell*/);
377 
378  // create FUSE client
379  FuseClient *client = new FuseClient(hostname.c_str(), port, this);
380 
381  try {
382  client->connect();
383  client->start();
384 
385  // send lut
386  client->enqueue(new FuseNetworkMessage(FUSE_MT_SET_LUT, lut_content));
387 
388  // mark FUSE client for deletion
389  m_delete_clients.push_locked(client);
390  } catch (Exception &e) {
391  e.print_trace();
392  client->cancel();
393  client->join();
394  delete client;
395  }
396 }
397 
398 void
399 FuseTransferWidget::local_lut_selected()
400 {
401  Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_local_lut_list->get_selection();
402  if (selection->count_selected_rows() != 1) {
403  return;
404  }
405 
406  Gtk::TreeModel::iterator it = selection->get_selected();
407  Glib::ustring filename = (*it)[m_lut_record.filename];
408 
409  if (filename == "Current") {
410  m_local_colormap = m_current_colormap;
411  } else {
412  // TODO
413  }
414 
415  m_local_colormap_viewer->set_colormap(m_local_colormap);
416  update_local_lut();
417 }
418 
419 void
420 FuseTransferWidget::remote_lut_selected()
421 {
422  Glib::RefPtr<Gtk::TreeSelection> selection = m_trv_remote_lut_list->get_selection();
423  if (selection->count_selected_rows() != 1) {
424  return;
425  }
426 
427  Gtk::TreeModel::iterator it = selection->get_selected();
428  Glib::ustring host_name = (*it)[m_lut_record.host_name];
429  unsigned int port = (*it)[m_lut_record.port];
430  Glib::ustring lut_id = (*it)[m_lut_record.lut_id];
431 
432  FuseClient *c = new FuseClient(host_name.c_str(), port, this);
433  try {
434  c->connect();
435  c->start();
436 
437  FUSE_lutdesc_message_t *lut_desc =
439  memset(lut_desc, 0, sizeof(FUSE_lutdesc_message_t));
440  strncpy(lut_desc->lut_id, lut_id.c_str(), LUT_ID_MAX_LENGTH - 1);
441  c->enqueue(FUSE_MT_GET_LUT, lut_desc, sizeof(FUSE_lutdesc_message_t));
442 
443  m_delete_clients.push_locked(c);
444  } catch (Exception &e) {
445  e.print_trace();
446  c->cancel();
447  c->join();
448  delete c;
449  }
450 }
451 
452 void
454  uint32_t remote_version) throw()
455 {
456  printf("Invalid versions: local: %u remote: %u\n", local_version, remote_version);
457 }
458 
459 void
461 {
462 }
463 
464 void
466 {
467  if (m_cur_client.active) {
468  m_delete_clients.push_locked(m_cur_client.client);
469  m_cur_client.active = false;
470  }
471 
472  m_signal_delete_client();
473 }
474 
475 void
477 {
478  switch (m->type()) {
479  case FUSE_MT_LUT_LIST:
480  try {
481  FuseLutListContent *content = m->msgc<FuseLutListContent>();
482  if (content->has_next()) {
483  while (content->has_next()) {
484  // check whether there already is an entry for the given lut_id
485  FUSE_lutinfo_t *lut_info = content->next();
486  char lut_id[LUT_ID_MAX_LENGTH + 1];
487  lut_id[LUT_ID_MAX_LENGTH] = '\0';
488  strncpy(lut_id, lut_info->lut_id, LUT_ID_MAX_LENGTH);
489 
490  Gtk::TreeModel::Children children = m_remote_lut_list->children();
491  Gtk::TreeModel::Children::iterator iter = children.begin();
492  while (iter != children.end()) {
493  Gtk::TreeModel::Row row = *iter;
494  if (row[m_lut_record.lut_id] == Glib::ustring(lut_id)) {
495  iter = m_remote_lut_list->erase(iter);
496  } else {
497  ++iter;
498  }
499  }
500 
501  Gtk::TreeModel::Row row = *m_remote_lut_list->append();
502  row[m_lut_record.service_name] = Glib::ustring(m_cur_client.service_name);
503  row[m_lut_record.host_name] = Glib::ustring(m_cur_client.host_name);
504  row[m_lut_record.port] = m_cur_client.port;
505  row[m_lut_record.lut_id] = Glib::ustring(lut_id);
506  row[m_lut_record.width] = ntohl(lut_info->width);
507  row[m_lut_record.height] = ntohl(lut_info->height);
508  row[m_lut_record.depth] = ntohl(lut_info->depth);
509  row[m_lut_record.bytes_per_cell] = ntohl(lut_info->bytes_per_cell);
510  }
511  }
512  delete content;
513  } catch (Exception &e) {
514  e.print_trace();
515  }
516 
517  m_delete_clients.push_locked(m_cur_client.client);
518  m_cur_client.active = false;
519 
520  m_signal_update_remote_lut_list();
521  m_signal_get_lut_list();
522  m_signal_delete_client();
523 
524  break;
525 
526  case FUSE_MT_LUT:
527  try {
528  FuseLutContent *lut_content = m->msgc<FuseLutContent>();
529 
530  if (m_remote_colormap) {
531  delete m_remote_colormap;
532  }
533 
534  if (lut_content->width() != 256 || lut_content->height() != 256) {
535  m_signal_delete_client();
536  break;
537  }
538 
539  m_remote_colormap = new YuvColormap(lut_content->depth());
540  m_remote_colormap->set(lut_content->buffer());
541 
542  delete lut_content;
543  } catch (Exception &e) {
544  e.print_trace();
545  }
546  m_remote_colormap_viewer->set_colormap(m_remote_colormap);
547  m_signal_update_remote_lut();
548  m_signal_delete_client();
549 
550  break;
551 
552  case FUSE_MT_SET_LUT_FAILED: printf("LUT upload failed\n");
553 
554  case FUSE_MT_SET_LUT_SUCCEEDED:
555  printf("LUT upload succeeded\n");
556  m_signal_delete_client();
557  break;
558 
559  default: printf("Unhandled message type\n");
560  }
561 }
uint32_t bytes_per_cell
bytes per cell
Definition: fuse.h:184
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:324
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:182
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:181
YUV Colormap.
Definition: yuvcm.h:35
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:39
Base class for exceptions in Fawkes.
Definition: exception.h:35
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:178
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:180
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:194
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:646
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:601
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:163
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:597
void fuse_connection_died()
Connection died.
uint32_t depth
depth of LUT
Definition: fuse.h:183
virtual unsigned int height() const
Get height of colormap.
Definition: yuvcm.cpp:330
Select a layer from a colormap and render it to a Gtk::Image.
LUT description message.
Definition: fuse.h:161
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:499