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) noexcept
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 }
Select a layer from a colormap and render it to a Gtk::Image.
void fuse_connection_died() noexcept
Connection died.
void set_remote_lut_list_trv(Gtk::TreeView *lut_list)
Set the TreeView for the list of remote LUTs.
void set_local_layer_selector(Gtk::Scale *scl)
Assign a Scale to switch between the layers of the loal colormap.
void fuse_inbound_received(firevision::FuseNetworkMessage *m) noexcept
Message received.
void set_current_colormap(firevision::YuvColormap *colormap)
Set the current colormap.
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 fuse_connection_established() noexcept
Connection has been established.
void set_local_img(Gtk::Image *img_local)
Set the Image to display the local LUT.
void remove_fountain_service(const char *name)
Tell the widget that a service is not available any more.
virtual ~FuseTransferWidget()
Destructor.
void set_upload_btn(Gtk::Button *btn_upload)
Set the button to trigger the LUT upload.
FuseTransferWidget()
Constructor.
void set_remote_layer_selector(Gtk::Scale *scl)
Assign a Scale to switch between the layers of the remote colormap.
void set_download_btn(Gtk::Button *btn_download)
Set the button to trigger the LUT download.
void set_local_lut_list_trv(Gtk::TreeView *lut_list)
Set the TreeView for the list of local LUTs.
void fuse_invalid_server_version(uint32_t local_version, uint32_t remote_version) noexcept
Invalid version string received.
Base class for exceptions in Fawkes.
Definition: exception.h:36
void print_trace() noexcept
Prints trace to stderr.
Definition: exception.cpp:601
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
void join()
Join the thread.
Definition: thread.cpp:597
void cancel()
Cancel a thread.
Definition: thread.cpp:646
void enqueue(FuseNetworkMessage *m)
Enqueue message.
void connect()
Connect.
void disconnect()
Disconnect.
FUSE lookup table content.
unsigned char * buffer() const
Get buffer.
unsigned int height() const
Height of LUT.
unsigned int depth() const
Depth of LUT.
unsigned int width() const
Width of LUT.
FUSE lookup table list content.
bool has_next()
Check if another LUT info is available.
FUSE_lutinfo_t * next()
Get next LUT info.
FUSE Network Message.
Definition: fuse_message.h:40
YUV Colormap.
Definition: yuvcm.h:36
virtual unsigned int height() const
Get height of colormap.
Definition: yuvcm.cpp:330
virtual unsigned int depth() const
Get depth of colormap.
Definition: yuvcm.cpp:336
virtual unsigned int width() const
Get width of colormap.
Definition: yuvcm.cpp:324
Fawkes library namespace.
LUT description message.
Definition: fuse.h:162
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:163
LUT info message.
Definition: fuse.h:179
uint32_t height
height of LUT
Definition: fuse.h:182
uint32_t bytes_per_cell
bytes per cell
Definition: fuse.h:184
uint32_t width
width of LUT
Definition: fuse.h:181
uint32_t depth
depth of LUT
Definition: fuse.h:183
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:180