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
36using namespace fawkes;
37using 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 */
105void
106FuseTransferWidget::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 */
123void
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 */
143void
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
168void
169FuseTransferWidget::update_local_lut_list()
170{
171 if (m_trv_local_lut_list) {
172 m_trv_local_lut_list->queue_draw();
173 }
174}
175
176void
177FuseTransferWidget::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 */
187void
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 */
197void
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 */
206void
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 */
216void
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 */
225void
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 */
235void
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 */
244void
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 */
262void
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
279void
280FuseTransferWidget::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
313void
314FuseTransferWidget::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
329void
330FuseTransferWidget::update_local_lut()
331{
332 if (!m_img_local) {
333 return;
334 }
335
336 m_local_colormap_viewer->draw();
337}
338
339void
340FuseTransferWidget::update_remote_lut()
341{
342 if (!m_img_remote) {
343 return;
344 }
345
346 m_remote_colormap_viewer->draw();
347}
348
349void
350FuseTransferWidget::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
398void
399FuseTransferWidget::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
419void
420FuseTransferWidget::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
452void
454 uint32_t remote_version) noexcept
455{
456 printf("Invalid versions: local: %u remote: %u\n", local_version, remote_version);
457}
458
459void
461{
462}
463
464void
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
475void
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 draw(unsigned int layer=0)
Draw the colormap.
void set_colormap_img(Gtk::Image *img)
Set the image to render into.
void set_colormap(firevision::Colormap *cm)
Set the colormap to display.
void set_layer_selector(Gtk::Scale *scl)
Set the selector widget to choose the layer of the colormap which gets rendered.
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 clear()
Clear the queue.
Definition: lock_queue.h:153
void push_locked(const Type &x)
Push element to queue with lock protection.
Definition: lock_queue.h:135
void lock() const
Lock queue.
Definition: lock_queue.h:114
void unlock() const
Unlock list.
Definition: lock_queue.h:128
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 char * get_buffer() const
Get the raw buffer of this colormap.
Definition: yuvcm.cpp:231
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