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
34namespace fawkes {
35
36/** Default title of interface chooser dialogs. */
37const 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 */
79InterfaceChooserDialog::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 */
97InterfaceChooserDialog::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 */
116void
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 */
182int
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 */
200void
201InterfaceChooserDialog::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 */
217void
218InterfaceChooserDialog::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
The BlackBoard abstract class.
Definition: blackboard.h:46
virtual bool is_alive() const noexcept=0
Check if the BlackBoard is still alive.
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
virtual InterfaceInfoList * list(const char *type_pattern, const char *id_pattern)=0
Get list of interfaces matching type and ID patterns.
Base class for exceptions in Fawkes.
Definition: exception.h:36
iterator begin() noexcept
Get iterator for messages.
Definition: exception.cpp:676
Gtk::TreeModelColumn< bool > has_writer
Writer exists?
Gtk::TreeModelColumn< Glib::ustring > id
The ID of the interface.
Gtk::TreeModelColumn< Glib::ustring > type
The type of the interface.
Gtk::TreeModelColumn< unsigned int > num_readers
Number of readers.
Blackboard interface chooser dialog.
virtual int init_columns()
Initializes the columns GUI-wise.
Gtk::TreeView treeview_
Tree widget for interfaces.
static const char *const DEFAULT_TITLE
Default title of interface chooser dialogs.
void init(BlackBoard *blackboard, const char *type_pattern, const char *id_pattern)
Initialization method.
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.
virtual const Record & record() const
Returns the Record of this chooser dialog.
Glib::RefPtr< Gtk::ListStore > model_
Data model of the tree.
InterfaceChooserDialog(Gtk::Window &parent, const Glib::ustring &title)
Constructor for subclasses.
static InterfaceChooserDialog * create(Gtk::Window &parent, BlackBoard *blackboard, const char *type_pattern, const char *id_pattern, const Glib::ustring &title=DEFAULT_TITLE)
Factory method.
fawkes::Interface * run_and_open_for_reading()
Run dialog and try to connect.
Interface information list.
Interface info.
bool has_writer() const
Check if there is a writer.
const char * type() const
Get interface type.
const char * id() const
Get interface ID.
unsigned int num_readers() const
Get number of readers.
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
Fawkes library namespace.