fuse_viewer_gui.cpp

00001
00002 /***************************************************************************
00003  *  fuse_viewer_gui.cpp -  Fuse (network camera) Viewer Gui
00004  *
00005  *  Created: Thu Dec 18 14:16:23 2008
00006  *  Copyright  2008-2009  Christof Rath <c.rath@student.tugraz.at>
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022
00023 #include "fuse_viewer_gui.h"
00024
00025 #include <gui_utils/avahi_dispatcher.h>
00026 #include <core/exception.h>
00027 #include <fvwidgets/fuse_image_list_widget.h>
00028 #include <fvwidgets/image_widget.h>
00029 #include <cams/net.h>
00030
00031 #include <cstring>
00032
00033 using namespace fawkes;
00034 
00035 /** @class FuseViewerGtkWindow fuse_viewer_gui.h  <tools/fuse_viewer/fuse_viewer_gui.h>
00036  * Fawkes network camera viewer.
00037  *
00038  * Currently the image refreshes 300ms after the retrieval and display of the
00039  * last refresh (e.g. every 300ms in an ideal system)
00040  * The FUSE list doesn't get updated (due to a bug?), restarting the fvfountain
00041  * plugin on the remote host does the job.
00042  *
00043  * @author Christof Rath
00044  */
00045 
00046 /** Constructor.
00047  * @param cobject C base object
00048  * @param ref_xml Glade XML
00049  */
00050 FuseViewerGtkWindow::FuseViewerGtkWindow(BaseObjectType* cobject,
00051                                        const Glib::RefPtr<Gnome::Glade::Xml> ref_xml)
00052   : Gtk::Window(cobject)
00053 {
00054   ref_xml->get_widget("swFuseList",  __image_list_scroll);
00055   ref_xml->get_widget("vpImage",     __image_viewport);
00056   ref_xml->get_widget("afSaveType",  __save_box);
00057   ref_xml->get_widget("fcbSaveTo",   __save_filechooser);
00058   ref_xml->get_widget("cbtAutoSave", __auto_save);
00059   ref_xml->get_widget("btSaveImage", __save_btn);
00060   ref_xml->get_widget("stb",         __statusbar);
00061
00062   __img_list_widget = Gtk::manage(new FuseImageListWidget());
00063   __img_list_widget->image_selected().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_fuse_image_selected) );
00064 //  __img_list_widget->set_auto_update(true, 1);
00065   __image_list_scroll->add(*__img_list_widget);
00066
00067   __save_type = Gtk::manage(new Gtk::ComboBoxText);
00068   __save_box->add(*__save_type);
00069
00070   Gdk::Pixbuf::SListHandle_PixbufFormat fmts = Gdk::Pixbuf::get_formats();
00071   Gdk::Pixbuf::SListHandle_PixbufFormat::const_iterator it = fmts.begin();
00072   __save_type->append_text("Don't save");
00073   for (; it != fmts.end(); ++it) {
00074     if ((*it).is_writable()) {
00075       __save_type->append_text((*it).get_name());
00076     }
00077   }
00078
00079   __save_type->set_active(0);
00080   __save_type->set_sensitive(false);
00081   __save_type->signal_changed().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_save_type_change) );
00082   __auto_save->signal_toggled().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_auto_save_cbt_change) );
00083   __save_btn->signal_clicked().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_save_image_clicked) );
00084   show_all_children();
00085
00086   __cur_service_name = "";
00087   __img_num          = 0;
00088   __img_widget       = NULL;
00089   __cam              = NULL;
00090
00091   set_status("");
00092
00093   __avahi_thread = new AvahiThread();
00094   __avahi_dispatcher = new AvahiDispatcher;
00095
00096   __avahi_dispatcher->signal_service_added().connect( sigc::mem_fun( *this, &FuseViewerGtkWindow::on_service_added ) );
00097   __avahi_dispatcher->signal_service_removed().connect( sigc::mem_fun( *this, &FuseViewerGtkWindow::on_service_removed ) );
00098
00099   __avahi_thread->watch_service("_fountain._tcp", __avahi_dispatcher);
00100   __avahi_thread->start();
00101 }
00102 
00103 /** Destructor. */
00104 FuseViewerGtkWindow::~FuseViewerGtkWindow()
00105 {
00106   delete __avahi_thread;
00107   delete __avahi_dispatcher;
00108 }
00109 
00110 /** Signal handler called after AvahiThread detects a new NetworkService */
00111 void
00112 FuseViewerGtkWindow::on_service_added(fawkes::NetworkService* service)
00113 {
00114   const char* name = service->name();
00115   const char* host = service->host();
00116
00117   __host_service_map[host] = name;
00118   __img_list_widget->add_fountain_service(
00119       name,
00120       host,
00121       service->port());
00122 }
00123 
00124 /** Signal handler called after AvahiThread detects a NetworkService removal */
00125 void
00126 FuseViewerGtkWindow::on_service_removed( fawkes::NetworkService* service )
00127 {
00128   __img_list_widget->remove_fountain_service( service->name() );
00129
00130   if (__cur_service_name == service->name()) {
00131     close_image();
00132   }
00133
00134   std::map<std::string, std::string>::const_iterator it = __host_service_map.begin();
00135   for (; it != __host_service_map.end(); ++it) {
00136     if (__cur_service_name == it->second) {
00137       __host_service_map.erase(it->first);
00138       break;
00139     }
00140   }
00141 }
00142 
00143 /** Signal handler that is called when an image is selected in the image list */
00144 void
00145 FuseViewerGtkWindow::on_fuse_image_selected()
00146 {
00147   __img_list_widget->set_sensitive(Gtk::SENSITIVITY_OFF);
00148   std::string host;
00149   unsigned short port;
00150   std::string image_id;
00151   bool compression;
00152
00153   __img_list_widget->get_selected_image(host, port, image_id, compression);
00154
00155   close_image();
00156
00157   try {
00158     __cam = new NetworkCamera( host.c_str(), port, image_id.c_str(), compression );
00159     __cam->open();
00160     __cam->start();
00161     __cur_service_name = __host_service_map[host];
00162
00163     __img_widget = new ImageWidget(__cam, 300);
00164     __image_viewport->add(*__img_widget);
00165     __image_viewport->set_size_request(__cam->pixel_width(), __cam->pixel_height());
00166     show_all_children();
00167     __save_type->set_sensitive(Gtk::SENSITIVITY_ON);
00168
00169     set_status(image_id, host, port);
00170   }
00171   catch (Exception& e) {
00172     __cam = NULL;
00173     e.print_trace();
00174   }
00175
00176   __img_list_widget->set_sensitive(Gtk::SENSITIVITY_ON);
00177 }
00178 
00179 /** Signal handler that is called if the 'Auto save' checkbox status changes */
00180 void
00181 FuseViewerGtkWindow::on_auto_save_cbt_change()
00182 {
00183   if (__auto_save->get_active()) {
00184     __save_btn->set_sensitive(false);
00185
00186     __img_widget->save_on_refresh_cam(true,
00187         __save_filechooser->get_current_folder(),
00188         __save_type->get_active_text(),
00189         __img_num);
00190   }
00191   else {
00192     __img_widget->save_on_refresh_cam(false);
00193     __img_num = __img_widget->get_image_num();
00194
00195     __save_btn->set_sensitive(true);
00196   }
00197 }
00198 
00199 /** Signal handler that is called when the fileformat to save images changes */
00200 void
00201 FuseViewerGtkWindow::on_save_type_change()
00202 {
00203   if (__save_type->get_active_row_number()) {
00204     __auto_save->set_sensitive(true);
00205
00206     if (__auto_save->get_active()) __img_num = __img_widget->get_image_num();
00207     on_auto_save_cbt_change();
00208   }
00209   else {
00210     __auto_save->set_active(false);
00211     __auto_save->set_sensitive(false);
00212     __save_btn->set_sensitive(false);
00213   }
00214 }
00215 
00216 /** Signal handler that is called when the 'Save image' button is pressed */
00217 void
00218 FuseViewerGtkWindow::on_save_image_clicked()
00219 {
00220   char *ctmp;
00221   if (asprintf(&ctmp, "%s/%06u.%s", __save_filechooser->get_current_folder().c_str(),
00222                ++__img_num, __save_type->get_active_text().c_str()) != -1) {
00223     Glib::ustring fn = ctmp;
00224     free(ctmp);
00225
00226     __img_widget->save_image(fn, __save_type->get_active_text());
00227   } else {
00228     printf("Could not save file, asprintf() ran out of memory");
00229   }
00230 }
00231 
00232 /**
00233  * Sets the current status (to the statusbar)
00234  * @param img_id the id of the current selected image
00235  * @param host the host that provides the image
00236  * @param port the port to transfer the image
00237  */
00238 void
00239 FuseViewerGtkWindow::set_status(std::string img_id, std::string host, unsigned short port)
00240 {
00241   if (!img_id.length()) {
00242     __statusbar->push(Glib::ustring("Not connected."));
00243   }
00244   else {
00245     char *ctmp = NULL;
00246     if (asprintf(&ctmp, "Host: %s:%u\tId: %s",
00247                  host.c_str(), port, img_id.c_str())) {
00248       __statusbar->push(Glib::ustring(ctmp));
00249       free(ctmp);
00250     }
00251   }
00252 }
00253 
00254 /** Closes the image and the camera */
00255 void
00256 FuseViewerGtkWindow::close_image()
00257 {
00258   if (__img_widget) {
00259     __image_viewport->remove();
00260     delete __img_widget;
00261     __img_widget = NULL;
00262     __save_type->set_sensitive(Gtk::SENSITIVITY_OFF);
00263   }
00264
00265   if (__cam) {
00266     __cam->stop();
00267     __cam->close();
00268     delete __cam;
00269     __cam = NULL;
00270   }
00271
00272   set_status("");
00273 }
00274