plugin_tree_view.cpp

00001 
00002 /***************************************************************************
00003  *  plugin_tree_view.cpp - Displays a list of Fawkes plugins and allows to
00004  *                         start/stop them
00005  *
00006  *  Created: Fri Sep 26 21:13:48 2008
00007  *  Copyright  2008  Daniel Beck
00008  *             2008  Tim Niemueller [www.niemueller.de]
00009  *
00010  ****************************************************************************/
00011 
00012 /*  This program is free software; you can redistribute it and/or modify
00013  *  it under the terms of the GNU General Public License as published by
00014  *  the Free Software Foundation; either version 2 of the License, or
00015  *  (at your option) any later version.
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 file in the doc directory.
00023  */
00024 
00025 #include <gui_utils/plugin_tree_view.h>
00026 #include <netcomm/fawkes/client.h>
00027 #include <plugin/net/messages.h>
00028 #include <plugin/net/list_message.h>
00029 #include <gui_utils/twolines_cellrenderer.h>
00030 
00031 #include <cstring>
00032 #include <string>
00033 
00034 using namespace std;
00035 
00036 namespace fawkes {
00037 #if 0 /* just to make Emacs auto-indent happy */
00038 }
00039 #endif
00040 
00041 /** @class PluginTreeView <gui_utils/plugin_tree_view.h>
00042  * A TreeView class to list available plugins und trigger their
00043  * loading/unloading.
00044  *
00045  * @author Daniel Beck
00046  * @author Tim Niemueller
00047  */
00048 
00049 /** @class PluginTreeView::PluginRecord <gui_utils/plugin_tree_view.h>
00050  * Column record class for the plugin tree view.
00051  *
00052  * @author Daniel Beck
00053  */
00054 
00055 /** @var PluginTreeView::m_plugin_list
00056  * Storage object for the plugin data.
00057  */
00058 
00059 /** @var PluginTreeView::m_plugin_record
00060  * Column record object.
00061  */
00062 
00063 /** Constructor. */
00064 PluginTreeView::PluginTreeView()
00065   : m_dispatcher(FAWKES_CID_PLUGINMANAGER)
00066 {
00067   ctor();
00068 }
00069 
00070 #ifdef HAVE_GLADEMM
00071 /** Constructor.
00072  * @param cobject pointer to base object type
00073  * @param ref_xml Glade XML file
00074  */
00075 PluginTreeView::PluginTreeView(BaseObjectType* cobject,
00076                                const Glib::RefPtr<Gnome::Glade::Xml> ref_xml)
00077   : Gtk::TreeView(cobject),
00078     m_dispatcher(FAWKES_CID_PLUGINMANAGER)
00079 {
00080   ctor();
00081 }
00082 #endif
00083 
00084 
00085 void
00086 PluginTreeView::ctor()
00087 {
00088   m_plugin_list = Gtk::ListStore::create(m_plugin_record);
00089   set_model(m_plugin_list);
00090   set_rules_hint(true);
00091   append_column("#", m_plugin_record.index);
00092   append_column_editable("Status", m_plugin_record.loaded);
00093   append_plugin_column();
00094 
00095   on_name_clicked();
00096   Gtk::TreeViewColumn *column = get_column(0);
00097   column->signal_clicked().connect(sigc::mem_fun(*this, &PluginTreeView::on_id_clicked));
00098   column = get_column(1);
00099   column->signal_clicked().connect(sigc::mem_fun(*this, &PluginTreeView::on_status_clicked));
00100 
00101   Gtk::CellRendererToggle* renderer;
00102   renderer = dynamic_cast<Gtk::CellRendererToggle*>( get_column_cell_renderer(1) );
00103   renderer->signal_toggled().connect( sigc::mem_fun(*this, &PluginTreeView::on_status_toggled));
00104 
00105   m_dispatcher.signal_connected().connect(sigc::mem_fun(*this, &PluginTreeView::on_connected));
00106   m_dispatcher.signal_disconnected().connect(sigc::mem_fun(*this, &PluginTreeView::on_disconnected));
00107   m_dispatcher.signal_message_received().connect(sigc::mem_fun(*this, &PluginTreeView::on_message_received));
00108 
00109 }
00110 
00111 /** Destructor. */
00112 PluginTreeView::~PluginTreeView()
00113 {
00114   if (m_dispatcher)
00115   {
00116     // unsubscribe
00117     FawkesNetworkMessage* msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00118                                                          MSG_PLUGIN_UNSUBSCRIBE_WATCH);
00119     m_dispatcher.get_client()->enqueue(msg);
00120 
00121     m_dispatcher.get_client()->deregister_handler(FAWKES_CID_PLUGINMANAGER);
00122   }
00123 
00124 #ifdef HAVE_GCONFMM
00125   if (__gconf) {
00126 #  ifdef GLIBMM_EXCEPTIONS_ENABLED
00127     __gconf->remove_dir(__gconf_prefix);
00128 #  else
00129     std::auto_ptr<Glib::Error> error;
00130     __gconf->remove_dir(__gconf_prefix, error);
00131 #  endif
00132   }
00133 #endif
00134 }
00135 
00136 
00137 /** Set the network client.
00138  * @param client a Fawkes network client
00139  */
00140 void
00141 PluginTreeView::set_network_client(FawkesNetworkClient* client)
00142 {
00143   m_dispatcher.set_client(client);
00144 }
00145 
00146 
00147 /** Set Gconf prefix.
00148  * @param gconf_prefix the GConf prefix
00149  */
00150 void
00151 PluginTreeView::set_gconf_prefix(Glib::ustring gconf_prefix)
00152 {
00153 #ifdef HAVE_GCONFMM
00154   if (! __gconf) {
00155     __gconf = Gnome::Conf::Client::get_default_client();
00156   } else {
00157 #  ifdef GLIBMM_EXCEPTIONS_ENABLED
00158     __gconf->remove_dir(__gconf_prefix);
00159 #  else
00160     std::auto_ptr<Glib::Error> error;
00161     __gconf->remove_dir(__gconf_prefix, error);
00162 #  endif
00163   }
00164 
00165 #ifdef GLIBMM_EXCEPTIONS_ENABLED
00166   __gconf->add_dir(gconf_prefix);
00167 #else
00168   std::auto_ptr<Glib::Error> error;
00169   __gconf->add_dir(gconf_prefix, Gnome::Conf::CLIENT_PRELOAD_NONE, error);
00170 #endif
00171   __gconf_prefix = gconf_prefix;
00172 
00173   if (__gconf_connection) {
00174     __gconf_connection.disconnect();
00175   }
00176   __gconf_connection = __gconf->signal_value_changed().connect(sigc::hide(sigc::hide(sigc::mem_fun(*this, &PluginTreeView::on_config_changed))));
00177 
00178   on_config_changed();
00179 #endif
00180 }
00181 
00182 void
00183 PluginTreeView::on_connected()
00184 {
00185   try
00186   {
00187     FawkesNetworkClient *client = m_dispatcher.get_client();
00188 
00189     // subscribe for load-/unload messages
00190     FawkesNetworkMessage* msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00191                                                          MSG_PLUGIN_SUBSCRIBE_WATCH);
00192     client->enqueue(msg);
00193 
00194     // request list of available plugins
00195     msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00196                                    MSG_PLUGIN_LIST_AVAIL);
00197     client->enqueue(msg);
00198 
00199     // request list of loaded plugins
00200     msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00201                                    MSG_PLUGIN_LIST_LOADED);
00202     client->enqueue(msg);
00203   }
00204   catch (Exception& e)
00205   {
00206     e.print_trace();
00207   }
00208 }
00209 
00210 /** Signal handler that is called whenever the connection is terminated. */
00211 void
00212 PluginTreeView::on_disconnected()
00213 {
00214   m_plugin_list->clear();
00215 }
00216 
00217 
00218 void
00219 PluginTreeView::on_message_received(fawkes::FawkesNetworkMessage* msg)
00220 {
00221   if (msg->cid() != FAWKES_CID_PLUGINMANAGER)  return;
00222 
00223   // loading
00224   unsigned int msgid = msg->msgid();
00225   if ( (msgid == MSG_PLUGIN_LOADED) ||
00226        (msgid == MSG_PLUGIN_LOAD_FAILED) ||
00227        (msgid == MSG_PLUGIN_UNLOADED) ||
00228        (msgid == MSG_PLUGIN_UNLOAD_FAILED) )
00229   {
00230     Glib::ustring name = "";
00231     bool loaded = false;
00232 
00233     if ( msgid == MSG_PLUGIN_LOADED)
00234     {
00235       if ( msg->payload_size() != sizeof(plugin_loaded_msg_t) )
00236       {
00237         printf("Invalid message size (load succeeded)\n");
00238       }
00239       else
00240       {
00241         plugin_loaded_msg_t* m = (plugin_loaded_msg_t*) msg->payload();
00242         name   = m->name;
00243         loaded = true;
00244       }
00245     }
00246     else if ( msgid == MSG_PLUGIN_LOAD_FAILED )
00247     {
00248       if ( msg->payload_size() != sizeof(plugin_load_failed_msg_t) )
00249       {
00250         printf("Invalid message size (load failed)\n");
00251       }
00252       else
00253       {
00254         plugin_load_failed_msg_t* m = (plugin_load_failed_msg_t*) msg->payload();
00255         name   = m->name;
00256         loaded = false;
00257       }
00258     }
00259     else if ( msg->msgid() == MSG_PLUGIN_UNLOADED )
00260     {
00261       if ( msg->payload_size() != sizeof(plugin_unloaded_msg_t) )
00262       {
00263         printf("Invalid message size (unload succeeded)\n");
00264       }
00265       else
00266       {
00267         plugin_unloaded_msg_t* m = (plugin_unloaded_msg_t*) msg->payload();
00268         name   = m->name;
00269         loaded = false;
00270       }
00271     }
00272     else if ( msg->msgid() == MSG_PLUGIN_UNLOAD_FAILED)
00273     {
00274       if ( msg->payload_size() != sizeof(plugin_unload_failed_msg_t) )
00275       {
00276         printf("Invalid message size (unload failed)\n");
00277       }
00278       else
00279       {
00280         plugin_unload_failed_msg_t* m = (plugin_unload_failed_msg_t*) msg->payload();
00281         name   = m->name;
00282         loaded = true;
00283       }
00284     }
00285 
00286     Gtk::TreeIter iter;
00287     for ( iter  = m_plugin_list->children().begin();
00288           iter != m_plugin_list->children().end();
00289           ++iter )
00290     {
00291       Glib::ustring n = (*iter)[m_plugin_record.name];
00292       if ( n == name )
00293       {
00294         (*iter)[m_plugin_record.loaded] = loaded;
00295         break;
00296       }
00297     }
00298   }
00299   else if (msgid == MSG_PLUGIN_AVAIL_LIST)
00300   {
00301     m_plugin_list->clear();
00302     PluginListMessage* plm = msg->msgc<PluginListMessage>();
00303     while ( plm->has_next() )
00304     {
00305       char *plugin_name = plm->next();
00306       char *plugin_desc = NULL;
00307       if ( plm->has_next() ) {
00308         plugin_desc = plm->next();
00309       } else {
00310         plugin_desc = strdup("Unknown, malformed plugin list message?");
00311       }
00312 
00313       Gtk::TreeModel::Row row = *m_plugin_list->append();
00314       unsigned int index = m_plugin_list->children().size();
00315       row[m_plugin_record.index]       = index;
00316       row[m_plugin_record.name]        = plugin_name;
00317       row[m_plugin_record.description] = plugin_desc;
00318       row[m_plugin_record.loaded]      = false;
00319 
00320       free(plugin_name);
00321       free(plugin_desc);
00322     }
00323     delete plm;
00324   }
00325   else if ( msg->msgid() == MSG_PLUGIN_AVAIL_LIST_FAILED)
00326   {
00327     printf("Obtaining list of available plugins failed\n");
00328   }
00329   else if (msg->msgid() == MSG_PLUGIN_LOADED_LIST )
00330   {
00331     PluginListMessage* plm = msg->msgc<PluginListMessage>();
00332     while ( plm->has_next() )
00333     {
00334       char* name = plm->next();
00335 
00336       Gtk::TreeIter iter;
00337       for ( iter  = m_plugin_list->children().begin();
00338             iter != m_plugin_list->children().end();
00339             ++iter )
00340       {
00341         Glib::ustring n = (*iter)[m_plugin_record.name];
00342         if ( n == name )
00343         {
00344           (*iter)[m_plugin_record.loaded] = true;
00345           break;
00346         }
00347       }
00348       free(name);
00349     }
00350     delete plm;
00351   }
00352   else if ( msg->msgid() == MSG_PLUGIN_LOADED_LIST_FAILED)
00353   {
00354     printf("Obtaining list of loaded plugins failed\n");
00355   }
00356 
00357   // unknown message received
00358   else
00359   {
00360     printf("received message with msg-id %d\n", msg->msgid());
00361   }
00362 }
00363 
00364 /** Signal handler that is called when the loaded checkbox is
00365  * toggled.
00366  * @param path the path of the selected row
00367  */
00368 void
00369 PluginTreeView::on_status_toggled(const Glib::ustring& path)
00370 {
00371   if ( ! m_dispatcher.get_client()->connected() )  return;
00372 
00373   Gtk::TreeModel::Row row = *m_plugin_list->get_iter(path);
00374   Glib::ustring plugin_name = row[m_plugin_record.name];
00375   bool loaded = row[m_plugin_record.loaded];
00376 
00377   if (loaded)
00378   {
00379     plugin_load_msg_t* m = (plugin_load_msg_t*) calloc(1, sizeof(plugin_load_msg_t));
00380     strncpy(m->name, plugin_name.c_str(), PLUGIN_MSG_NAME_LENGTH);
00381 
00382     FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00383                                                          MSG_PLUGIN_LOAD,
00384                                                          m, sizeof(plugin_load_msg_t));
00385     m_dispatcher.get_client()->enqueue(msg);
00386   }
00387   else
00388   {
00389     plugin_unload_msg_t* m = (plugin_unload_msg_t *)calloc(1, sizeof(plugin_unload_msg_t));
00390     strncpy(m->name, plugin_name.c_str(), PLUGIN_MSG_NAME_LENGTH);
00391 
00392     FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00393                                                          MSG_PLUGIN_UNLOAD,
00394                                                          m, sizeof(plugin_unload_msg_t));
00395     m_dispatcher.get_client()->enqueue(msg);
00396   }
00397 }
00398 
00399 /**
00400  * TreeView gets sorted by id
00401  */
00402 void
00403 PluginTreeView::on_id_clicked()
00404 {
00405   m_plugin_list->set_sort_column(0, Gtk::SORT_ASCENDING);
00406 }
00407 
00408 /**
00409  * TreeView gets sorted by status (loaded/unloaded)
00410  */
00411 void
00412 PluginTreeView::on_status_clicked()
00413 {
00414   m_plugin_list->set_sort_column(2, Gtk::SORT_DESCENDING);
00415 }
00416 
00417 /**
00418  * TreeView gets sorted by name
00419  */
00420 void
00421 PluginTreeView::on_name_clicked()
00422 {
00423   m_plugin_list->set_sort_column(1, Gtk::SORT_ASCENDING);
00424 }
00425 
00426 /**
00427  * Configuration data has changed
00428  */
00429 void
00430 PluginTreeView::on_config_changed()
00431 {
00432   Gtk::TreeViewColumn *plugin_col = get_column(2);
00433   if (plugin_col) remove_column(*plugin_col);
00434 
00435   append_plugin_column();
00436 }
00437 
00438 /**
00439  * Append appropriate plugin column - depending on the GConf value
00440  */
00441 void
00442 PluginTreeView::append_plugin_column()
00443 {
00444 #if GTKMM_MAJOR_VERSION > 2 || ( GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 14 )
00445   bool description_as_tooltip = false;
00446 #  ifdef HAVE_GCONFMM
00447   if ( __gconf )
00448   {
00449 #    ifdef GLIBMM_EXCEPTIONS_ENABLED
00450     description_as_tooltip = __gconf->get_bool(__gconf_prefix + "/description_as_tooltip");
00451 #    else
00452     std::auto_ptr<Glib::Error> error;
00453     description_as_tooltip = __gconf->get_bool(__gconf_prefix + "/description_as_tooltip", error);
00454 #    endif
00455   }
00456 #  endif
00457 #endif
00458 
00459 #if GTKMM_MAJOR_VERSION > 2 || ( GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 14 )
00460   if (description_as_tooltip)
00461   {
00462 #endif
00463     append_column("Plugin", m_plugin_record.name);
00464 #if GTKMM_MAJOR_VERSION > 2 || ( GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 14 )
00465     set_tooltip_column(2);
00466   }
00467   else
00468   {
00469     TwoLinesCellRenderer *twolines_renderer = new TwoLinesCellRenderer();
00470     Gtk::TreeViewColumn *tlcol = new Gtk::TreeViewColumn("Plugin", *Gtk::manage(twolines_renderer));
00471     append_column(*Gtk::manage(tlcol));
00472 
00473  #  ifdef GLIBMM_PROPERTIES_ENABLED
00474     tlcol->add_attribute(twolines_renderer->property_line1(), m_plugin_record.name);
00475     tlcol->add_attribute(twolines_renderer->property_line2(), m_plugin_record.description);
00476  #  else
00477     tlcol->add_attribute(*twolines_renderer, "line1", m_plugin_record.name);
00478     tlcol->add_attribute(*twolines_renderer, "line2", m_plugin_record.description);
00479  #  endif
00480 
00481     set_tooltip_column(-1);
00482   }
00483 #endif
00484 
00485   set_headers_clickable();
00486   Gtk::TreeViewColumn *plugin_col = get_column(2);
00487   if (plugin_col) plugin_col->signal_clicked().connect(sigc::mem_fun(*this, &PluginTreeView::on_name_clicked));
00488 }
00489 
00490 } // end namespace fawkes

Generated on Tue Feb 22 13:32:27 2011 for Fawkes API by  doxygen 1.4.7