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 <core/exception.h>
26 #include <fvcams/net.h>
27 #include <fvwidgets/fuse_image_list_widget.h>
28 #include <fvwidgets/image_widget.h>
29 #include <gui_utils/avahi_dispatcher.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(
65  sigc::mem_fun(*this, &FuseViewerGtkWindow::on_fuse_image_selected));
66  // img_list_widget_->set_auto_update(true, 1);
67  image_list_scroll_->add(*img_list_widget_);
68 
69  save_type_ = Gtk::manage(new Gtk::ComboBoxText);
70  save_box_->add(*save_type_);
71 
72  std::vector<Gdk::PixbufFormat> fmts = Gdk::Pixbuf::get_formats();
73  std::vector<Gdk::PixbufFormat>::const_iterator it = fmts.begin();
74 #if GTK_VERSION_GE(3, 0)
75  save_type_->append("Don't save");
76 #else
77  save_type_->append_text("Don't save");
78 #endif
79  for (; it != fmts.end(); ++it) {
80  if ((*it).is_writable()) {
81 #if GTK_VERSION_GE(3, 0)
82  save_type_->append((*it).get_name());
83 #else
84  save_type_->append_text((*it).get_name());
85 #endif
86  }
87  }
88 
89  save_type_->set_active(0);
90  save_type_->set_sensitive(false);
91  save_type_->signal_changed().connect(
92  sigc::mem_fun(*this, &FuseViewerGtkWindow::on_save_type_change));
93  auto_save_->signal_toggled().connect(
94  sigc::mem_fun(*this, &FuseViewerGtkWindow::on_auto_save_cbt_change));
95  save_btn_->signal_clicked().connect(
96  sigc::mem_fun(*this, &FuseViewerGtkWindow::on_save_image_clicked));
97  show_all_children();
98 
99  cur_service_name_ = "";
100  img_num_ = 0;
101  img_widget_ = NULL;
102  cam_ = NULL;
103 
104  set_status("");
105 
106  avahi_thread_ = new AvahiThread();
107  avahi_dispatcher_ = new AvahiDispatcher;
108 
109  avahi_dispatcher_->signal_service_added().connect(
110  sigc::mem_fun(*this, &FuseViewerGtkWindow::on_service_added));
111  avahi_dispatcher_->signal_service_removed().connect(
112  sigc::mem_fun(*this, &FuseViewerGtkWindow::on_service_removed));
113 
114  avahi_thread_->watch_service("_fountain._tcp", avahi_dispatcher_);
115  avahi_thread_->start();
116 }
117 
118 /** Destructor. */
120 {
121  delete avahi_thread_;
122  delete avahi_dispatcher_;
123 }
124 
125 /** Signal handler called after AvahiThread detects a new NetworkService */
126 void
127 FuseViewerGtkWindow::on_service_added(fawkes::NetworkService *service)
128 {
129  const char *name = service->name();
130  const char *host = service->host();
131 
132  host_service_map_[host] = name;
133  img_list_widget_->add_fountain_service(name, host, service->port());
134 }
135 
136 /** Signal handler called after AvahiThread detects a NetworkService removal */
137 void
138 FuseViewerGtkWindow::on_service_removed(fawkes::NetworkService *service)
139 {
140  img_list_widget_->remove_fountain_service(service->name());
141 
142  if (cur_service_name_ == service->name()) {
143  close_image();
144  }
145 
146  std::map<std::string, std::string>::const_iterator it = host_service_map_.begin();
147  for (; it != host_service_map_.end(); ++it) {
148  if (cur_service_name_ == it->second) {
149  host_service_map_.erase(it->first);
150  break;
151  }
152  }
153 }
154 
155 /** Signal handler that is called when an image is selected in the image list */
156 void
157 FuseViewerGtkWindow::on_fuse_image_selected()
158 {
159  img_list_widget_->set_sensitive(false);
160  std::string host;
161  unsigned short port;
162  std::string image_id;
163  bool compression;
164 
165  img_list_widget_->get_selected_image(host, port, image_id, compression);
166 
167  close_image();
168 
169  try {
170  cam_ = new NetworkCamera(host.c_str(), port, image_id.c_str(), compression);
171  cam_->open();
172  cam_->start();
173  cur_service_name_ = host_service_map_[host];
174 
175  img_widget_ = new ImageWidget(cam_, 300);
176  image_viewport_->add(*img_widget_);
177  image_viewport_->set_size_request(cam_->pixel_width(), cam_->pixel_height());
178  show_all_children();
179  save_type_->set_sensitive(true);
180 
181  set_status(image_id, host, port);
182  } catch (Exception &e) {
183  cam_ = NULL;
184  e.print_trace();
185  }
186 
187  img_list_widget_->set_sensitive(true);
188 }
189 
190 /** Signal handler that is called if the 'Auto save' checkbox status changes */
191 void
192 FuseViewerGtkWindow::on_auto_save_cbt_change()
193 {
194  if (auto_save_->get_active()) {
195  save_btn_->set_sensitive(false);
196 
197  img_widget_->save_on_refresh_cam(true,
198  save_filechooser_->get_current_folder(),
199  save_type_->get_active_text(),
200  img_num_);
201  } else {
202  img_widget_->save_on_refresh_cam(false);
203  img_num_ = img_widget_->get_image_num();
204 
205  save_btn_->set_sensitive(true);
206  }
207 }
208 
209 /** Signal handler that is called when the fileformat to save images changes */
210 void
211 FuseViewerGtkWindow::on_save_type_change()
212 {
213  if (save_type_->get_active_row_number()) {
214  auto_save_->set_sensitive(true);
215 
216  if (auto_save_->get_active())
217  img_num_ = img_widget_->get_image_num();
218  on_auto_save_cbt_change();
219  } else {
220  auto_save_->set_active(false);
221  auto_save_->set_sensitive(false);
222  save_btn_->set_sensitive(false);
223  }
224 }
225 
226 /** Signal handler that is called when the 'Save image' button is pressed */
227 void
228 FuseViewerGtkWindow::on_save_image_clicked()
229 {
230  char *ctmp;
231  if (asprintf(&ctmp,
232  "%s/%06u.%s",
233  save_filechooser_->get_current_folder().c_str(),
234  ++img_num_,
235  save_type_->get_active_text().c_str())
236  != -1) {
237  Glib::ustring fn = ctmp;
238  free(ctmp);
239 
240  img_widget_->save_image(fn, save_type_->get_active_text());
241  } else {
242  printf("Could not save file, asprintf() ran out of memory");
243  }
244 }
245 
246 /**
247  * Sets the current status (to the statusbar)
248  * @param img_id the id of the current selected image
249  * @param host the host that provides the image
250  * @param port the port to transfer the image
251  */
252 void
253 FuseViewerGtkWindow::set_status(std::string img_id, std::string host, unsigned short port)
254 {
255  if (!img_id.length()) {
256  statusbar_->push(Glib::ustring("Not connected."));
257  } else {
258  char *ctmp = NULL;
259  if (asprintf(&ctmp, "Host: %s:%u\tId: %s", host.c_str(), port, img_id.c_str())) {
260  statusbar_->push(Glib::ustring(ctmp));
261  free(ctmp);
262  }
263  }
264 }
265 
266 /** Closes the image and the camera */
267 void
268 FuseViewerGtkWindow::close_image()
269 {
270  if (img_widget_) {
271  image_viewport_->remove();
272  delete img_widget_;
273  img_widget_ = NULL;
274  save_type_->set_sensitive(false);
275  }
276 
277  if (cam_) {
278  cam_->stop();
279  cam_->close();
280  delete cam_;
281  cam_ = NULL;
282  }
283 
284  set_status("");
285 }
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:342
This class is an image container to display fawkes cameras (or image buffers) inside a Gtk::Container...
Definition: image_widget.h:42
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:401
virtual void open()
Open the camera.
Definition: net.cpp:188
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:410
sigc::signal< void, NetworkService * > signal_service_removed()
Get "service remove" signal.
virtual ~FuseViewerGtkWindow()
Destructor.
Base class for exceptions in Fawkes.
Definition: exception.h:35
virtual void start()
Start image transfer from the camera.
Definition: net.cpp:212
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:332
Avahi main thread.
Definition: avahi_thread.h:53
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:302
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:601
virtual void stop()
Stop image transfer from the camera.
Definition: net.cpp:218
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:40
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:499
const char * name() const
Get name of service.
Definition: service.cpp:349