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