Fawkes API  Fawkes Development Version
interface_chooser_dialog.cpp
1 
2 /***************************************************************************
3  * interface_chooser_dialog.cpp - Dialog for choosing a blackboard interface
4  *
5  * Created: Sat Mar 19 12:21:40 2011
6  * Copyright 2008-2011 Tim Niemueller [www.niemueller.de]
7  * Copyright 2011 Christoph Schwering
8  *
9  ****************************************************************************/
10 
11 /* This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version. A runtime exception applies to
15  * this software (see LICENSE.GPL_WRE file mentioned below for details).
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Library General Public License for more details.
21  *
22  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
23  */
24 
25 #include <gui_utils/interface_chooser_dialog.h>
26 
27 #include <gtkmm.h>
28 #include <core/exception.h>
29 #include <core/exceptions/software.h>
30 #include <blackboard/blackboard.h>
31 #include <interface/interface_info.h>
32 
33 #include <cstring>
34 
35 namespace fawkes {
36 #if 0 /* just to make Emacs auto-indent happy */
37 }
38 #endif
39 
40 /** Default title of interface chooser dialogs. */
41 const char* const InterfaceChooserDialog::DEFAULT_TITLE = "Select Interfaces";
42 
43 /** @class InterfaceChooserDialog::Record <gui_utils/interface_chooser_dialog.h>
44  * Blackboard interface record.
45  * Record with information about a blackboard interface for a tree model.
46  * @author Tim Niemueller
47  */
48 
49 /** Constructor. */
51 {
52  add(type);
53  add(id);
54  add(has_writer);
55  add(num_readers);
56 }
57 
58 /** @class InterfaceChooserDialog <gui_utils/interface_chooser_dialog.h>
59  * Blackboard interface chooser dialog.
60  * Allows to choose a blackboard interface from a list of interfaces matching
61  * given type and ID patterns.
62  * @author Tim Niemueller, Christoph Schwering
63  */
64 
65 
66 /** Factory method.
67  *
68  * Why a factory method instead of a ctor?
69  * The factory method calls init(), and init() calls other virtual methods.
70  * If this was a ctor, this ctor would not be allowed to be called by
71  * subclasses, because then the virtual methods in init() don't dispatch the
72  * right way during construction (see Effective C++ #9).
73  *
74  * @param parent parent window
75  * @param blackboard blackboard instance to query interfaces from
76  * @param type_pattern pattern with shell like globs (* for any number of
77  * characters, ? for exactly one character) to match the interface type.
78  * @param id_pattern pattern with shell like globs (* for any number of
79  * characters, ? for exactly one character) to match the interface ID.
80  * @param title title of the dialog
81  * @return new InterfaceChooserDialog
82  */
85  Gtk::Window& parent,
86  BlackBoard* blackboard,
87  const char* type_pattern,
88  const char* id_pattern,
89  const Glib::ustring& title)
90 {
91  InterfaceChooserDialog* d = new InterfaceChooserDialog(parent, title);
92  d->init(blackboard, type_pattern, id_pattern);
93  return d;
94 }
95 
96 
97 /** Constructor for subclasses.
98  *
99  * After calling this constructor, the init() method needs to be called.
100  *
101  * @param parent parent window
102  * @param title title of the dialog
103  */
105  const Glib::ustring& title)
106  : Gtk::Dialog(title, parent, /* modal */ true),
107  __parent(parent),
108  __record(NULL)
109 {
110  // May *NOT* call init(), because init() calls virtual methods.
111 }
112 
113 
114 /** Initialization method.
115  *
116  * Subclasses should use the protected constructor and should then call the
117  * init() method.
118  * This ensures that init()'s calls to virtual methods dispatch to the right
119  * ones.
120  *
121  * @param blackboard blackboard instance to query interfaces from
122  * @param type_pattern pattern with shell like globs (* for any number of
123  * characters, ? for exactly one character) to match the interface type.
124  * @param id_pattern pattern with shell like globs (* for any number of
125  * characters, ? for exactly one character) to match the interface ID.
126  */
127 void
129  const char *type_pattern,
130  const char *id_pattern)
131 {
132  __model = Gtk::ListStore::create(record());
133 
134  set_default_size(360, 240);
135 
136  __treeview.set_model(__model);
137  init_columns();
138  __scrollwin.add(__treeview);
139  __scrollwin.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
140  __treeview.show();
141 
142  Gtk::Box *vbox = get_vbox();
143  vbox->pack_start(__scrollwin);
144  __scrollwin.show();
145 
146  add_button(Gtk::Stock::CANCEL, 0);
147  add_button(Gtk::Stock::OK, 1);
148 
149  set_default_response(1);
150 
151  __treeview.signal_row_activated().connect(sigc::bind(sigc::hide<0>(sigc::hide<0>(sigc::mem_fun(*this, &InterfaceChooserDialog::response))), 1));
152 
153  __bb = blackboard;
154 
155  InterfaceInfoList *infl = __bb->list(type_pattern, id_pattern);
156  for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i) {
157  Gtk::TreeModel::Row row = *__model->append();
158  init_row(row, *i);
159  }
160  delete infl;
161 }
162 
163 
164 /** Destructor. */
166 {
167  if (__record) {
168  delete __record;
169  }
170 }
171 
172 
173 /** Returns the Record of this chooser dialog.
174  * Subclasses of InterfaceChooserDialog might want to override this method.
175  * @return Record implementation.
176  */
179 {
180  if (!__record) {
181  InterfaceChooserDialog* this_nonconst = const_cast<InterfaceChooserDialog*>(this);
182  this_nonconst->__record = new Record();
183  }
184  return *__record;
185 }
186 
187 
188 /** Initializes the columns GUI-wise.
189  * Called in the ctor.
190  * Subclasses of InterfaceChooserDialog might want to override this method,
191  * but should probably still call their super-class's implementation
192  * (i.e., this one).
193  * @return The number of columns added.
194  */
195 int
197 {
198  __treeview.append_column("Type", record().type);
199  __treeview.append_column("ID", record().id);
200  __treeview.append_column("Writer?", record().has_writer);
201  __treeview.append_column("Readers", record().num_readers);
202  return 4;
203 }
204 
205 
206 /** Initializes a row with the given interface.
207  * Called in the ctor.
208  * Subclasses of InterfaceChooserDialog might want to override this method,
209  * but should probably still call their super-class's implementation
210  * (i.e., this one).
211  * @param row The row whose content is to be set.
212  * @param ii The interface info that should populate the row.
213  */
214 void
215 InterfaceChooserDialog::init_row(Gtk::TreeModel::Row& row,
216  const InterfaceInfo& ii)
217 {
218  row[record().type] = ii.type();
219  row[record().id] = ii.id();
220  row[record().has_writer] = ii.has_writer();
221  row[record().num_readers] = ii.num_readers();
222 }
223 
224 
225 /** Get selected interface type and ID.
226  * If an interface has been selected use this method to get the
227  * type and ID.
228  * Only applicable if get_multi() == false.
229  * @param type upon return contains the type of the interface
230  * @param id upon return contains the ID of the interface
231  * @exception Exception thrown if no interface has been selected
232  */
233 void
235  Glib::ustring &id)
236 {
237  const Glib::RefPtr<Gtk::TreeSelection> treesel = __treeview.get_selection();
238  const Gtk::TreeModel::iterator iter = treesel->get_selected();
239  if (iter) {
240  const Gtk::TreeModel::Row row = *iter;
241  type = row[record().type];
242  id = row[record().id];
243  } else {
244  throw Exception("No interface selected");
245  }
246 }
247 
248 
249 /** Run dialog and try to connect.
250  * This runs the service chooser dialog and connects to the given service
251  * with the attached FawkesNetworkClient. If the connection couldn't be established
252  * an error dialog is shown. You should not rely on the connection to be
253  * active after calling this method, rather you should use a ConnectionDispatcher
254  * to get the "connected" signal.
255  * @return interface instant of the selected interface. Note that this is only
256  * an untyped interface instance which is useful for instrospection purposes
257  * only.
258  */
261 {
262  if (__bb->is_alive()) throw Exception("BlackBoard is not alive");
263 
264  if ( run() ) {
265  try {
266  Glib::ustring type;
267  Glib::ustring id;
268 
269  return __bb->open_for_reading(type.c_str(), id.c_str());
270  } catch (Exception &e) {
271  Glib::ustring message = *(e.begin());
272  Gtk::MessageDialog md(__parent, message, /* markup */ false,
273  Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK,
274  /* modal */ true);
275  md.set_title("Opening Interface failed");
276  md.run();
277  throw;
278  }
279  } else {
280  return NULL;
281  }
282 }
283 
284 } // end of namespace fawkes
const char * type() const
Get interface type.
Blackboard interface chooser dialog.
Fawkes library namespace.
const char * id() const
Get interface ID.
void init(BlackBoard *blackboard, const char *type_pattern, const char *id_pattern)
Initialization method.
Glib::RefPtr< Gtk::ListStore > __model
Data model of the tree.
virtual const Record & record() const
Returns the Record of this chooser dialog.
static const char *const DEFAULT_TITLE
Default title of interface chooser dialogs.
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:79
virtual InterfaceInfoList * list(const char *type_pattern, const char *id_pattern)=0
Get list of interfaces matching type and ID patterns.
Interface information list.
virtual int init_columns()
Initializes the columns GUI-wise.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Gtk::TreeModelColumn< Glib::ustring > type
The type of the interface.
bool has_writer() const
Check if there is a writer.
Gtk::TreeModelColumn< bool > has_writer
Writer exists?
virtual bool is_alive() const =0
Check if the BlackBoard is still alive.
Gtk::TreeView __treeview
Tree widget for interfaces.
iterator begin()
Get iterator for messages.
Definition: exception.cpp:700
InterfaceChooserDialog(Gtk::Window &parent, const Glib::ustring &title)
Constructor for subclasses.
Gtk::TreeModelColumn< unsigned int > num_readers
Number of readers.
unsigned int num_readers() const
Get number of readers.
void get_selected_interface(Glib::ustring &type, Glib::ustring &id)
Get selected interface type and ID.
virtual void init_row(Gtk::TreeModel::Row &row, const InterfaceInfo &ii)
Initializes a row with the given interface.
fawkes::Interface * run_and_open_for_reading()
Run dialog and try to connect.
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
The BlackBoard abstract class.
Definition: blackboard.h:48
Gtk::TreeModelColumn< Glib::ustring > id
The ID of the interface.
static InterfaceChooserDialog * create(Gtk::Window &parent, BlackBoard *blackboard, const char *type_pattern, const char *id_pattern, const Glib::ustring &title=DEFAULT_TITLE)
Factory method.
Interface info.