Fawkes API  Fawkes Development Version
fuse_viewer_gui.cpp
1 
2 /***************************************************************************
3  * fuse_viewer_gui.cpp - Fuse (network camera) Viewer Gui
4  *
5  * Created: Thu Dec 18 14:16:23 2008
6  * Copyright 2008-2009 Christof Rath <c.rath@student.tugraz.at>
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_viewer_gui.h"
24 
25 #include <gui_utils/avahi_dispatcher.h>
26 #include <core/exception.h>
27 #include <fvwidgets/fuse_image_list_widget.h>
28 #include <fvwidgets/image_widget.h>
29 #include <fvcams/net.h>
30 
31 #include <cstring>
32 
33 using namespace fawkes;
34 using namespace firevision;
35 
36 /** @class FuseViewerGtkWindow "fuse_viewer_gui.h"
37  * Fawkes network camera viewer.
38  *
39  * Currently the image refreshes 300ms after the retrieval and display of the
40  * last refresh (e.g. every 300ms in an ideal system)
41  * The FUSE list doesn't get updated (due to a bug?), restarting the fvfountain
42  * plugin on the remote host does the job.
43  *
44  * @author Christof Rath
45  */
46 
47 /** Constructor.
48  * @param cobject C base object
49  * @param builder Gtk::Builder
50  */
52  const Glib::RefPtr<Gtk::Builder> builder)
53  : Gtk::Window(cobject)
54 {
55  builder->get_widget("swFuseList", __image_list_scroll);
56  builder->get_widget("vpImage", __image_viewport);
57  builder->get_widget("afSaveType", __save_box);
58  builder->get_widget("fcbSaveTo", __save_filechooser);
59  builder->get_widget("cbtAutoSave", __auto_save);
60  builder->get_widget("btSaveImage", __save_btn);
61  builder->get_widget("stb", __statusbar);
62 
63  __img_list_widget = Gtk::manage(new FuseImageListWidget());
64  __img_list_widget->image_selected().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_fuse_image_selected) );
65 // __img_list_widget->set_auto_update(true, 1);
66  __image_list_scroll->add(*__img_list_widget);
67 
68  __save_type = Gtk::manage(new Gtk::ComboBoxText);
69  __save_box->add(*__save_type);
70 
71  std::vector<Gdk::PixbufFormat> fmts = Gdk::Pixbuf::get_formats();
72  std::vector<Gdk::PixbufFormat>::const_iterator it = fmts.begin();
73 #if GTK_VERSION_GE(3,0)
74  __save_type->append("Don't save");
75 #else
76  __save_type->append_text("Don't save");
77 #endif
78  for (; it != fmts.end(); ++it) {
79  if ((*it).is_writable()) {
80 #if GTK_VERSION_GE(3,0)
81  __save_type->append((*it).get_name());
82 #else
83  __save_type->append_text((*it).get_name());
84 #endif
85  }
86  }
87 
88  __save_type->set_active(0);
89  __save_type->set_sensitive(false);
90  __save_type->signal_changed().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_save_type_change) );
91  __auto_save->signal_toggled().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_auto_save_cbt_change) );
92  __save_btn->signal_clicked().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_save_image_clicked) );
93  show_all_children();
94 
95  __cur_service_name = "";
96  __img_num = 0;
97  __img_widget = NULL;
98  __cam = NULL;
99 
100  set_status("");
101 
102  __avahi_thread = new AvahiThread();
103  __avahi_dispatcher = new AvahiDispatcher;
104 
105  __avahi_dispatcher->signal_service_added().connect( sigc::mem_fun( *this, &FuseViewerGtkWindow::on_service_added ) );
106  __avahi_dispatcher->signal_service_removed().connect( sigc::mem_fun( *this, &FuseViewerGtkWindow::on_service_removed ) );
107 
108  __avahi_thread->watch_service("_fountain._tcp", __avahi_dispatcher);
109  __avahi_thread->start();
110 }
111 
112 /** Destructor. */
114 {
115  delete __avahi_thread;
116  delete __avahi_dispatcher;
117 }
118 
119 /** Signal handler called after AvahiThread detects a new NetworkService */
120 void
121 FuseViewerGtkWindow::on_service_added(fawkes::NetworkService* service)
122 {
123  const char* name = service->name();
124  const char* host = service->host();
125 
126  __host_service_map[host] = name;
127  __img_list_widget->add_fountain_service(
128  name,
129  host,
130  service->port());
131 }
132 
133 /** Signal handler called after AvahiThread detects a NetworkService removal */
134 void
135 FuseViewerGtkWindow::on_service_removed( fawkes::NetworkService* service )
136 {
137  __img_list_widget->remove_fountain_service( service->name() );
138 
139  if (__cur_service_name == service->name()) {
140  close_image();
141  }
142 
143  std::map<std::string, std::string>::const_iterator it = __host_service_map.begin();
144  for (; it != __host_service_map.end(); ++it) {
145  if (__cur_service_name == it->second) {
146  __host_service_map.erase(it->first);
147  break;
148  }
149  }
150 }
151 
152 /** Signal handler that is called when an image is selected in the image list */
153 void
154 FuseViewerGtkWindow::on_fuse_image_selected()
155 {
156  __img_list_widget->set_sensitive(Gtk::SENSITIVITY_OFF);
157  std::string host;
158  unsigned short port;
159  std::string image_id;
160  bool compression;
161 
162  __img_list_widget->get_selected_image(host, port, image_id, compression);
163 
164  close_image();
165 
166  try {
167  __cam = new NetworkCamera( host.c_str(), port, image_id.c_str(), compression );
168  __cam->open();
169  __cam->start();
170  __cur_service_name = __host_service_map[host];
171 
172  __img_widget = new ImageWidget(__cam, 300);
173  __image_viewport->add(*__img_widget);
174  __image_viewport->set_size_request(__cam->pixel_width(), __cam->pixel_height());
175  show_all_children();
176  __save_type->set_sensitive(Gtk::SENSITIVITY_ON);
177 
178  set_status(image_id, host, port);
179  }
180  catch (Exception& e) {
181  __cam = NULL;
182  e.print_trace();
183  }
184 
185  __img_list_widget->set_sensitive(Gtk::SENSITIVITY_ON);
186 }
187 
188 /** Signal handler that is called if the 'Auto save' checkbox status changes */
189 void
190 FuseViewerGtkWindow::on_auto_save_cbt_change()
191 {
192  if (__auto_save->get_active()) {
193  __save_btn->set_sensitive(false);
194 
195  __img_widget->save_on_refresh_cam(true,
196  __save_filechooser->get_current_folder(),
197  __save_type->get_active_text(),
198  __img_num);
199  }
200  else {
201  __img_widget->save_on_refresh_cam(false);
202  __img_num = __img_widget->get_image_num();
203 
204  __save_btn->set_sensitive(true);
205  }
206 }
207 
208 /** Signal handler that is called when the fileformat to save images changes */
209 void
210 FuseViewerGtkWindow::on_save_type_change()
211 {
212  if (__save_type->get_active_row_number()) {
213  __auto_save->set_sensitive(true);
214 
215  if (__auto_save->get_active()) __img_num = __img_widget->get_image_num();
216  on_auto_save_cbt_change();
217  }
218  else {
219  __auto_save->set_active(false);
220  __auto_save->set_sensitive(false);
221  __save_btn->set_sensitive(false);
222  }
223 }
224 
225 /** Signal handler that is called when the 'Save image' button is pressed */
226 void
227 FuseViewerGtkWindow::on_save_image_clicked()
228 {
229  char *ctmp;
230  if (asprintf(&ctmp, "%s/%06u.%s", __save_filechooser->get_current_folder().c_str(),
231  ++__img_num, __save_type->get_active_text().c_str()) != -1) {
232  Glib::ustring fn = ctmp;
233  free(ctmp);
234 
235  __img_widget->save_image(fn, __save_type->get_active_text());
236  } else {
237  printf("Could not save file, asprintf() ran out of memory");
238  }
239 }
240 
241 /**
242  * Sets the current status (to the statusbar)
243  * @param img_id the id of the current selected image
244  * @param host the host that provides the image
245  * @param port the port to transfer the image
246  */
247 void
248 FuseViewerGtkWindow::set_status(std::string img_id, std::string host, unsigned short port)
249 {
250  if (!img_id.length()) {
251  __statusbar->push(Glib::ustring("Not connected."));
252  }
253  else {
254  char *ctmp = NULL;
255  if (asprintf(&ctmp, "Host: %s:%u\tId: %s",
256  host.c_str(), port, img_id.c_str())) {
257  __statusbar->push(Glib::ustring(ctmp));
258  free(ctmp);
259  }
260  }
261 }
262 
263 /** Closes the image and the camera */
264 void
265 FuseViewerGtkWindow::close_image()
266 {
267  if (__img_widget) {
268  __image_viewport->remove();
269  delete __img_widget;
270  __img_widget = NULL;
271  __save_type->set_sensitive(Gtk::SENSITIVITY_OFF);
272  }
273 
274  if (__cam) {
275  __cam->stop();
276  __cam->close();
277  delete __cam;
278  __cam = NULL;
279  }
280 
281  set_status("");
282 }
283 
Glib::Dispatcher & image_selected()
Access the Dispatcher that is signalled when a new image is selected in the list of images...
virtual unsigned int pixel_height()
Height of image in pixels.
Definition: net.cpp:351
This class is an image container to display fawkes cameras (or image buffers) inside a Gtk::Container...
Definition: image_widget.h:45
Avahi dispatcher.
This widget displays all available Fuse images in a tree view.
Fawkes library namespace.
void add_fountain_service(const char *name, const char *host_name, uint32_t port)
Call this method when new Fountain services are discovered.
const char * host() const
Get host of service.
Definition: service.cpp:368
virtual void open()
Open the camera.
Definition: net.cpp:196
bool get_selected_image(std::string &host_name, unsigned short &port, std::string &image_id, bool &compression)
Get the host name, port, and image id of the selected image.
unsigned short int port() const
Get port of service.
Definition: service.cpp:378
sigc::signal< void, NetworkService * > signal_service_removed()
Get "service remove" signal.
virtual ~FuseViewerGtkWindow()
Destructor.
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual void start()
Start image transfer from the camera.
Definition: net.cpp:219
bool save_image(std::string filename, Glib::ustring type) const
Saves the current content of the Image.
void watch_service(const char *service_type, ServiceBrowseHandler *h)
Add a result handler.
virtual unsigned int pixel_width()
Width of image in pixels.
Definition: net.cpp:341
Avahi main thread.
Definition: avahi_thread.h:54
void save_on_refresh_cam(bool enabled, std::string path="", Glib::ustring type="", unsigned int img_num=0)
Saves the content of the image on every refresh.
Representation of a service announced or found via service discovery (i.e.
Definition: service.h:37
virtual void close()
Close camera.
Definition: net.cpp:311
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:619
virtual void stop()
Stop image transfer from the camera.
Definition: net.cpp:225
unsigned int get_image_num()
Returns the latest image number.
FuseViewerGtkWindow(BaseObjectType *cobject, const Glib::RefPtr< Gtk::Builder > builder)
Constructor.
void remove_fountain_service(const char *name)
Call this method when a Fountain service vanishes.
Network camera.
Definition: net.h:42
sigc::signal< void, NetworkService * > signal_service_added()
Get "service added" signal.
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:511
const char * name() const
Get name of service.
Definition: service.cpp:312