Fawkes API  Fawkes Development Version
interface_chooser_dialog.cpp
00001 
00002 /***************************************************************************
00003  *  interface_chooser_dialog.cpp - Dialog for choosing a blackboard interface
00004  *
00005  *  Created: Sat Mar 19 12:21:40 2011
00006  *  Copyright  2008-2011  Tim Niemueller [www.niemueller.de]
00007  *  Copyright  2011       Christoph Schwering
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/interface_chooser_dialog.h>
00026 
00027 #include <gtkmm.h>
00028 #include <core/exception.h>
00029 #include <core/exceptions/software.h>
00030 #include <blackboard/blackboard.h>
00031 #include <interface/interface_info.h>
00032 
00033 #include <cstring>
00034 
00035 namespace fawkes {
00036 #if 0 /* just to make Emacs auto-indent happy */
00037 }
00038 #endif
00039 
00040 /** Default title of interface chooser dialogs. */
00041 const char* const InterfaceChooserDialog::DEFAULT_TITLE = "Select Interfaces";
00042 
00043 /** @class InterfaceChooserDialog::Record <gui_utils/interface_chooser_dialog.h>
00044  * Blackboard interface record.
00045  * Record with information about a blackboard interface for a tree model.
00046  * @author Tim Niemueller
00047  */
00048 
00049 /** Constructor. */
00050 InterfaceChooserDialog::Record::Record()
00051 {
00052   add(type);
00053   add(id);
00054   add(has_writer);
00055   add(num_readers);
00056 }
00057 
00058 /** @class InterfaceChooserDialog <gui_utils/interface_chooser_dialog.h>
00059  * Blackboard interface chooser dialog.
00060  * Allows to choose a blackboard interface from a list of interfaces matching
00061  * given type and ID patterns.
00062  * @author Tim Niemueller, Christoph Schwering
00063  */
00064 
00065 
00066 /** Factory method.
00067  *
00068  * Why a factory method instead of a ctor?
00069  * The factory method calls init(), and init() calls other virtual methods.
00070  * If this was a ctor, this ctor would not be allowed to be called by
00071  * subclasses, because then the virtual methods in init() don't dispatch the
00072  * right way during construction (see Effective C++ #9).
00073  *
00074  * @param parent parent window
00075  * @param blackboard blackboard instance to query interfaces from
00076  * @param type_pattern pattern with shell like globs (* for any number of
00077  * characters, ? for exactly one character) to match the interface type.
00078  * @param id_pattern pattern with shell like globs (* for any number of
00079  * characters, ? for exactly one character) to match the interface ID.
00080  * @param title title of the dialog
00081  * @return new InterfaceChooserDialog
00082  */
00083 InterfaceChooserDialog*
00084 InterfaceChooserDialog::create(
00085     Gtk::Window& parent,
00086     BlackBoard* blackboard,
00087     const char* type_pattern,
00088     const char* id_pattern,
00089     const Glib::ustring& title)
00090 {
00091   InterfaceChooserDialog* d = new InterfaceChooserDialog(parent, title);
00092   d->init(blackboard, type_pattern, id_pattern);
00093   return d;
00094 }
00095 
00096 
00097 /** Constructor for subclasses.
00098  *
00099  * After calling this constructor, the init() method needs to be called.
00100  *
00101  * @param parent parent window
00102  * @param title title of the dialog
00103  */
00104 InterfaceChooserDialog::InterfaceChooserDialog(Gtk::Window& parent,
00105                                                const Glib::ustring& title)
00106   : Gtk::Dialog(title, parent, /* modal */ true),
00107     __parent(parent),
00108     __record(NULL)
00109 {
00110   // May *NOT* call init(), because init() calls virtual methods.
00111 }
00112 
00113 
00114 /** Initialization method.
00115  *
00116  * Subclasses should use the protected constructor and should then call the
00117  * init() method.
00118  * This ensures that init()'s calls to virtual methods dispatch to the right
00119  * ones.
00120  *
00121  * @param blackboard blackboard instance to query interfaces from
00122  * @param type_pattern pattern with shell like globs (* for any number of
00123  * characters, ? for exactly one character) to match the interface type.
00124  * @param id_pattern pattern with shell like globs (* for any number of
00125  * characters, ? for exactly one character) to match the interface ID.
00126  */
00127 void
00128 InterfaceChooserDialog::init(BlackBoard *blackboard,
00129                              const char *type_pattern,
00130                              const char *id_pattern)
00131 {
00132   __model = Gtk::ListStore::create(record());
00133 
00134   set_default_size(360, 240);
00135 
00136   __treeview.set_model(__model);
00137   init_columns();
00138   __scrollwin.add(__treeview);
00139   __scrollwin.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
00140   __treeview.show();
00141 
00142   Gtk::Box *vbox = get_vbox();
00143   vbox->pack_start(__scrollwin);
00144   __scrollwin.show();
00145 
00146   add_button(Gtk::Stock::CANCEL, 0);
00147   add_button(Gtk::Stock::OK, 1);
00148 
00149   set_default_response(1);
00150 
00151   __treeview.signal_row_activated().connect(sigc::bind(sigc::hide<0>(sigc::hide<0>(sigc::mem_fun(*this, &InterfaceChooserDialog::response))), 1));
00152 
00153   __bb = blackboard;
00154 
00155   InterfaceInfoList *infl = __bb->list(type_pattern, id_pattern);
00156   for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i) {
00157     Gtk::TreeModel::Row row = *__model->append();
00158     init_row(row, *i);
00159   }
00160   delete infl;
00161 }
00162 
00163 
00164 /** Destructor. */
00165 InterfaceChooserDialog::~InterfaceChooserDialog()
00166 {
00167   if (__record) {
00168     delete __record;
00169   }
00170 }
00171 
00172 
00173 /** Returns the Record of this chooser dialog.
00174  * Subclasses of InterfaceChooserDialog might want to override this method.
00175  * @return Record implementation.
00176  */
00177 const InterfaceChooserDialog::Record&
00178 InterfaceChooserDialog::record() const
00179 {
00180   if (!__record) {
00181     InterfaceChooserDialog* this_nonconst = const_cast<InterfaceChooserDialog*>(this);
00182     this_nonconst->__record = new Record();
00183   }
00184   return *__record;
00185 }
00186 
00187 
00188 /** Initializes the columns GUI-wise.
00189  * Called in the ctor.
00190  * Subclasses of InterfaceChooserDialog might want to override this method,
00191  * but should probably still call their super-class's implementation
00192  * (i.e., this one).
00193  * @return The number of columns added.
00194  */
00195 int
00196 InterfaceChooserDialog::init_columns()
00197 {
00198   __treeview.append_column("Type", record().type);
00199   __treeview.append_column("ID", record().id);
00200   __treeview.append_column("Writer?", record().has_writer);
00201   __treeview.append_column("Readers", record().num_readers);
00202   return 4;
00203 }
00204 
00205 
00206 /** Initializes a row with the given interface.
00207  * Called in the ctor.
00208  * Subclasses of InterfaceChooserDialog might want to override this method,
00209  * but should probably still call their super-class's implementation
00210  * (i.e., this one).
00211  * @param row The row whose content is to be set.
00212  * @param ii The interface info that should populate the row.
00213  */
00214 void
00215 InterfaceChooserDialog::init_row(Gtk::TreeModel::Row& row,
00216                                  const InterfaceInfo& ii)
00217 {
00218   row[record().type]         = ii.type();
00219   row[record().id]           = ii.id();
00220   row[record().has_writer]   = ii.has_writer();
00221   row[record().num_readers]  = ii.num_readers();
00222 }
00223 
00224 
00225 /** Get selected interface type and ID.
00226  * If an interface has been selected use this method to get the
00227  * type and ID.
00228  * Only applicable if get_multi() == false.
00229  * @param type upon return contains the type of the interface
00230  * @param id upon return contains the ID of the interface
00231  * @exception Exception thrown if no interface has been selected
00232  */
00233 void
00234 InterfaceChooserDialog::get_selected_interface(Glib::ustring &type,
00235                                                Glib::ustring &id)
00236 {
00237   const Glib::RefPtr<Gtk::TreeSelection> treesel = __treeview.get_selection();
00238   const Gtk::TreeModel::iterator iter = treesel->get_selected();
00239   if (iter) {
00240     const Gtk::TreeModel::Row row = *iter;
00241     type   = row[record().type];
00242     id     = row[record().id];
00243   } else {
00244     throw Exception("No interface selected");
00245   }
00246 }
00247 
00248 
00249 /** Run dialog and try to connect.
00250  * This runs the service chooser dialog and connects to the given service
00251  * with the attached FawkesNetworkClient. If the connection couldn't be established
00252  * an error dialog is shown. You should not rely on the connection to be
00253  * active after calling this method, rather you should use a ConnectionDispatcher
00254  * to get the "connected" signal.
00255  * @return interface instant of the selected interface. Note that this is only
00256  * an untyped interface instance which is useful for instrospection purposes
00257  * only.
00258  */
00259 fawkes::Interface *
00260 InterfaceChooserDialog::run_and_open_for_reading()
00261 {
00262   if (__bb->is_alive()) throw Exception("BlackBoard is not alive");
00263 
00264   if ( run() ) {
00265     try {
00266       Glib::ustring type;
00267       Glib::ustring id;
00268 
00269       return __bb->open_for_reading(type.c_str(), id.c_str());
00270     } catch (Exception &e) {
00271       Glib::ustring message = *(e.begin());
00272       Gtk::MessageDialog md(__parent, message, /* markup */ false,
00273                             Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK,
00274                             /* modal */ true);
00275       md.set_title("Opening Interface failed");
00276       md.run();
00277       throw;
00278     }
00279   } else {
00280     return NULL;
00281   }
00282 }
00283 
00284 } // end of namespace fawkes