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 <blackboard/blackboard.h>
26 #include <core/exception.h>
27 #include <core/exceptions/software.h>
28 #include <gui_utils/interface_chooser_dialog.h>
29 #include <interface/interface_info.h>
30 
31 #include <cstring>
32 #include <gtkmm.h>
33 
34 namespace fawkes {
35 
36 /** Default title of interface chooser dialogs. */
37 const char *const InterfaceChooserDialog::DEFAULT_TITLE = "Select Interfaces";
38 
39 /** @class InterfaceChooserDialog::Record <gui_utils/interface_chooser_dialog.h>
40  * Blackboard interface record.
41  * Record with information about a blackboard interface for a tree model.
42  * @author Tim Niemueller
43  */
44 
45 /** Constructor. */
47 {
48  add(type);
49  add(id);
50  add(has_writer);
51  add(num_readers);
52 }
53 
54 /** @class InterfaceChooserDialog <gui_utils/interface_chooser_dialog.h>
55  * Blackboard interface chooser dialog.
56  * Allows to choose a blackboard interface from a list of interfaces matching
57  * given type and ID patterns.
58  * @author Tim Niemueller, Christoph Schwering
59  */
60 
61 /** Factory method.
62  *
63  * Why a factory method instead of a ctor?
64  * The factory method calls init(), and init() calls other virtual methods.
65  * If this was a ctor, this ctor would not be allowed to be called by
66  * subclasses, because then the virtual methods in init() don't dispatch the
67  * right way during construction (see Effective C++ #9).
68  *
69  * @param parent parent window
70  * @param blackboard blackboard instance to query interfaces from
71  * @param type_pattern pattern with shell like globs (* for any number of
72  * characters, ? for exactly one character) to match the interface type.
73  * @param id_pattern pattern with shell like globs (* for any number of
74  * characters, ? for exactly one character) to match the interface ID.
75  * @param title title of the dialog
76  * @return new InterfaceChooserDialog
77  */
79 InterfaceChooserDialog::create(Gtk::Window & parent,
80  BlackBoard * blackboard,
81  const char * type_pattern,
82  const char * id_pattern,
83  const Glib::ustring &title)
84 {
85  InterfaceChooserDialog *d = new InterfaceChooserDialog(parent, title);
86  d->init(blackboard, type_pattern, id_pattern);
87  return d;
88 }
89 
90 /** Constructor for subclasses.
91  *
92  * After calling this constructor, the init() method needs to be called.
93  *
94  * @param parent parent window
95  * @param title title of the dialog
96  */
97 InterfaceChooserDialog::InterfaceChooserDialog(Gtk::Window &parent, const Glib::ustring &title)
98 : Gtk::Dialog(title, parent, /* modal */ true), parent_(parent), record_(NULL)
99 {
100  // May *NOT* call init(), because init() calls virtual methods.
101 }
102 
103 /** Initialization method.
104  *
105  * Subclasses should use the protected constructor and should then call the
106  * init() method.
107  * This ensures that init()'s calls to virtual methods dispatch to the right
108  * ones.
109  *
110  * @param blackboard blackboard instance to query interfaces from
111  * @param type_pattern pattern with shell like globs (* for any number of
112  * characters, ? for exactly one character) to match the interface type.
113  * @param id_pattern pattern with shell like globs (* for any number of
114  * characters, ? for exactly one character) to match the interface ID.
115  */
116 void
118  const char *type_pattern,
119  const char *id_pattern)
120 {
121  model_ = Gtk::ListStore::create(record());
122 
123  set_default_size(360, 240);
124 
125  treeview_.set_model(model_);
126  init_columns();
127  scrollwin_.add(treeview_);
128  scrollwin_.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
129  treeview_.show();
130 
131  Gtk::Box *vbox = get_vbox();
132  vbox->pack_start(scrollwin_);
133  scrollwin_.show();
134 
135  add_button(Gtk::Stock::CANCEL, 0);
136  add_button(Gtk::Stock::OK, 1);
137 
138  set_default_response(1);
139 
140  treeview_.signal_row_activated().connect(sigc::bind(
141  sigc::hide<0>(sigc::hide<0>(sigc::mem_fun(*this, &InterfaceChooserDialog::response))), 1));
142 
143  bb_ = blackboard;
144 
145  InterfaceInfoList *infl = bb_->list(type_pattern, id_pattern);
146  for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i) {
147  Gtk::TreeModel::Row row = *model_->append();
148  init_row(row, *i);
149  }
150  delete infl;
151 }
152 
153 /** Destructor. */
155 {
156  if (record_) {
157  delete record_;
158  }
159 }
160 
161 /** Returns the Record of this chooser dialog.
162  * Subclasses of InterfaceChooserDialog might want to override this method.
163  * @return Record implementation.
164  */
167 {
168  if (!record_) {
169  InterfaceChooserDialog *this_nonconst = const_cast<InterfaceChooserDialog *>(this);
170  this_nonconst->record_ = new Record();
171  }
172  return *record_;
173 }
174 
175 /** Initializes the columns GUI-wise.
176  * Called in the ctor.
177  * Subclasses of InterfaceChooserDialog might want to override this method,
178  * but should probably still call their super-class's implementation
179  * (i.e., this one).
180  * @return The number of columns added.
181  */
182 int
184 {
185  treeview_.append_column("Type", record().type);
186  treeview_.append_column("ID", record().id);
187  treeview_.append_column("Writer?", record().has_writer);
188  treeview_.append_column("Readers", record().num_readers);
189  return 4;
190 }
191 
192 /** Initializes a row with the given interface.
193  * Called in the ctor.
194  * Subclasses of InterfaceChooserDialog might want to override this method,
195  * but should probably still call their super-class's implementation
196  * (i.e., this one).
197  * @param row The row whose content is to be set.
198  * @param ii The interface info that should populate the row.
199  */
200 void
201 InterfaceChooserDialog::init_row(Gtk::TreeModel::Row &row, const InterfaceInfo &ii)
202 {
203  row[record().type] = ii.type();
204  row[record().id] = ii.id();
205  row[record().has_writer] = ii.has_writer();
206  row[record().num_readers] = ii.num_readers();
207 }
208 
209 /** Get selected interface type and ID.
210  * If an interface has been selected use this method to get the
211  * type and ID.
212  * Only applicable if get_multi() == false.
213  * @param type upon return contains the type of the interface
214  * @param id upon return contains the ID of the interface
215  * @exception Exception thrown if no interface has been selected
216  */
217 void
218 InterfaceChooserDialog::get_selected_interface(Glib::ustring &type, Glib::ustring &id)
219 {
220  const Glib::RefPtr<Gtk::TreeSelection> treesel = treeview_.get_selection();
221  const Gtk::TreeModel::iterator iter = treesel->get_selected();
222  if (iter) {
223  const Gtk::TreeModel::Row row = *iter;
224  type = row[record().type];
225  id = row[record().id];
226  } else {
227  throw Exception("No interface selected");
228  }
229 }
230 
231 /** Run dialog and try to connect.
232  * This runs the service chooser dialog and connects to the given service
233  * with the attached FawkesNetworkClient. If the connection couldn't be established
234  * an error dialog is shown. You should not rely on the connection to be
235  * active after calling this method, rather you should use a ConnectionDispatcher
236  * to get the "connected" signal.
237  * @return interface instant of the selected interface. Note that this is only
238  * an untyped interface instance which is useful for instrospection purposes
239  * only.
240  */
243 {
244  if (bb_->is_alive())
245  throw Exception("BlackBoard is not alive");
246 
247  if (run()) {
248  try {
249  Glib::ustring type;
250  Glib::ustring id;
251 
252  return bb_->open_for_reading(type.c_str(), id.c_str());
253  } catch (Exception &e) {
254  Glib::ustring message = *(e.begin());
255  Gtk::MessageDialog md(parent_,
256  message,
257  /* markup */ false,
258  Gtk::MESSAGE_ERROR,
259  Gtk::BUTTONS_OK,
260  /* modal */ true);
261  md.set_title("Opening Interface failed");
262  md.run();
263  throw;
264  }
265  } else {
266  return NULL;
267  }
268 }
269 
270 } // end of namespace fawkes
const char * type() const
Get interface type.
Gtk::TreeView treeview_
Tree widget for interfaces.
Blackboard interface chooser dialog.
Fawkes library namespace.
unsigned int num_readers() const
Get number of readers.
void init(BlackBoard *blackboard, const char *type_pattern, const char *id_pattern)
Initialization method.
bool has_writer() const
Check if there is a writer.
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:78
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.
Glib::RefPtr< Gtk::ListStore > model_
Data model of the tree.
Base class for exceptions in Fawkes.
Definition: exception.h:35
Gtk::TreeModelColumn< Glib::ustring > type
The type of the interface.
Gtk::TreeModelColumn< bool > has_writer
Writer exists?
virtual bool is_alive() const =0
Check if the BlackBoard is still alive.
const char * id() const
Get interface ID.
iterator begin()
Get iterator for messages.
Definition: exception.cpp:676
InterfaceChooserDialog(Gtk::Window &parent, const Glib::ustring &title)
Constructor for subclasses.
Gtk::TreeModelColumn< unsigned int > num_readers
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:45
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.