Fawkes API  Fawkes Development Version
service_selector_cbe.cpp
00001 
00002 /***************************************************************************
00003  *  service_selector_cbe.cpp - Manages list of discovered services of given type
00004  *
00005  *  Created: Mon Sep 29 17:46:44 2008
00006  *  Copyright  2008  Daniel Beck
00007  *             2008  Tim Niemueller [www.niemueller.de]
00008  *
00009  ****************************************************************************/
00010 
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version. A runtime exception applies to
00015  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00016  *
00017  *  This program is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU Library General Public License for more details.
00021  *
00022  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00023  */
00024 
00025 #include <gui_utils/service_selector_cbe.h>
00026 #include <gui_utils/service_model.h>
00027 #include <gui_utils/connection_dispatcher.h>
00028 #include <netcomm/fawkes/client.h>
00029 
00030 #include <sstream>
00031 
00032 using namespace fawkes;
00033 
00034 /** @class fawkes::ServiceSelectorCBE gui_utils/service_selector_cbe.h
00035  * This widget consists of a Gtk::ComboBox and a Gtk::Button. The
00036  * combo box contains all detected services of a given type; upon
00037  * click the button opens a network connection to the selected service.
00038  *
00039  * @author Daniel Beck
00040  * @author Tim Niemueller
00041  */
00042 
00043 /** @var fawkes::ServiceSelectorCBE::m_cbe_services
00044  * A Gtk::ComboBox that lists all available services.
00045  */
00046 
00047 /** @var fawkes::ServiceSelectorCBE::m_btn_connect
00048  * A Gtk::Button that triggers the connection.
00049  */
00050 
00051 /** @var fawkes::ServiceSelectorCBE::m_tbtn_connect
00052  * A Gtk::ToolButton that triggers the connection.
00053  */
00054 
00055 /** @var fawkes::ServiceSelectorCBE::m_parent
00056  * The parent Gtk::Window.
00057  */
00058 
00059 /** @var fawkes::ServiceSelectorCBE::m_service_model
00060  * A liststore which contains information about detected services.
00061  */
00062 
00063 /** @var fawkes::ServiceSelectorCBE::m_dispatcher
00064  * A ConnectionDispatcher which dispatches connection signals.
00065  */
00066 
00067 /** Construtor.
00068  * @param services the combo box to hold the list of services
00069  * @param connect the button to trigger the network connection
00070  * @param parent the parent window. Used for error dialogs.
00071  * @param service a service identifier
00072  */
00073 #if GTK_VERSION_GE(3,0)
00074 ServiceSelectorCBE::ServiceSelectorCBE( Gtk::ComboBox* services,
00075 #else
00076 ServiceSelectorCBE::ServiceSelectorCBE( Gtk::ComboBoxEntry* services,
00077 #endif
00078                                         Gtk::Button* connect,
00079                                         Gtk::Window* parent,
00080                                         const char* service )
00081 {
00082   m_service_model = new ServiceModel(service);
00083 
00084   m_cbe_services  = services;
00085   m_btn_connect   = connect;
00086   m_tbtn_connect  = NULL;
00087   m_parent        = parent;
00088 
00089   initialize();
00090 }
00091 
00092 /** Construtor.
00093  * @param services the combo box to hold the list of services
00094  * @param connect the button to trigger the network connection
00095  * @param parent the parent window. Used for error dialogs.
00096  * @param service a service identifier
00097  */
00098 #if GTK_VERSION_GE(3,0)
00099 ServiceSelectorCBE::ServiceSelectorCBE( Gtk::ComboBox* services,
00100 #else
00101 ServiceSelectorCBE::ServiceSelectorCBE( Gtk::ComboBoxEntry* services,
00102 #endif
00103                                         Gtk::ToolButton* connect,
00104                                         Gtk::Window* parent,
00105                                         const char* service )
00106 {
00107   m_service_model = new ServiceModel(service);
00108 
00109   m_cbe_services  = services;
00110   m_btn_connect   = NULL;
00111   m_tbtn_connect  = connect;
00112   m_parent        = parent;
00113 
00114   initialize();
00115 }
00116 
00117 /** Constructor.
00118  * @param builder Gtk builder
00119  * @param cbe_name name of the combo box
00120  * @param btn_name name of the button
00121  * @param wnd_name name of the parent window
00122  * @param service service identifier
00123  */
00124 ServiceSelectorCBE::ServiceSelectorCBE( Glib::RefPtr<Gtk::Builder> builder,
00125                                         const char* cbe_name,
00126                                         const char* btn_name,
00127                                         const char* wnd_name,
00128                                         const char* service )
00129 {
00130   m_service_model = new ServiceModel(service);
00131 
00132   builder->get_widget(wnd_name, m_parent);
00133   builder->get_widget(cbe_name, m_cbe_services);
00134   builder->get_widget(btn_name, m_btn_connect);
00135 
00136   initialize();
00137 }
00138 
00139 /** Initializer method. */
00140 void
00141 ServiceSelectorCBE::initialize()
00142 {
00143 #if GTK_VERSION_GE(3,0)
00144   if (! m_cbe_services->get_has_entry()) {
00145     throw Exception("Service combo box does not have an entry, fix UI file?");
00146   }
00147 #endif
00148   m_cbe_services->set_model( m_service_model->get_list_store() );
00149 #if GTK_VERSION_GE(3,0)
00150   m_cbe_services->set_entry_text_column(m_service_model->get_column_record().name);
00151 #else
00152   m_cbe_services->set_text_column(m_service_model->get_column_record().name);
00153 #endif
00154   m_cbe_services->get_entry()->set_activates_default(true);
00155   m_cbe_services->signal_changed().connect( sigc::mem_fun( *this, &ServiceSelectorCBE::on_service_selected) );
00156   
00157   Gtk::Entry *ent = static_cast<Gtk::Entry *>(m_cbe_services->get_child());
00158   if (ent)
00159   {
00160     char * fawkes_ip = getenv("FAWKES_IP");
00161     if (fawkes_ip) ent->set_text(fawkes_ip);
00162     else ent->set_text("localhost");
00163   }
00164 
00165   if ( m_btn_connect )
00166   {
00167     m_btn_connect->signal_clicked().connect( sigc::mem_fun( *this, &ServiceSelectorCBE::on_btn_connect_clicked) );
00168     m_btn_connect->set_label("gtk-connect");
00169     m_btn_connect->set_use_stock(true);
00170     m_btn_connect->grab_default();
00171   }
00172   else
00173   {
00174     m_tbtn_connect->signal_clicked().connect( sigc::mem_fun( *this, &ServiceSelectorCBE::on_btn_connect_clicked) );
00175     m_tbtn_connect->set_stock_id( Gtk::StockID("gtk-connect") );
00176     m_tbtn_connect->grab_default();
00177   }
00178 
00179   m_dispatcher = new ConnectionDispatcher();
00180   m_dispatcher->signal_connected().connect(sigc::mem_fun(*this, &ServiceSelectorCBE::on_connected));
00181   m_dispatcher->signal_disconnected().connect(sigc::mem_fun(*this, &ServiceSelectorCBE::on_disconnected));
00182   
00183   __hostname = "";
00184   __port = 0;
00185 }
00186 
00187 /** Destructor. */
00188 ServiceSelectorCBE::~ServiceSelectorCBE()
00189 {
00190   delete m_dispatcher;
00191   delete m_service_model;
00192 }
00193 
00194 /** Access the current network client.
00195  * @return the current network client
00196  */
00197 FawkesNetworkClient*
00198 ServiceSelectorCBE::get_network_client()
00199 {
00200   return m_dispatcher->get_client();
00201 }
00202 
00203 /**
00204  * Returns the currently selected hostname (after connect)
00205  * @return the hostname
00206  */
00207 Glib::ustring
00208 ServiceSelectorCBE::get_hostname()
00209 {
00210   return __hostname;
00211 }
00212 
00213 /**
00214  * Returns the currently selected service name (after connect)
00215  * @return the service name
00216  */
00217 Glib::ustring
00218 ServiceSelectorCBE::get_name()
00219 {
00220   return __servicename;
00221 }
00222 
00223 /**
00224  * Returns the currently used port (after connect)
00225  * @return the port
00226  */
00227 unsigned int
00228 ServiceSelectorCBE::get_port()
00229 {
00230   return __port;
00231 }
00232 
00233 /** This signal is emitted whenever a network connection is established.
00234  * @return reference to the corresponding dispatcher
00235  */
00236 sigc::signal<void>
00237 ServiceSelectorCBE::signal_connected()
00238 {
00239   return m_dispatcher->signal_connected();
00240 }
00241 
00242 /** This signal is emitted whenever a network connection is terminated.
00243  * @return reference to the corresponding dispatcher
00244  */
00245 sigc::signal<void>
00246 ServiceSelectorCBE::signal_disconnected()
00247 {
00248   return m_dispatcher->signal_disconnected();
00249 }
00250 
00251 /** Signal handler that is called whenever the connect button is
00252  * clicked or an entry in the combo box is selected.
00253  */
00254 void
00255 ServiceSelectorCBE::on_btn_connect_clicked()
00256 {
00257   FawkesNetworkClient *client = m_dispatcher->get_client();
00258 
00259   if (client->connected())
00260   {
00261     client->disconnect();
00262     if ( m_btn_connect )
00263     { m_btn_connect->set_label("gtk-connect"); }
00264     else
00265     { m_tbtn_connect->set_label("gtk-connect"); }
00266   }
00267   else
00268   { 
00269     if ( -1 == m_cbe_services->get_active_row_number() )
00270     {
00271       Gtk::Entry* entry = m_cbe_services->get_entry();
00272       __hostname = entry->get_text();
00273 
00274       Glib::ustring::size_type pos;
00275       if ((pos = __hostname.find(':')) != Glib::ustring::npos) 
00276       {
00277         Glib::ustring host = "";
00278         unsigned int port = 1234567; //Greater than max port num (i.e. 65535)
00279         std::istringstream is(__hostname.replace(pos, 1, " "));
00280         is >> host;
00281         is >> port;
00282         
00283         if (port != 1234567 && host.size())
00284         {
00285           __hostname = host;
00286           __port = port;
00287         }
00288       }
00289       else __port = 1910;
00290       __servicename = __hostname;
00291     }
00292     else
00293     {
00294       Gtk::TreeModel::Row row = *m_cbe_services->get_active();
00295       __hostname = row[m_service_model->get_column_record().hostname];
00296       __servicename = row[m_service_model->get_column_record().name];
00297       __port = row[m_service_model->get_column_record().port];
00298     }
00299 
00300     try
00301     {
00302       client->connect( __hostname.c_str(), __port );
00303     }
00304     catch (Exception& e)
00305     {
00306       Glib::ustring message = *(e.begin());
00307       Gtk::MessageDialog md(*m_parent, message, /* markup */ false,
00308                             Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK,
00309                             /* modal */ true);
00310       md.set_title("Connection failed");
00311       md.run();
00312     }
00313   }
00314 }
00315 
00316 /** Signal handler that is called whenever an entry is selected from
00317  * the combo box.
00318  */
00319 void
00320 ServiceSelectorCBE::on_service_selected()
00321 {
00322   if ( -1 == m_cbe_services->get_active_row_number() )  return;
00323 
00324   FawkesNetworkClient *client = m_dispatcher->get_client();
00325   if ( client->connected() )
00326   {
00327     client->disconnect();
00328   }
00329 
00330   Gtk::TreeModel::Row row = *m_cbe_services->get_active();
00331   __hostname = row[m_service_model->get_column_record().hostname];
00332   __servicename = row[m_service_model->get_column_record().name];
00333   __port = row[m_service_model->get_column_record().port];
00334 
00335   m_cbe_services->get_entry()->set_text(__hostname);
00336 
00337   try
00338   {
00339     client->connect( __hostname.c_str(), __port );
00340   }
00341   catch (Exception& e)
00342   {
00343     Glib::ustring message = *(e.begin());
00344     Gtk::MessageDialog md(*m_parent, message, /* markup */ false,
00345                           Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK,
00346                           /* modal */ true);
00347     md.set_title("Connection failed");
00348     md.run();
00349   }
00350 }
00351 
00352 /** Signal handler for the connection established signal. */
00353 void
00354 ServiceSelectorCBE::on_connected()
00355 {
00356   if ( m_btn_connect )
00357   { m_btn_connect->set_label("gtk-disconnect"); }
00358   else
00359   { m_tbtn_connect->set_stock_id( Gtk::StockID("gtk-disconnect") ); }
00360 }
00361 
00362 /** Signal handler for the connection terminated signal. */
00363 void
00364 ServiceSelectorCBE::on_disconnected()
00365 {
00366   if ( m_btn_connect )
00367   { m_btn_connect->set_label("gtk-connect"); }
00368   else
00369   { m_tbtn_connect->set_stock_id( Gtk::StockID("gtk-connect") ); }
00370 }