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 #include <QSplashScreen>
00031 #include <QDockWidget>
00032 #include <QDir>
00033 #include <QCloseEvent>
00034 #include <QToolBar>
00035 #include <QMenuBar>
00036 #include <QMenu>
00037 #include <QMessageBox>
00038 #include <QFileDialog>
00039 #include <QDesktopServices>
00040 #include <QUrl>
00041
00042 #include <boost/filesystem.hpp>
00043 #include <boost/bind.hpp>
00044 #include <boost/algorithm/string/split.hpp>
00045 #include <boost/algorithm/string/trim.hpp>
00046
00047 #include <ros/package.h>
00048 #include <ros/console.h>
00049
00050 #include <ogre_tools/initialization.h>
00051 #include <ogre_tools/render_system.h>
00052
00053 #include "visualization_frame.h"
00054 #include "render_panel.h"
00055 #include "displays_panel.h"
00056 #include "views_panel.h"
00057 #include "time_panel.h"
00058 #include "selection_panel.h"
00059 #include "tool_properties_panel.h"
00060 #include "visualization_manager.h"
00061 #include "tools/tool.h"
00062 #include "loading_dialog.h"
00063 #include "config.h"
00064 #include "panel_dock_widget.h"
00065
00067
00068
00069
00070 namespace fs = boost::filesystem;
00071
00072 #define CONFIG_WINDOW_X "/Window/X"
00073 #define CONFIG_WINDOW_Y "/Window/Y"
00074 #define CONFIG_WINDOW_WIDTH "/Window/Width"
00075 #define CONFIG_WINDOW_HEIGHT "/Window/Height"
00076
00077
00078 #define CONFIG_QMAINWINDOW "/QMainWindow"
00079 #define CONFIG_AUIMANAGER_PERSPECTIVE "/AuiManagerPerspective"
00080 #define CONFIG_AUIMANAGER_PERSPECTIVE_VERSION "/AuiManagerPerspectiveVersion"
00081 #define CONFIG_RECENT_CONFIGS "/RecentConfigs"
00082 #define CONFIG_LAST_DIR "/LastConfigDir"
00083
00084 #define CONFIG_EXTENSION "vcg"
00085 #define CONFIG_EXTENSION_WILDCARD "*."CONFIG_EXTENSION
00086 #define PERSPECTIVE_VERSION 2
00087
00088 #define RECENT_CONFIG_COUNT 10
00089
00090 namespace rviz
00091 {
00092
00093 VisualizationFrame::VisualizationFrame( QWidget* parent )
00094 : QMainWindow( parent )
00095 , render_panel_(NULL)
00096 , displays_panel_(NULL)
00097 , views_panel_(NULL)
00098 , time_panel_(NULL)
00099 , selection_panel_(NULL)
00100 , tool_properties_panel_(NULL)
00101 , file_menu_(NULL)
00102 , recent_configs_menu_(NULL)
00103 , toolbar_(NULL)
00104 , manager_(NULL)
00105 , position_correction_( 0, 0 )
00106 , num_move_events_( 0 )
00107 , toolbar_actions_( NULL )
00108 {
00109 setWindowTitle( "RViz" );
00110 }
00111
00112 VisualizationFrame::~VisualizationFrame()
00113 {
00114 if( manager_ )
00115 {
00116 manager_->removeAllDisplays();
00117 }
00118
00119 delete render_panel_;
00120 delete manager_;
00121 }
00122
00123 void VisualizationFrame::closeEvent( QCloseEvent* event )
00124 {
00125 if( general_config_ )
00126 {
00127 saveConfigs();
00128 }
00129 event->accept();
00130 }
00131
00132 void VisualizationFrame::onSplashLoadStatus( const std::string& status )
00133 {
00134 splash_->showMessage( QString::fromStdString( status ));
00135 }
00136
00137 void VisualizationFrame::initialize(const std::string& display_config_file,
00138 const std::string& fixed_frame,
00139 const std::string& target_frame,
00140 const std::string& splash_path,
00141 bool verbose )
00142 {
00143 initConfigs();
00144
00145 int new_x, new_y, new_width, new_height;
00146 general_config_->get( CONFIG_WINDOW_X, &new_x, x() );
00147 general_config_->get( CONFIG_WINDOW_Y, &new_y, y() );
00148 general_config_->get( CONFIG_WINDOW_WIDTH, &new_width, width() );
00149 general_config_->get( CONFIG_WINDOW_HEIGHT, &new_height, height() );
00150
00151 {
00152 std::string recent;
00153 if( general_config_->get( CONFIG_RECENT_CONFIGS, &recent ))
00154 {
00155 boost::trim( recent );
00156 boost::split( recent_configs_, recent, boost::is_any_of (":"), boost::token_compress_on );
00157 }
00158
00159 general_config_->get( CONFIG_LAST_DIR, &last_config_dir_ );
00160 }
00161
00162 move( new_x, new_y );
00163 resize( new_width, new_height );
00164
00165 package_path_ = ros::package::getPath("rviz_qt");
00166
00167 std::string final_splash_path = splash_path;
00168
00169 if ( splash_path.empty() )
00170 {
00171 #if BOOST_FILESYSTEM_VERSION == 3
00172 final_splash_path = (fs::path(package_path_) / "images/splash.png").string();
00173 #else
00174 final_splash_path = (fs::path(package_path_) / "images/splash.png").file_string();
00175 #endif
00176 }
00177 QPixmap splash_image( QString::fromStdString( final_splash_path ));
00178 splash_ = new QSplashScreen( splash_image );
00179 splash_->show();
00180 splash_->showMessage( "Initializing" );
00181
00182 if( !ros::isInitialized() )
00183 {
00184 int argc = 0;
00185 ros::init( argc, 0, "rviz", ros::init_options::AnonymousName );
00186 }
00187
00188 render_panel_ = new RenderPanel( ogre_tools::RenderSystem::get(), 0, this );
00189 displays_panel_ = new DisplaysPanel( this );
00190 views_panel_ = new ViewsPanel( this );
00191 time_panel_ = new TimePanel( this );
00192 selection_panel_ = new SelectionPanel( this );
00193 tool_properties_panel_ = new ToolPropertiesPanel( this );
00194
00195 splash_->showMessage( "Initializing OGRE resources" );
00196 ogre_tools::V_string paths;
00197 paths.push_back( package_path_ + "/ogre_media/textures" );
00198 ogre_tools::initializeResources( paths );
00199
00200 initMenus();
00201 toolbar_ = addToolBar( "Tools" );
00202 toolbar_->setObjectName( "Tools" );
00203 toolbar_actions_ = new QActionGroup( this );
00204 connect( toolbar_actions_, SIGNAL( triggered( QAction* )), this, SLOT( onToolbarActionTriggered( QAction* )));
00205 view_menu_->addAction( toolbar_->toggleViewAction() );
00206
00207 setCentralWidget( render_panel_ );
00208
00209 addPane( "Displays", displays_panel_, Qt::LeftDockWidgetArea, false );
00210 addPane( "Tool Properties", tool_properties_panel_, Qt::RightDockWidgetArea, false );
00211 addPane( "Views", views_panel_, Qt::RightDockWidgetArea, false );
00212 addPane( "Selection", selection_panel_, Qt::RightDockWidgetArea, false );
00213 addPane( "Time", time_panel_, Qt::BottomDockWidgetArea, false );
00214
00215 manager_ = new VisualizationManager( render_panel_, this );
00216 render_panel_->initialize( manager_->getSceneManager(), manager_ );
00217 displays_panel_->initialize( manager_ );
00218 views_panel_->initialize( manager_ );
00219 time_panel_->initialize(manager_);
00220 selection_panel_->initialize( manager_ );
00221 tool_properties_panel_->initialize( manager_ );
00222
00223 connect( manager_, SIGNAL( toolAdded( Tool* )), this, SLOT( addTool( Tool* )));
00224 connect( manager_, SIGNAL( toolChanged( Tool* )), this, SLOT( indicateToolIsCurrent( Tool* )));
00225
00226 manager_->initialize( StatusCallback(), verbose );
00227 manager_->loadGeneralConfig(general_config_, boost::bind( &VisualizationFrame::onSplashLoadStatus, this, _1 ));
00228
00229 bool display_config_valid = !display_config_file.empty();
00230 if( display_config_valid && !fs::exists( display_config_file ))
00231 {
00232 ROS_ERROR("File [%s] does not exist", display_config_file.c_str());
00233 display_config_valid = false;
00234 }
00235
00236 if( !display_config_valid )
00237 {
00238 manager_->loadDisplayConfig( display_config_, boost::bind( &VisualizationFrame::onSplashLoadStatus, this, _1 ));
00239 }
00240 else
00241 {
00242 boost::shared_ptr<Config> config( new Config );
00243 config->readFromFile( display_config_file );
00244 manager_->loadDisplayConfig( config, boost::bind( &VisualizationFrame::onSplashLoadStatus, this, _1 ));
00245 }
00246
00247 if( !fixed_frame.empty() )
00248 {
00249 manager_->setFixedFrame( fixed_frame );
00250 }
00251
00252 if( !target_frame.empty() )
00253 {
00254 manager_->setTargetFrame( target_frame );
00255 }
00256
00257 splash_->showMessage( "Loading perspective" );
00258
00259 std::string main_window_config;
00260 if( general_config_->get( CONFIG_QMAINWINDOW, &main_window_config ))
00261 {
00262 restoreState( QByteArray::fromHex( main_window_config.c_str() ));
00263 }
00264
00265 updateRecentConfigMenu();
00266 if( display_config_valid )
00267 {
00268 markRecentConfig( display_config_file );
00269 }
00270
00271 delete splash_;
00272 splash_ = 0;
00273
00274 manager_->startUpdate();
00275 }
00276
00277 void VisualizationFrame::initConfigs()
00278 {
00279 config_dir_ = QDir::toNativeSeparators( QDir::homePath() ).toStdString();
00280 #if BOOST_FILESYSTEM_VERSION == 3
00281 std::string old_dir = (fs::path(config_dir_) / ".standalone_visualizer").string();
00282 config_dir_ = (fs::path(config_dir_) / ".rviz_qt").string();
00283 general_config_file_ = (fs::path(config_dir_) / "config").string();
00284 display_config_file_ = (fs::path(config_dir_) / "display_config").string();
00285 #else
00286 std::string old_dir = (fs::path(config_dir_) / ".standalone_visualizer").file_string();
00287 config_dir_ = (fs::path(config_dir_) / ".rviz_qt").file_string();
00288 general_config_file_ = (fs::path(config_dir_) / "config").file_string();
00289 display_config_file_ = (fs::path(config_dir_) / "display_config").file_string();
00290 #endif
00291
00292 if( fs::exists( old_dir ) && !fs::exists( config_dir_ ))
00293 {
00294 ROS_INFO("Migrating old config directory to new location ([%s] to [%s])", old_dir.c_str(), config_dir_.c_str());
00295 fs::rename( old_dir, config_dir_ );
00296 }
00297
00298 if( fs::is_regular_file( config_dir_ ))
00299 {
00300 ROS_INFO("Migrating old config file to new location ([%s] to [%s])", config_dir_.c_str(), general_config_file_.c_str());
00301 std::string backup_file = config_dir_ + "bak";
00302
00303 fs::rename(config_dir_, backup_file);
00304 fs::create_directory(config_dir_);
00305 fs::rename(backup_file, general_config_file_);
00306 }
00307 else if (!fs::exists(config_dir_))
00308 {
00309 fs::create_directory(config_dir_);
00310 }
00311
00312 if (fs::exists(general_config_file_) && !fs::exists(display_config_file_))
00313 {
00314 ROS_INFO("Creating display config from general config");
00315 fs::copy_file(general_config_file_, display_config_file_);
00316 }
00317
00318 ROS_INFO("Loading general config from [%s]", general_config_file_.c_str());
00319 general_config_.reset( new Config );
00320 general_config_->readFromFile( general_config_file_ );
00321
00322 ROS_INFO("Loading display config from [%s]", display_config_file_.c_str());
00323 display_config_.reset( new Config );
00324 display_config_->readFromFile( display_config_file_ );
00325 }
00326
00327 void VisualizationFrame::initMenus()
00328 {
00329 file_menu_ = menuBar()->addMenu( "&File" );
00330 file_menu_->addAction( "&Open Config", this, SLOT( onOpen() ), QKeySequence( "Ctrl+O" ));
00331 file_menu_->addAction( "&Save Config", this, SLOT( onSave() ), QKeySequence( "Ctrl+S" ));
00332 recent_configs_menu_ = file_menu_->addMenu( "&Recent Configs" );
00333 file_menu_->addSeparator();
00334 file_menu_->addAction( "&Quit", this, SLOT( close() ), QKeySequence( "Ctrl+Q" ));
00335
00336 view_menu_ = menuBar()->addMenu( "&View" );
00337
00343
00344 QMenu* help_menu = menuBar()->addMenu( "&Help" );
00345 help_menu->addAction( "Wiki", this, SLOT( onHelpWiki() ));
00346 }
00347
00348 void VisualizationFrame::updateRecentConfigMenu()
00349 {
00350 recent_configs_menu_->clear();
00351
00352 D_string::iterator it = recent_configs_.begin();
00353 D_string::iterator end = recent_configs_.end();
00354 for (; it != end; ++it)
00355 {
00356 if( *it != "" )
00357 {
00358 recent_configs_menu_->addAction( QString::fromStdString( *it ), this, SLOT( onRecentConfigSelected() ));
00359 }
00360 }
00361 }
00362
00363 void VisualizationFrame::markRecentConfig( const std::string& path )
00364 {
00365 D_string::iterator it = std::find( recent_configs_.begin(), recent_configs_.end(), path );
00366 if( it != recent_configs_.end() )
00367 {
00368 recent_configs_.erase( it );
00369 }
00370
00371 recent_configs_.push_front( path );
00372
00373 if( recent_configs_.size() > RECENT_CONFIG_COUNT )
00374 {
00375 recent_configs_.pop_back();
00376 }
00377
00378 updateRecentConfigMenu();
00379 }
00380
00381 void VisualizationFrame::loadDisplayConfig( const std::string& path )
00382 {
00383 if( !fs::exists( path ))
00384 {
00385 QString message = QString::fromStdString( path ) + " does not exist!";
00386 QMessageBox::critical( this, "Config file does not exist", message );
00387 return;
00388 }
00389
00390 manager_->removeAllDisplays();
00391
00392 LoadingDialog dialog( this );
00393 dialog.show();
00394
00395 boost::shared_ptr<Config> config( new Config );
00396 config->readFromFile( path );
00397 manager_->loadDisplayConfig( config, boost::bind( &LoadingDialog::setState, &dialog, _1 ));
00398
00399 markRecentConfig(path);
00400 }
00401
00402
00403 void VisualizationFrame::moveEvent( QMoveEvent* event )
00404 {
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 switch( num_move_events_ )
00424 {
00425 case 0:
00426 first_position_ = pos();
00427 num_move_events_++;
00428 break;
00429 case 1:
00430 position_correction_ = first_position_ - pos();
00431 num_move_events_++;
00432 break;
00433 }
00434 }
00435
00436 QRect VisualizationFrame::hackedFrameGeometry()
00437 {
00438 QRect geom = frameGeometry();
00439 geom.moveTopLeft( pos() + position_correction_ );
00440 return geom;
00441 }
00442
00443 void VisualizationFrame::saveConfigs()
00444 {
00445 ROS_INFO("Saving general config to [%s]", general_config_file_.c_str());
00446 general_config_->clear();
00447 QRect geom = hackedFrameGeometry();
00448 general_config_->set( CONFIG_WINDOW_X, geom.x() );
00449 general_config_->set( CONFIG_WINDOW_Y, geom.y() );
00450 general_config_->set( CONFIG_WINDOW_WIDTH, geom.width() );
00451 general_config_->set( CONFIG_WINDOW_HEIGHT, geom.height() );
00452
00453 QByteArray window_state = saveState().toHex();
00454 general_config_->set( CONFIG_QMAINWINDOW, std::string( window_state.constData() ));
00455
00456 {
00457 std::stringstream ss;
00458 D_string::iterator it = recent_configs_.begin();
00459 D_string::iterator end = recent_configs_.end();
00460 for (; it != end; ++it)
00461 {
00462 if (it != recent_configs_.begin())
00463 {
00464 ss << ":";
00465 }
00466 ss << *it;
00467 }
00468
00469 general_config_->set( CONFIG_RECENT_CONFIGS, ss.str() );
00470 }
00471
00472 general_config_->set( CONFIG_LAST_DIR, last_config_dir_ );
00473
00474 manager_->saveGeneralConfig( general_config_ );
00475 general_config_->writeToFile( general_config_file_ );
00476
00477 ROS_INFO( "Saving display config to [%s]", display_config_file_.c_str() );
00478 display_config_->clear();
00479 manager_->saveDisplayConfig( display_config_ );
00480 display_config_->writeToFile( display_config_file_ );
00481 }
00482
00483 void VisualizationFrame::onOpen()
00484 {
00485 QString filename = QFileDialog::getOpenFileName( this, "Choose a file to open",
00486 QString::fromStdString( last_config_dir_ ),
00487 "RViz config files (" CONFIG_EXTENSION_WILDCARD ")" );
00488
00489 if( !filename.isEmpty() )
00490 {
00491 std::string filename_string = filename.toStdString();
00492 loadDisplayConfig( filename_string );
00493 last_config_dir_ = fs::path( filename_string ).parent_path().string();
00494 }
00495 }
00496
00497 void VisualizationFrame::onSave()
00498 {
00499 QString q_filename = QFileDialog::getSaveFileName( this, "Choose a file to save to",
00500 QString::fromStdString( last_config_dir_ ),
00501 "RViz config files (" CONFIG_EXTENSION_WILDCARD ")" );
00502
00503 if( !q_filename.isEmpty() )
00504 {
00505 std::string filename = q_filename.toStdString();
00506 fs::path path( filename );
00507 if( path.extension() != "."CONFIG_EXTENSION )
00508 {
00509 filename += "."CONFIG_EXTENSION;
00510 }
00511
00512 boost::shared_ptr<Config> config( new Config() );
00513 manager_->saveDisplayConfig( config );
00514 config->writeToFile( filename );
00515
00516 markRecentConfig( filename );
00517
00518 last_config_dir_ = fs::path( filename ).parent_path().string();
00519 }
00520 }
00521
00522 void VisualizationFrame::onRecentConfigSelected()
00523 {
00524 QAction* action = dynamic_cast<QAction*>( sender() );
00525 if( action )
00526 {
00527 std::string path = action->text().toStdString();
00528 if( !path.empty() )
00529 {
00530 loadDisplayConfig( path );
00531 }
00532 }
00533 }
00534
00535 void VisualizationFrame::addTool( Tool* tool )
00536 {
00537 QAction* action = new QAction( QString::fromStdString( tool->getName() ), toolbar_actions_ );
00538 action->setCheckable( true );
00539 action->setShortcut( QKeySequence( QString( tool->getShortcutKey() )));
00540 toolbar_->addAction( action );
00541 action_to_tool_map_[ action ] = tool;
00542 tool_to_action_map_[ tool ] = action;
00543 }
00544
00545 void VisualizationFrame::onToolbarActionTriggered( QAction* action )
00546 {
00547 Tool* tool = action_to_tool_map_[ action ];
00548 if( tool )
00549 {
00550 manager_->setCurrentTool( tool );
00551 }
00552 }
00553
00554 void VisualizationFrame::indicateToolIsCurrent( Tool* tool )
00555 {
00556 QAction* action = tool_to_action_map_[ tool ];
00557 if( action )
00558 {
00559 action->setChecked( true );
00560 }
00561 }
00562
00569 void VisualizationFrame::onHelpWiki()
00570 {
00571 QDesktopServices::openUrl( QUrl( "http://www.ros.org/wiki/rviz" ));
00572 }
00573
00574 QWidget* VisualizationFrame::getParentWindow()
00575 {
00576 return this;
00577 }
00578
00579 PanelDockWidget* VisualizationFrame::addPane( const std::string& name, QWidget* panel, Qt::DockWidgetArea area, bool floating )
00580 {
00581 QString q_name = QString::fromStdString( name );
00582 PanelDockWidget *dock;
00583 dock = new PanelDockWidget( q_name, this );
00584 dock->setWidget( panel );
00585 dock->setFloating( floating );
00586 dock->setObjectName( q_name );
00587 addDockWidget( area, dock );
00588 view_menu_->addAction( dock->toggleViewAction() );
00589 return dock;
00590 }
00591
00592 }