Fawkes API
Fawkes Development Version
|
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