Fawkes API  Fawkes Development Version
multi_interface_chooser_dialog.cpp
00001 /***************************************************************************
00002  *  multi_interface_chooser_dialog.cpp - Dialog for choosing a blackboard interface
00003  *
00004  *  Created: Mon Oct 17 21:01:30 2011
00005  *  Copyright  2011  Christoph Schwering
00006  *
00007  ****************************************************************************/
00008 
00009 /*  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version. A runtime exception applies to
00013  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00021  */
00022 
00023 #include <gui_utils/multi_interface_chooser_dialog.h>
00024 
00025 #include <gtkmm.h>
00026 #include <core/exception.h>
00027 #include <core/exceptions/software.h>
00028 #include <blackboard/blackboard.h>
00029 #include <interface/interface_info.h>
00030 
00031 #include <algorithm>
00032 #include <cassert>
00033 #include <cstring>
00034 
00035 namespace fawkes {
00036 
00037 /** @class MultiInterfaceChooserDialog::Record <gui_utils/multi_interface_chooser_dialog.h>
00038  * Blackboard interface record.
00039  * Adds a checkbox whether or not to load the specific interface.
00040  * @author Christoph Schwering
00041  */
00042 
00043 /** Constructor. */
00044 MultiInterfaceChooserDialog::Record::Record()
00045 {
00046   add(load);
00047 }
00048 
00049 /** @class MultiInterfaceChooserDialog <gui_utils/multi_interface_chooser_dialog.h>
00050  * Blackboard interface chooser dialog that supports multiple choices.
00051  * Allows to choose multiple blackboard interfaces from a list of interfaces
00052  * matching given type and ID patterns.
00053  * @author Christoph Schwering
00054  */
00055 
00056 
00057 /** Factory method.
00058  *
00059  * Why a factory method instead of a ctor?
00060  * The factory method calls init(), and init() calls other virtual methods.
00061  * If this was a ctor, this ctor would not be allowed to be called by
00062  * subclasses, because then the virtual methods in init() don't dispatch the
00063  * right way during construction (see Effective C++ #9).
00064  *
00065  * @param parent parent window
00066  * @param blackboard blackboard instance to query interfaces from
00067  * @param type_pattern pattern with shell like globs (* for any number of
00068  * characters, ? for exactly one character) to match the interface type.
00069  * @param id_pattern pattern with shell like globs (* for any number of
00070  * characters, ? for exactly one character) to match the interface ID.
00071  * @param loaded_interfaces list of interfaces which are already loaded
00072  * @param title title of the dialog
00073  * @return new MultiInterfaceChooserDialog
00074  */
00075 MultiInterfaceChooserDialog*
00076 MultiInterfaceChooserDialog::create(
00077     Gtk::Window& parent,
00078     BlackBoard* blackboard,
00079     const char* type_pattern,
00080     const char* id_pattern,
00081     const TypeIdPairList& loaded_interfaces,
00082     const Glib::ustring& title)
00083 {
00084   MultiInterfaceChooserDialog* d = new MultiInterfaceChooserDialog(
00085       parent, loaded_interfaces, title);
00086   d->init(blackboard, type_pattern, id_pattern);
00087   return d;
00088 }
00089 
00090 
00091 /** Constructor for subclasses.
00092  *
00093  * After calling this constructor, the init() method needs to be called.
00094  *
00095  * @param parent parent window
00096  * @param loaded_interfaces list of interfaces which are already loaded
00097  * @param title title of the dialog
00098  */
00099 MultiInterfaceChooserDialog::MultiInterfaceChooserDialog(
00100     Gtk::Window &parent,
00101     const TypeIdPairList& loaded_interfaces,
00102     const Glib::ustring& title)
00103   : InterfaceChooserDialog(parent, title),
00104     __record(NULL)
00105 {
00106   __loaded_interfaces.insert(loaded_interfaces.begin(), loaded_interfaces.end());
00107   Glib::RefPtr<Gtk::TreeSelection> treesel = __treeview.get_selection();
00108   __treeview.set_reorderable(true);
00109   __treeview.set_tooltip_text("Drag the rows to change the painting order.");
00110   treesel->set_mode(Gtk::SELECTION_NONE);
00111   // May *NOT* call init(), because init() calls virtual methods.
00112 }
00113 
00114 
00115 /** Destructor. */
00116 MultiInterfaceChooserDialog::~MultiInterfaceChooserDialog()
00117 {
00118   if (__record) {
00119     delete __record;
00120   }
00121 }
00122 
00123 
00124 void
00125 MultiInterfaceChooserDialog::on_load_toggled(const Glib::ustring& path)
00126 {
00127   Gtk::TreeModel::Row row = *__model->get_iter(path);
00128   row[record().load] = !row[record().load];
00129 }
00130 
00131 
00132 /** Returns the Record of this chooser dialog.
00133  * Subclasses of InterfaceChooserDialog might want to override this method.
00134  * @return Record implementation.
00135  */
00136 const MultiInterfaceChooserDialog::Record&
00137 MultiInterfaceChooserDialog::record() const
00138 {
00139   if (!__record) {
00140     MultiInterfaceChooserDialog* this_nonconst = const_cast<MultiInterfaceChooserDialog*>(this);
00141     this_nonconst->__record = new Record();
00142   }
00143   return *__record;
00144 }
00145 
00146 
00147 /** Initializes the columns GUI-wise.
00148  * Called in the ctor.
00149  * Subclasses of InterfaceChooserDialog might want to override this method,
00150  * but should probably still call their super-class's implementation
00151  * (i.e., this one).
00152  * @return The number of columns added.
00153  */
00154 int
00155 MultiInterfaceChooserDialog::init_columns()
00156 {
00157   __treeview.append_column("Load", record().load);
00158 
00159   const int n = InterfaceChooserDialog::init_columns();
00160 
00161   Gtk::CellRendererToggle* renderer = dynamic_cast<Gtk::CellRendererToggle*>(
00162       __treeview.get_column_cell_renderer(0));
00163   assert(renderer != NULL);
00164 
00165   renderer->set_activatable(true);
00166   renderer->signal_toggled().connect(
00167       sigc::mem_fun(*this, &MultiInterfaceChooserDialog::on_load_toggled));
00168 
00169   return n + 2;
00170 }
00171 
00172 
00173 /** Initializes a row with the given interface.
00174  * Called in the ctor.
00175  * Subclasses of InterfaceChooserDialog might want to override this method,
00176  * but should probably still call their super-class's implementation
00177  * (i.e., this one).
00178  * @param row The row whose content is to be set.
00179  * @param ii The interface info that should populate the row.
00180  */
00181 void
00182 MultiInterfaceChooserDialog::init_row(Gtk::TreeModel::Row& row,
00183                                       const InterfaceInfo& ii)
00184 {
00185   InterfaceChooserDialog::init_row(row, ii);
00186   row[record().load] = __loaded_interfaces.find(std::make_pair(ii.type(), ii.id())) !=
00187                        __loaded_interfaces.end();
00188 }
00189 
00190 
00191 /** Get selected interface types and their respective IDs.
00192  * @return A list of type + id pairs of interfaces that are to be loaded.
00193  */
00194 MultiInterfaceChooserDialog::TypeIdPairList
00195 MultiInterfaceChooserDialog::get_selected_interfaces() const
00196 {
00197   TypeIdPairList types_and_ids;
00198 
00199   const Gtk::TreeNodeChildren children = __model->children();
00200   for (Gtk::TreeNodeChildren::const_iterator it = children.begin();
00201        it != children.end(); ++it)
00202   {
00203     const Gtk::TreeRow& row = *it;
00204     if (row[record().load]) {
00205       TypeIdPair pair = std::make_pair(row[record().type], row[record().id]);
00206       types_and_ids.push_back(pair);
00207     }
00208   }
00209 
00210   return types_and_ids;
00211 }
00212 
00213 
00214 /** Get selected interface types and their respective IDs.
00215  * @return A list of type + id pairs of interfaces that are to be loaded,
00216  *         and *NOT* contained in the list of loaded interfaces handed
00217  *         over to create().
00218  */
00219 MultiInterfaceChooserDialog::TypeIdPairList
00220 MultiInterfaceChooserDialog::get_newly_selected_interfaces() const
00221 {
00222   TypeIdPairList types_and_ids;
00223 
00224   const Gtk::TreeNodeChildren children = __model->children();
00225   for (Gtk::TreeNodeChildren::const_iterator it = children.begin();
00226        it != children.end(); ++it)
00227   {
00228     const Gtk::TreeRow& row = *it;
00229     if (row[record().load]) {
00230       TypeIdPair pair = std::make_pair(row[record().type], row[record().id]);
00231       if (__loaded_interfaces.find(pair) == __loaded_interfaces.end())
00232       {
00233         types_and_ids.push_back(pair);
00234       }
00235     }
00236   }
00237 
00238   return types_and_ids;
00239 }
00240 
00241 } // end of namespace fawkes
00242