Fawkes API  Fawkes Development Version
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 <fvcams/net.h>
00030 
00031 #include <cstring>
00032 
00033 using namespace fawkes;
00034 using namespace firevision;
00035 
00036 /** @class FuseViewerGtkWindow "fuse_viewer_gui.h"
00037  * Fawkes network camera viewer.
00038  *
00039  * Currently the image refreshes 300ms after the retrieval and display of the
00040  * last refresh (e.g. every 300ms in an ideal system)
00041  * The FUSE list doesn't get updated (due to a bug?), restarting the fvfountain
00042  * plugin on the remote host does the job.
00043  *
00044  * @author Christof Rath
00045  */
00046 
00047 /** Constructor.
00048  * @param cobject C base object
00049  * @param builder Gtk::Builder
00050  */
00051 FuseViewerGtkWindow::FuseViewerGtkWindow(BaseObjectType* cobject,
00052                                          const Glib::RefPtr<Gtk::Builder> builder)
00053   : Gtk::Window(cobject)
00054 {
00055   builder->get_widget("swFuseList",  __image_list_scroll);
00056   builder->get_widget("vpImage",     __image_viewport);
00057   builder->get_widget("afSaveType",  __save_box);
00058   builder->get_widget("fcbSaveTo",   __save_filechooser);
00059   builder->get_widget("cbtAutoSave", __auto_save);
00060   builder->get_widget("btSaveImage", __save_btn);
00061   builder->get_widget("stb",         __statusbar);
00062 
00063   __img_list_widget = Gtk::manage(new FuseImageListWidget());
00064   __img_list_widget->image_selected().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_fuse_image_selected) );
00065 //  __img_list_widget->set_auto_update(true, 1);
00066   __image_list_scroll->add(*__img_list_widget);
00067 
00068   __save_type = Gtk::manage(new Gtk::ComboBoxText);
00069   __save_box->add(*__save_type);
00070 
00071   std::vector<Gdk::PixbufFormat> fmts = Gdk::Pixbuf::get_formats();
00072   std::vector<Gdk::PixbufFormat>::const_iterator it = fmts.begin();
00073 #if GTK_VERSION_GE(3,0)
00074   __save_type->append("Don't save");
00075 #else
00076   __save_type->append_text("Don't save");
00077 #endif
00078   for (; it != fmts.end(); ++it) {
00079     if ((*it).is_writable()) {
00080 #if GTK_VERSION_GE(3,0)
00081       __save_type->append((*it).get_name());
00082 #else
00083       __save_type->append_text((*it).get_name());
00084 #endif
00085     }
00086   }
00087 
00088   __save_type->set_active(0);
00089   __save_type->set_sensitive(false);
00090   __save_type->signal_changed().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_save_type_change) );
00091   __auto_save->signal_toggled().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_auto_save_cbt_change) );
00092   __save_btn->signal_clicked().connect( sigc::mem_fun(*this, &FuseViewerGtkWindow::on_save_image_clicked) );
00093   show_all_children();
00094 
00095   __cur_service_name = "";
00096   __img_num          = 0;
00097   __img_widget       = NULL;
00098   __cam              = NULL;
00099 
00100   set_status("");
00101 
00102   __avahi_thread = new AvahiThread();
00103   __avahi_dispatcher = new AvahiDispatcher;
00104 
00105   __avahi_dispatcher->signal_service_added().connect( sigc::mem_fun( *this, &FuseViewerGtkWindow::on_service_added ) );
00106   __avahi_dispatcher->signal_service_removed().connect( sigc::mem_fun( *this, &FuseViewerGtkWindow::on_service_removed ) );
00107 
00108   __avahi_thread->watch_service("_fountain._tcp", __avahi_dispatcher);
00109   __avahi_thread->start();
00110 }
00111 
00112 /** Destructor. */
00113 FuseViewerGtkWindow::~FuseViewerGtkWindow()
00114 {
00115   delete __avahi_thread;
00116   delete __avahi_dispatcher;
00117 }
00118 
00119 /** Signal handler called after AvahiThread detects a new NetworkService */
00120 void
00121 FuseViewerGtkWindow::on_service_added(fawkes::NetworkService* service)
00122 {
00123   const char* name = service->name();
00124   const char* host = service->host();
00125 
00126   __host_service_map[host] = name;
00127   __img_list_widget->add_fountain_service(
00128       name,
00129       host,
00130       service->port());
00131 }
00132 
00133 /** Signal handler called after AvahiThread detects a NetworkService removal */
00134 void
00135 FuseViewerGtkWindow::on_service_removed( fawkes::NetworkService* service )
00136 {
00137   __img_list_widget->remove_fountain_service( service->name() );
00138 
00139   if (__cur_service_name == service->name()) {
00140     close_image();
00141   }
00142 
00143   std::map<std::string, std::string>::const_iterator it = __host_service_map.begin();
00144   for (; it != __host_service_map.end(); ++it) {
00145     if (__cur_service_name == it->second) {
00146       __host_service_map.erase(it->first);
00147       break;
00148     }
00149   }
00150 }
00151 
00152 /** Signal handler that is called when an image is selected in the image list */
00153 void
00154 FuseViewerGtkWindow::on_fuse_image_selected()
00155 {
00156   __img_list_widget->set_sensitive(Gtk::SENSITIVITY_OFF);
00157   std::string host;
00158   unsigned short port;
00159   std::string image_id;
00160   bool compression;
00161 
00162   __img_list_widget->get_selected_image(host, port, image_id, compression);
00163 
00164   close_image();
00165 
00166   try {
00167     __cam = new NetworkCamera( host.c_str(), port, image_id.c_str(), compression );
00168     __cam->open();
00169     __cam->start();
00170     __cur_service_name = __host_service_map[host];
00171 
00172     __img_widget = new ImageWidget(__cam, 300);
00173     __image_viewport->add(*__img_widget);
00174     __image_viewport->set_size_request(__cam->pixel_width(), __cam->pixel_height());
00175     show_all_children();
00176     __save_type->set_sensitive(Gtk::SENSITIVITY_ON);
00177 
00178     set_status(image_id, host, port);
00179   }
00180   catch (Exception& e) {
00181     __cam = NULL;
00182     e.print_trace();
00183   }
00184 
00185   __img_list_widget->set_sensitive(Gtk::SENSITIVITY_ON);
00186 }
00187 
00188 /** Signal handler that is called if the 'Auto save' checkbox status changes */
00189 void
00190 FuseViewerGtkWindow::on_auto_save_cbt_change()
00191 {
00192   if (__auto_save->get_active()) {
00193     __save_btn->set_sensitive(false);
00194 
00195     __img_widget->save_on_refresh_cam(true,
00196         __save_filechooser->get_current_folder(),
00197         __save_type->get_active_text(),
00198         __img_num);
00199   }
00200   else {
00201     __img_widget->save_on_refresh_cam(false);
00202     __img_num = __img_widget->get_image_num();
00203 
00204     __save_btn->set_sensitive(true);
00205   }
00206 }
00207 
00208 /** Signal handler that is called when the fileformat to save images changes */
00209 void
00210 FuseViewerGtkWindow::on_save_type_change()
00211 {
00212   if (__save_type->get_active_row_number()) {
00213     __auto_save->set_sensitive(true);
00214 
00215     if (__auto_save->get_active()) __img_num = __img_widget->get_image_num();
00216     on_auto_save_cbt_change();
00217   }
00218   else {
00219     __auto_save->set_active(false);
00220     __auto_save->set_sensitive(false);
00221     __save_btn->set_sensitive(false);
00222   }
00223 }
00224 
00225 /** Signal handler that is called when the 'Save image' button is pressed */
00226 void
00227 FuseViewerGtkWindow::on_save_image_clicked()
00228 {
00229   char *ctmp;
00230   if (asprintf(&ctmp, "%s/%06u.%s", __save_filechooser->get_current_folder().c_str(),
00231                ++__img_num, __save_type->get_active_text().c_str()) != -1) {
00232     Glib::ustring fn = ctmp;
00233     free(ctmp);
00234 
00235     __img_widget->save_image(fn, __save_type->get_active_text());
00236   } else {
00237     printf("Could not save file, asprintf() ran out of memory");
00238   }
00239 }
00240 
00241 /**
00242  * Sets the current status (to the statusbar)
00243  * @param img_id the id of the current selected image
00244  * @param host the host that provides the image
00245  * @param port the port to transfer the image
00246  */
00247 void
00248 FuseViewerGtkWindow::set_status(std::string img_id, std::string host, unsigned short port)
00249 {
00250   if (!img_id.length()) {
00251     __statusbar->push(Glib::ustring("Not connected."));
00252   }
00253   else {
00254     char *ctmp = NULL;
00255     if (asprintf(&ctmp, "Host: %s:%u\tId: %s",
00256                  host.c_str(), port, img_id.c_str())) {
00257       __statusbar->push(Glib::ustring(ctmp));
00258       free(ctmp);
00259     }
00260   }
00261 }
00262 
00263 /** Closes the image and the camera */
00264 void
00265 FuseViewerGtkWindow::close_image()
00266 {
00267   if (__img_widget) {
00268     __image_viewport->remove();
00269     delete __img_widget;
00270     __img_widget = NULL;
00271     __save_type->set_sensitive(Gtk::SENSITIVITY_OFF);
00272   }
00273 
00274   if (__cam) {
00275     __cam->stop();
00276     __cam->close();
00277     delete __cam;
00278     __cam = NULL;
00279   }
00280 
00281   set_status("");
00282 }
00283