00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "displays_panel.h"
00032 #include "visualization_manager.h"
00033 #include "display.h"
00034 #include "display_wrapper.h"
00035 #include "new_display_dialog.h"
00036 #include "properties/property.h"
00037 #include "properties/property_manager.h"
00038 #include "plugin/type_registry.h"
00039 #include "plugin/plugin_manager.h"
00040 #include "plugin/plugin.h"
00041
00042 #include <wx/propgrid/propgrid.h>
00043 #include <wx/msgdlg.h>
00044 #include <wx/confbase.h>
00045 #include <wx/artprov.h>
00046 #include <wx/timer.h>
00047 #include <wx/textdlg.h>
00048
00049 #include <boost/bind.hpp>
00050
00051 static const wxString PROPERTY_GRID_CONFIG(wxT("Property Grid State"));
00052
00053 namespace rviz
00054 {
00055
00056 class ManageDisplaysDialog : public ManageDisplaysDialogGenerated
00057 {
00058 public:
00059 ManageDisplaysDialog(V_DisplayWrapper& displays, VisualizationManager* manager, wxWindow* parent);
00060
00061 virtual void onRename( wxCommandEvent& event );
00062 virtual void onRemove( wxCommandEvent& event );
00063 virtual void onRemoveAll( wxCommandEvent& event );
00064 virtual void onMoveUp( wxCommandEvent& event );
00065 virtual void onMoveDown( wxCommandEvent& event );
00066 virtual void onOK( wxCommandEvent& event );
00067
00068 V_DisplayWrapper& displays_;
00069 VisualizationManager* manager_;
00070 };
00071
00072 ManageDisplaysDialog::ManageDisplaysDialog(V_DisplayWrapper& displays, VisualizationManager* manager, wxWindow* parent)
00073 : ManageDisplaysDialogGenerated(parent)
00074 , displays_(displays)
00075 , manager_(manager)
00076 {
00077 move_up_->SetBitmapLabel( wxArtProvider::GetIcon( wxART_GO_UP, wxART_OTHER, wxSize(16,16) ) );
00078 move_down_->SetBitmapLabel( wxArtProvider::GetIcon( wxART_GO_DOWN, wxART_OTHER, wxSize(16,16) ) );
00079
00080 V_DisplayWrapper::iterator it = displays_.begin();
00081 V_DisplayWrapper::iterator end = displays_.end();
00082 for (; it != end; ++it)
00083 {
00084 DisplayWrapper* wrapper = *it;
00085 const std::string& name = wrapper->getName();
00086 listbox_->Append(wxString::FromAscii(name.c_str()));
00087 }
00088 }
00089
00090 void ManageDisplaysDialog::onRename( wxCommandEvent& event )
00091 {
00092 int sel = listbox_->GetSelection();
00093 if (sel < 0)
00094 {
00095 return;
00096 }
00097
00098 bool ok = true;
00099 wxString new_name;
00100 do
00101 {
00102 if (!ok)
00103 {
00104 new_name = wxGetTextFromUser(wxT("That name is already taken. Please try another."), wxT("Rename Display"), listbox_->GetString(sel), this);
00105 }
00106 else
00107 {
00108 new_name = wxGetTextFromUser(wxT("New Name?"), wxT("Rename Display"), listbox_->GetString(sel), this);
00109 }
00110
00111 ok = true;
00112 if (new_name.IsEmpty() || new_name == listbox_->GetString(sel))
00113 {
00114 return;
00115 }
00116
00117
00118 V_DisplayWrapper::iterator it = displays_.begin();
00119 V_DisplayWrapper::iterator end = displays_.end();
00120 for (; it != end; ++it)
00121 {
00122 DisplayWrapper* wrapper = *it;
00123 if (wrapper->getName() == (const char*)new_name.mb_str())
00124 {
00125 ok = false;
00126 break;
00127 }
00128 }
00129 } while (!ok);
00130
00131 displays_[sel]->setName((const char*)new_name.mb_str());
00132 listbox_->SetString(sel, new_name);
00133 }
00134
00135 void ManageDisplaysDialog::onRemove(wxCommandEvent& event)
00136 {
00137 int sel = listbox_->GetSelection();
00138 if (sel < 0)
00139 {
00140 return;
00141 }
00142
00143 manager_->removeDisplay(displays_[sel]);
00144 listbox_->Delete(sel);
00145 if (sel < listbox_->GetCount())
00146 {
00147 listbox_->SetSelection(sel);
00148 }
00149 else if (sel > 0)
00150 {
00151 listbox_->SetSelection(sel - 1);
00152 }
00153 }
00154
00155 void ManageDisplaysDialog::onRemoveAll(wxCommandEvent& event)
00156 {
00157 manager_->removeAllDisplays();
00158 listbox_->Clear();
00159 }
00160
00161 void ManageDisplaysDialog::onMoveUp( wxCommandEvent& event )
00162 {
00163 int sel = listbox_->GetSelection();
00164 if (sel > 0)
00165 {
00166 std::swap(displays_[sel], displays_[sel - 1]);
00167 listbox_->Insert(listbox_->GetString(sel - 1), sel + 1);
00168 listbox_->Delete(sel - 1);
00169 listbox_->SetSelection(sel - 1);
00170 }
00171 }
00172
00173 void ManageDisplaysDialog::onMoveDown( wxCommandEvent& event )
00174 {
00175 int sel = listbox_->GetSelection();
00176 if (sel >= 0 && sel < listbox_->GetCount() - 1)
00177 {
00178 std::swap(displays_[sel], displays_[sel + 1]);
00179 listbox_->Insert(listbox_->GetString(sel + 1), sel);
00180 listbox_->Delete(sel + 2);
00181 listbox_->SetSelection(sel + 1);
00182 }
00183 }
00184
00185 void ManageDisplaysDialog::onOK( wxCommandEvent& event )
00186 {
00187 EndModal(wxOK);
00188 }
00189
00190 DisplaysPanel::DisplaysPanel( wxWindow* parent )
00191 : DisplaysPanelGenerated( parent )
00192 , manager_(NULL)
00193 {
00194 property_grid_ = new wxPropertyGrid( properties_panel_, wxID_ANY, wxDefaultPosition, wxSize(500, 500), wxPG_SPLITTER_AUTO_CENTER | wxPG_DEFAULT_STYLE );
00195 properties_panel_sizer_->Add( property_grid_, 1, wxEXPAND, 5 );
00196
00197 property_grid_->SetExtraStyle(wxPG_EX_DISABLE_TLP_TRACKING);
00198
00199 property_grid_->Connect( wxEVT_PG_CHANGING, wxPropertyGridEventHandler( DisplaysPanel::onPropertyChanging ), NULL, this );
00200 property_grid_->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( DisplaysPanel::onPropertyChanged ), NULL, this );
00201 property_grid_->Connect( wxEVT_PG_SELECTED, wxPropertyGridEventHandler( DisplaysPanel::onPropertySelected ), NULL, this );
00202 property_grid_->Connect( wxEVT_PG_HIGHLIGHTED, wxPropertyGridEventHandler( DisplaysPanel::onPropertyHighlighted ), NULL, this );
00203
00204 property_grid_->SetCaptionBackgroundColour( wxColour( 4, 89, 127 ) );
00205 property_grid_->SetCaptionForegroundColour( *wxWHITE );
00206
00207 help_html_->Connect(wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler(DisplaysPanel::onLinkClicked), NULL, this);
00208
00209 state_changed_timer_ = new wxTimer(this);
00210 state_changed_timer_->Start(200);
00211 Connect(state_changed_timer_->GetId(), wxEVT_TIMER, wxTimerEventHandler(DisplaysPanel::onStateChangedTimer), NULL, this);
00212 }
00213
00214 DisplaysPanel::~DisplaysPanel()
00215 {
00216 delete state_changed_timer_;
00217
00218 property_grid_->Destroy();
00219 }
00220
00221 void DisplaysPanel::initialize(VisualizationManager* manager)
00222 {
00223 manager_ = manager;
00224 manager_->getDisplayAddingSignal().connect( boost::bind( &DisplaysPanel::onDisplayAdding, this, _1 ) );
00225 manager_->getDisplayAddedSignal().connect( boost::bind( &DisplaysPanel::onDisplayAdded, this, _1 ) );
00226 manager_->getDisplayRemovingSignal().connect( boost::bind( &DisplaysPanel::onDisplayRemoving, this, _1 ) );
00227 manager_->getDisplayRemovedSignal().connect( boost::bind( &DisplaysPanel::onDisplayRemoved, this, _1 ) );
00228 manager_->getDisplaysRemovingSignal().connect( boost::bind( &DisplaysPanel::onDisplaysRemoving, this, _1 ) );
00229 manager_->getDisplaysRemovedSignal().connect( boost::bind( &DisplaysPanel::onDisplaysRemoved, this, _1 ) );
00230 manager_->getDisplaysConfigLoadedSignal().connect( boost::bind( &DisplaysPanel::onDisplaysConfigLoaded, this, _1 ) );
00231 manager_->getDisplaysConfigSavingSignal().connect( boost::bind( &DisplaysPanel::onDisplaysConfigSaving, this, _1 ) );
00232
00233 manager_->getPropertyManager()->setPropertyGrid(property_grid_);
00234
00235 sortDisplays();
00236 }
00237
00238 void DisplaysPanel::sortDisplays()
00239 {
00240 property_grid_->Freeze();
00241 property_grid_->Sort(property_grid_->GetRoot());
00242 property_grid_->Refresh();
00243 property_grid_->Thaw();
00244 }
00245
00246 void DisplaysPanel::onPropertyChanging( wxPropertyGridEvent& event )
00247 {
00248 wxPGProperty* property = event.GetProperty();
00249
00250 if ( !property )
00251 {
00252 return;
00253 }
00254
00255 manager_->getPropertyManager()->propertyChanging( event );
00256 }
00257
00258 void DisplaysPanel::onPropertyChanged( wxPropertyGridEvent& event )
00259 {
00260 wxPGProperty* property = event.GetProperty();
00261
00262 if ( !property )
00263 {
00264 return;
00265 }
00266
00267 manager_->getPropertyManager()->propertyChanged( event );
00268 }
00269
00270 void DisplaysPanel::onPropertySelected( wxPropertyGridEvent& event )
00271 {
00272
00273
00274
00275
00276
00277
00278 wxSize size = GetMinSize();
00279 int height = 0;
00280 height += GetSizer()->GetItem(1)->GetMinSize().GetHeight();
00281 height += GetSizer()->GetItem(2)->GetMinSize().GetHeight();
00282 size.SetHeight( height );
00283 SetMinSize( size );
00284
00285 wxPGProperty* pg_property = event.GetProperty();
00286
00287 selected_display_ = 0;
00288
00289 if ( !pg_property )
00290 {
00291 return;
00292 }
00293
00294 wxString text = pg_property->GetHelpString();
00295 wxString html = wxT("<html><body bgcolor=\"#EFEBE7\"><strong>") + pg_property->GetLabel() + wxT("</strong><br>") + text + wxT("</body></html>");
00296
00297 help_html_->SetPage(html);
00298
00299 void* client_data = pg_property->GetClientData();
00300 if ( client_data )
00301 {
00302 PropertyBase* property = reinterpret_cast<PropertyBase*>(client_data);
00303
00304 void* user_data = property->getUserData();
00305 if ( user_data )
00306 {
00307 DisplayWrapper* wrapper = reinterpret_cast<DisplayWrapper*>(user_data);
00308
00309 if ( manager_->isValidDisplay( wrapper ) )
00310 {
00311 selected_display_ = manager_->getDisplayWrapper(wrapper->getName());
00312 }
00313 else
00314 {
00315 DisplayWrapper* wrapper = manager_->getDisplayWrapper(reinterpret_cast<Display*>(user_data));
00316
00317 if (wrapper)
00318 {
00319 selected_display_ = wrapper;
00320 }
00321 }
00322 }
00323 }
00324 }
00325
00326 void DisplaysPanel::onPropertyHighlighted( wxPropertyGridEvent& event )
00327 {
00328 wxPGProperty* property = event.GetProperty();
00329
00330 if ( !property )
00331 {
00332 return;
00333 }
00334
00335
00336
00337
00338
00339
00340
00341 }
00342
00343 void DisplaysPanel::onLinkClicked(wxHtmlLinkEvent& event)
00344 {
00345 wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref());
00346 }
00347
00348 void DisplaysPanel::onNewDisplay( wxCommandEvent& event )
00349 {
00350 L_DisplayTypeInfo display_types;
00351 PluginManager* pm = manager_->getPluginManager();
00352
00353 S_string current_display_names;
00354 manager_->getDisplayNames(current_display_names);
00355
00356 NewDisplayDialog dialog( this, pm->getPlugins(), current_display_names );
00357 while (1)
00358 {
00359 if ( dialog.ShowModal() == wxOK )
00360 {
00361 std::string class_name = dialog.getClassName();
00362 std::string name = dialog.getDisplayName();
00363 std::string package = dialog.getPackageName();
00364
00365 if (manager_->getDisplayWrapper(name))
00366 {
00367 wxMessageBox( wxT("A display with that name already exists!"), wxT("Invalid name"), wxICON_ERROR | wxOK, this );
00368 continue;
00369 }
00370
00371 DisplayWrapper* wrapper = manager_->createDisplay( package, class_name, name, true );
00372 (void)wrapper;
00373 break;
00374 }
00375 else
00376 {
00377 break;
00378 }
00379 }
00380 }
00381
00382 void DisplaysPanel::onDeleteDisplay( wxCommandEvent& event )
00383 {
00384 DisplayWrapper* selected = selected_display_;
00385 if ( !selected )
00386 {
00387 return;
00388 }
00389
00390 manager_->removeDisplay(selected);
00391 selected_display_ = 0;
00392 }
00393
00394 void DisplaysPanel::onManage(wxCommandEvent& event)
00395 {
00396 V_DisplayWrapper& displays = manager_->getDisplays();
00397 ManageDisplaysDialog d(displays, manager_, this);
00398 d.ShowModal();
00399
00400
00401 {
00402 display_map_.clear();
00403 V_DisplayWrapper::iterator it = displays.begin();
00404 V_DisplayWrapper::iterator end = displays.end();
00405 for (; it != end; ++it)
00406 {
00407 DisplayWrapper* display = *it;
00408 uint32_t index = it - displays.begin();
00409 display_map_[display] = index;
00410 setDisplayCategoryLabel(display, index);
00411 }
00412 }
00413
00414 sortDisplays();
00415 }
00416
00417 void DisplaysPanel::setDisplayCategoryLabel(const DisplayWrapper* wrapper, int index)
00418 {
00419 std::string display_name;
00420 if (wrapper->isLoaded())
00421 {
00422 display_name = wrapper->getTypeInfo()->display_name;
00423 }
00424 else
00425 {
00426 display_name = "Plugin from package [" + wrapper->getPackage() + "] not loaded for display class [" + wrapper->getClassName() + "]";
00427 }
00428
00429 char buf[1024];
00430 snprintf( buf, 1024, "%02d. %s (%s)", index + 1, wrapper->getName().c_str(), display_name.c_str());
00431 wrapper->getCategory().lock()->setLabel(buf);
00432 }
00433
00434 void DisplaysPanel::setDisplayCategoryColor(const DisplayWrapper* wrapper)
00435 {
00436 CategoryPropertyPtr cat = wrapper->getCategory().lock();
00437 wxPGProperty* property = wrapper->getCategory().lock()->getPGProperty();
00438
00439 wxPGCell* cell = property->GetCell( 0 );
00440 if ( !cell )
00441 {
00442 cell = new wxPGCell(*(wxString*)0, wxNullBitmap, wxNullColour, wxNullColour);
00443 property->SetCell( 0, cell );
00444 }
00445
00446 if (!wrapper->isLoaded())
00447 {
00448 cat->setToError();
00449 }
00450 else if ( wrapper->getDisplay()->isEnabled() )
00451 {
00452 switch (wrapper->getDisplay()->getStatus())
00453 {
00454 case status_levels::Ok:
00455 cat->setToOK();
00456 break;
00457 case status_levels::Warn:
00458 cat->setToWarn();
00459 break;
00460 case status_levels::Error:
00461 cat->setToError();
00462 break;
00463 }
00464 }
00465 else
00466 {
00467 cat->setToDisabled();
00468 }
00469 }
00470
00471 void DisplaysPanel::onStateChangedTimer(wxTimerEvent& event)
00472 {
00473 S_Display local_displays;
00474 {
00475 boost::mutex::scoped_lock lock(state_changed_displays_mutex_);
00476 local_displays.swap(state_changed_displays_);
00477 }
00478
00479 S_Display::iterator it = local_displays.begin();
00480 S_Display::iterator end = local_displays.end();
00481 for (; it != end; ++it)
00482 {
00483 Display* display = *it;
00484 DisplayWrapper* wrapper = manager_->getDisplayWrapper(display);
00485 if (!wrapper)
00486 {
00487 continue;
00488 }
00489
00490 M_DisplayToIndex::iterator it = display_map_.find(wrapper);
00491 if (it == display_map_.end())
00492 {
00493 continue;
00494 }
00495
00496 int index = it->second;
00497 setDisplayCategoryColor(wrapper);
00498 setDisplayCategoryLabel(wrapper, index);
00499 }
00500 }
00501
00502 void DisplaysPanel::onDisplayStateChanged( Display* display )
00503 {
00504
00505 boost::mutex::scoped_lock lock(state_changed_displays_mutex_);
00506 state_changed_displays_.insert(display);
00507
00508 }
00509
00510 void DisplaysPanel::onDisplayCreated( DisplayWrapper* wrapper )
00511 {
00512 wrapper->getDisplay()->getStateChangedSignal().connect( boost::bind( &DisplaysPanel::onDisplayStateChanged, this, _1 ) );
00513
00514 setDisplayCategoryColor(wrapper);
00515
00516 Refresh();
00517 }
00518
00519 void DisplaysPanel::onDisplayDestroyed( DisplayWrapper* wrapper )
00520 {
00521 M_DisplayToIndex::iterator it = display_map_.find(wrapper);
00522 if (it == display_map_.end())
00523 {
00524 return;
00525 }
00526
00527 setDisplayCategoryColor(wrapper);
00528
00529
00530 int index = it->second;
00531 setDisplayCategoryLabel(wrapper, index);
00532
00533 Refresh();
00534 }
00535
00536 void DisplaysPanel::onDisplayAdding( DisplayWrapper* wrapper )
00537 {
00538 property_grid_->Freeze();
00539
00540 wrapper->getDisplayCreatedSignal().connect(boost::bind(&DisplaysPanel::onDisplayCreated, this, _1));
00541 wrapper->getDisplayDestroyedSignal().connect(boost::bind(&DisplaysPanel::onDisplayDestroyed, this, _1));
00542 }
00543
00544 void DisplaysPanel::onDisplayAdded( DisplayWrapper* wrapper )
00545 {
00546 int index = display_map_.size();
00547 bool inserted = display_map_.insert(std::make_pair(wrapper, index)).second;
00548 ROS_ASSERT(inserted);
00549 setDisplayCategoryLabel(wrapper, index);
00550 setDisplayCategoryColor(wrapper);
00551
00552 property_grid_->Refresh();
00553 property_grid_->Thaw();
00554 }
00555
00556 void DisplaysPanel::onDisplayRemoving( DisplayWrapper* wrapper )
00557 {
00558 property_grid_->Freeze();
00559 }
00560
00561 void DisplaysPanel::onDisplayRemoved( DisplayWrapper* wrapper )
00562 {
00563 M_DisplayToIndex::iterator it = display_map_.find(wrapper);
00564 ROS_ASSERT(it != display_map_.end());
00565
00566 uint32_t index = it->second;
00567
00568 display_map_.erase(it);
00569
00570 it = display_map_.begin();
00571 M_DisplayToIndex::iterator end = display_map_.end();
00572 for (;it != end; ++it)
00573 {
00574 if (it->second > index)
00575 {
00576 --it->second;
00577 setDisplayCategoryLabel(it->first, it->second);
00578 }
00579 }
00580
00581 sortDisplays();
00582
00583 property_grid_->Refresh();
00584 property_grid_->Thaw();
00585 }
00586
00587 void DisplaysPanel::onDisplaysRemoving( const V_DisplayWrapper& displays )
00588 {
00589 property_grid_->Freeze();
00590 }
00591
00592 void DisplaysPanel::onDisplaysRemoved( const V_DisplayWrapper& displays )
00593 {
00594 property_grid_->Thaw();
00595 }
00596
00597 void DisplaysPanel::onDisplaysConfigLoaded(const boost::shared_ptr<wxConfigBase>& config)
00598 {
00599 wxString grid_state;
00600 if ( config->Read( PROPERTY_GRID_CONFIG, &grid_state ) )
00601 {
00602 property_grid_->RestoreEditableState( grid_state );
00603 }
00604 }
00605
00606 void DisplaysPanel::onDisplaysConfigSaving(const boost::shared_ptr<wxConfigBase>& config)
00607 {
00608 config->Write( PROPERTY_GRID_CONFIG, property_grid_->SaveEditableState() );
00609 }
00610
00611 }