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 < (int) 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 < (int) 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
00206
00207
00208 #if wxMAJOR_VERSION == 2 and wxMINOR_VERSION == 8 // If wxWidgets 2.8.x
00209
00210 property_grid_->SetCaptionForegroundColour( *wxWHITE );
00211 #endif
00212
00213
00214 help_html_->Connect(wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler(DisplaysPanel::onLinkClicked), NULL, this);
00215
00216 state_changed_timer_ = new wxTimer(this);
00217 state_changed_timer_->Start(200);
00218 Connect(state_changed_timer_->GetId(), wxEVT_TIMER, wxTimerEventHandler(DisplaysPanel::onStateChangedTimer), NULL, this);
00219 }
00220
00221 DisplaysPanel::~DisplaysPanel()
00222 {
00223 delete state_changed_timer_;
00224
00225 property_grid_->Destroy();
00226 }
00227
00228 void DisplaysPanel::initialize(VisualizationManager* manager)
00229 {
00230 manager_ = manager;
00231 manager_->getDisplayAddingSignal().connect( boost::bind( &DisplaysPanel::onDisplayAdding, this, _1 ) );
00232 manager_->getDisplayAddedSignal().connect( boost::bind( &DisplaysPanel::onDisplayAdded, this, _1 ) );
00233 manager_->getDisplayRemovingSignal().connect( boost::bind( &DisplaysPanel::onDisplayRemoving, this, _1 ) );
00234 manager_->getDisplayRemovedSignal().connect( boost::bind( &DisplaysPanel::onDisplayRemoved, this, _1 ) );
00235 manager_->getDisplaysRemovingSignal().connect( boost::bind( &DisplaysPanel::onDisplaysRemoving, this, _1 ) );
00236 manager_->getDisplaysRemovedSignal().connect( boost::bind( &DisplaysPanel::onDisplaysRemoved, this, _1 ) );
00237 manager_->getDisplaysConfigLoadedSignal().connect( boost::bind( &DisplaysPanel::onDisplaysConfigLoaded, this, _1 ) );
00238 manager_->getDisplaysConfigSavingSignal().connect( boost::bind( &DisplaysPanel::onDisplaysConfigSaving, this, _1 ) );
00239
00240 manager_->getPropertyManager()->setPropertyGrid(property_grid_);
00241
00242 sortDisplays();
00243 }
00244
00245 void DisplaysPanel::sortDisplays()
00246 {
00247 property_grid_->Freeze();
00248
00249
00250
00251 #if wxMAJOR_VERSION == 2 and wxMINOR_VERSION == 8 // If wxWidgets 2.8.x
00252 property_grid_->Sort(property_grid_->GetRoot());
00253 #else
00254
00255 property_grid_->Sort();
00256 #endif
00257
00258 property_grid_->Refresh();
00259 property_grid_->Thaw();
00260 }
00261
00262 void DisplaysPanel::onPropertyChanging( wxPropertyGridEvent& event )
00263 {
00264 wxPGProperty* property = event.GetProperty();
00265
00266 if ( !property )
00267 {
00268 return;
00269 }
00270
00271 manager_->getPropertyManager()->propertyChanging( event );
00272 }
00273
00274 void DisplaysPanel::onPropertyChanged( wxPropertyGridEvent& event )
00275 {
00276 wxPGProperty* property = event.GetProperty();
00277
00278 if ( !property )
00279 {
00280 return;
00281 }
00282
00283 manager_->getPropertyManager()->propertyChanged( event );
00284 }
00285
00286 void DisplaysPanel::onPropertySelected( wxPropertyGridEvent& event )
00287 {
00288
00289
00290
00291
00292
00293
00294 wxSize size = GetMinSize();
00295 int height = 0;
00296 height += GetSizer()->GetItem(1)->GetMinSize().GetHeight();
00297 height += GetSizer()->GetItem(2)->GetMinSize().GetHeight();
00298 size.SetHeight( height );
00299 SetMinSize( size );
00300
00301 wxPGProperty* pg_property = event.GetProperty();
00302
00303 selected_display_ = 0;
00304
00305 if ( !pg_property )
00306 {
00307 return;
00308 }
00309
00310 wxString text = pg_property->GetHelpString();
00311 wxString html = wxT("<html><body bgcolor=\"#EFEBE7\"><strong>") + pg_property->GetLabel() + wxT("</strong><br>") + text + wxT("</body></html>");
00312
00313 help_html_->SetPage(html);
00314
00315 void* client_data = pg_property->GetClientData();
00316 if ( client_data )
00317 {
00318 PropertyBase* property = reinterpret_cast<PropertyBase*>(client_data);
00319
00320 void* user_data = property->getUserData();
00321 if ( user_data )
00322 {
00323 DisplayWrapper* wrapper = reinterpret_cast<DisplayWrapper*>(user_data);
00324
00325 if ( manager_->isValidDisplay( wrapper ) )
00326 {
00327 selected_display_ = manager_->getDisplayWrapper(wrapper->getName());
00328 }
00329 else
00330 {
00331 DisplayWrapper* wrapper = manager_->getDisplayWrapper(reinterpret_cast<Display*>(user_data));
00332
00333 if (wrapper)
00334 {
00335 selected_display_ = wrapper;
00336 }
00337 }
00338 }
00339 }
00340 }
00341
00342 void DisplaysPanel::onPropertyHighlighted( wxPropertyGridEvent& event )
00343 {
00344 wxPGProperty* property = event.GetProperty();
00345
00346 if ( !property )
00347 {
00348 return;
00349 }
00350
00351
00352
00353
00354
00355
00356
00357 }
00358
00359 void DisplaysPanel::onLinkClicked(wxHtmlLinkEvent& event)
00360 {
00361 wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref());
00362 }
00363
00364 void DisplaysPanel::onNewDisplay( wxCommandEvent& event )
00365 {
00366 L_DisplayTypeInfo display_types;
00367 PluginManager* pm = manager_->getPluginManager();
00368
00369 S_string current_display_names;
00370 manager_->getDisplayNames(current_display_names);
00371
00372 NewDisplayDialog dialog( this, pm->getPlugins(), current_display_names );
00373 while (1)
00374 {
00375 if ( dialog.ShowModal() == wxOK )
00376 {
00377 std::string class_name = dialog.getClassName();
00378 std::string name = dialog.getDisplayName();
00379 std::string package = dialog.getPackageName();
00380
00381 if (manager_->getDisplayWrapper(name))
00382 {
00383 wxMessageBox( wxT("A display with that name already exists!"), wxT("Invalid name"), wxICON_ERROR | wxOK, this );
00384 continue;
00385 }
00386
00387 DisplayWrapper* wrapper = manager_->createDisplay( package, class_name, name, true );
00388 (void)wrapper;
00389 break;
00390 }
00391 else
00392 {
00393 break;
00394 }
00395 }
00396 }
00397
00398 void DisplaysPanel::onDeleteDisplay( wxCommandEvent& event )
00399 {
00400 DisplayWrapper* selected = selected_display_;
00401 if ( !selected )
00402 {
00403 return;
00404 }
00405
00406 manager_->removeDisplay(selected);
00407 selected_display_ = 0;
00408 }
00409
00410 void DisplaysPanel::onManage(wxCommandEvent& event)
00411 {
00412 V_DisplayWrapper& displays = manager_->getDisplays();
00413 ManageDisplaysDialog d(displays, manager_, this);
00414 d.ShowModal();
00415
00416
00417 {
00418 display_map_.clear();
00419 V_DisplayWrapper::iterator it = displays.begin();
00420 V_DisplayWrapper::iterator end = displays.end();
00421 for (; it != end; ++it)
00422 {
00423 DisplayWrapper* display = *it;
00424 uint32_t index = it - displays.begin();
00425 display_map_[display] = index;
00426 setDisplayCategoryLabel(display, index);
00427 }
00428 }
00429
00430 sortDisplays();
00431 }
00432
00433 void DisplaysPanel::setDisplayCategoryLabel(const DisplayWrapper* wrapper, int index)
00434 {
00435 std::string display_name;
00436 if (wrapper->isLoaded())
00437 {
00438 display_name = wrapper->getTypeInfo()->display_name;
00439 }
00440 else
00441 {
00442 display_name = "Plugin from package [" + wrapper->getPackage() + "] not loaded for display class [" + wrapper->getClassName() + "]";
00443 }
00444
00445 char buf[1024];
00446 snprintf( buf, 1024, "%02d. %s (%s)", index + 1, wrapper->getName().c_str(), display_name.c_str());
00447 wrapper->getCategory().lock()->setLabel(buf);
00448 }
00449
00450 void DisplaysPanel::setDisplayCategoryColor(const DisplayWrapper* wrapper)
00451 {
00452 CategoryPropertyPtr cat = wrapper->getCategory().lock();
00453 wxPGProperty* property = wrapper->getCategory().lock()->getPGProperty();
00454
00455
00456
00457
00458 #if wxMAJOR_VERSION == 2 and wxMINOR_VERSION == 8 // If wxWidgets 2.8.x
00459 wxPGCell* cell = property->GetCell( 0 );
00460 if ( !cell )
00461 {
00462 cell = new wxPGCell(*(wxString*)0, wxNullBitmap, wxNullColour, wxNullColour);
00463 property->SetCell( 0, cell );
00464 }
00465 #else
00466
00467
00468 wxPGCell _cell = property->GetCell(0);
00469 #endif
00470
00471
00472 if (!wrapper->isLoaded())
00473 {
00474 cat->setToError();
00475 }
00476 else if ( wrapper->getDisplay()->isEnabled() )
00477 {
00478 switch (wrapper->getDisplay()->getStatus())
00479 {
00480 case status_levels::Ok:
00481 cat->setToOK();
00482 break;
00483 case status_levels::Warn:
00484 cat->setToWarn();
00485 break;
00486 case status_levels::Error:
00487 cat->setToError();
00488 break;
00489 }
00490 }
00491 else
00492 {
00493 cat->setToDisabled();
00494 }
00495 }
00496
00497 void DisplaysPanel::onStateChangedTimer(wxTimerEvent& event)
00498 {
00499 S_Display local_displays;
00500 {
00501 boost::mutex::scoped_lock lock(state_changed_displays_mutex_);
00502 local_displays.swap(state_changed_displays_);
00503 }
00504
00505 S_Display::iterator it = local_displays.begin();
00506 S_Display::iterator end = local_displays.end();
00507 for (; it != end; ++it)
00508 {
00509 Display* display = *it;
00510 DisplayWrapper* wrapper = manager_->getDisplayWrapper(display);
00511 if (!wrapper)
00512 {
00513 continue;
00514 }
00515
00516 M_DisplayToIndex::iterator it = display_map_.find(wrapper);
00517 if (it == display_map_.end())
00518 {
00519 continue;
00520 }
00521
00522 int index = it->second;
00523 setDisplayCategoryColor(wrapper);
00524 setDisplayCategoryLabel(wrapper, index);
00525 }
00526 }
00527
00528 void DisplaysPanel::onDisplayStateChanged( Display* display )
00529 {
00530
00531 boost::mutex::scoped_lock lock(state_changed_displays_mutex_);
00532 state_changed_displays_.insert(display);
00533
00534 }
00535
00536 void DisplaysPanel::onDisplayCreated( DisplayWrapper* wrapper )
00537 {
00538 wrapper->getDisplay()->getStateChangedSignal().connect( boost::bind( &DisplaysPanel::onDisplayStateChanged, this, _1 ) );
00539
00540 setDisplayCategoryColor(wrapper);
00541
00542 Refresh();
00543 }
00544
00545 void DisplaysPanel::onDisplayDestroyed( DisplayWrapper* wrapper )
00546 {
00547 M_DisplayToIndex::iterator it = display_map_.find(wrapper);
00548 if (it == display_map_.end())
00549 {
00550 return;
00551 }
00552
00553 setDisplayCategoryColor(wrapper);
00554
00555
00556 int index = it->second;
00557 setDisplayCategoryLabel(wrapper, index);
00558
00559 Refresh();
00560 }
00561
00562 void DisplaysPanel::onDisplayAdding( DisplayWrapper* wrapper )
00563 {
00564 property_grid_->Freeze();
00565
00566 wrapper->getDisplayCreatedSignal().connect(boost::bind(&DisplaysPanel::onDisplayCreated, this, _1));
00567 wrapper->getDisplayDestroyedSignal().connect(boost::bind(&DisplaysPanel::onDisplayDestroyed, this, _1));
00568 }
00569
00570 void DisplaysPanel::onDisplayAdded( DisplayWrapper* wrapper )
00571 {
00572 int index = display_map_.size();
00573 bool inserted = display_map_.insert(std::make_pair(wrapper, index)).second;
00574 ROS_ASSERT(inserted);
00575 setDisplayCategoryLabel(wrapper, index);
00576 setDisplayCategoryColor(wrapper);
00577
00578 property_grid_->Refresh();
00579 property_grid_->Thaw();
00580 }
00581
00582 void DisplaysPanel::onDisplayRemoving( DisplayWrapper* wrapper )
00583 {
00584 property_grid_->Freeze();
00585 }
00586
00587 void DisplaysPanel::onDisplayRemoved( DisplayWrapper* wrapper )
00588 {
00589 M_DisplayToIndex::iterator it = display_map_.find(wrapper);
00590 ROS_ASSERT(it != display_map_.end());
00591
00592 uint32_t index = it->second;
00593
00594 display_map_.erase(it);
00595
00596 it = display_map_.begin();
00597 M_DisplayToIndex::iterator end = display_map_.end();
00598 for (;it != end; ++it)
00599 {
00600 if (it->second > index)
00601 {
00602 --it->second;
00603 setDisplayCategoryLabel(it->first, it->second);
00604 }
00605 }
00606
00607 sortDisplays();
00608
00609 property_grid_->Refresh();
00610 property_grid_->Thaw();
00611 }
00612
00613 void DisplaysPanel::onDisplaysRemoving( const V_DisplayWrapper& displays )
00614 {
00615 property_grid_->Freeze();
00616 }
00617
00618 void DisplaysPanel::onDisplaysRemoved( const V_DisplayWrapper& displays )
00619 {
00620 property_grid_->Thaw();
00621 }
00622
00623 void DisplaysPanel::onDisplaysConfigLoaded(const boost::shared_ptr<wxConfigBase>& config)
00624 {
00625 wxString grid_state;
00626 if ( config->Read( PROPERTY_GRID_CONFIG, &grid_state ) )
00627 {
00628 property_grid_->RestoreEditableState( grid_state );
00629 }
00630 }
00631
00632 void DisplaysPanel::onDisplaysConfigSaving(const boost::shared_ptr<wxConfigBase>& config)
00633 {
00634 config->Write( PROPERTY_GRID_CONFIG, property_grid_->SaveEditableState() );
00635 }
00636
00637 }