planning_groups_widget.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2012, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 /* Author: Dave Coleman */
00036 
00037 // ******************************************************************************************
00038 /* DEVELOPER NOTES
00039 
00040    This widget has 6 subscreens, located in somewhat different places
00041    - Main screen, the tree view of all groups & subgroups - embedded in this file as a function
00042    - Add/Edit Group screen - located in group_edit_widget.cpp
00043    - Joint Collection Screen - implements the double_list_widget.cpp widget
00044    - Link Collection Screen - implements the double_list_widget.cpp widget
00045    - Kinematic Chain Screen - uses it own custom widget - kinematic_chain_widget.cpp
00046    - Subgroup Screen - implements the double_list_widget.cpp widget
00047 */
00048 // ******************************************************************************************
00049 
00050 #include "ros/ros.h"
00051 #include "header_widget.h"
00052 #include "planning_groups_widget.h"
00053 #include <boost/thread.hpp>
00054 #include <boost/lexical_cast.hpp> // for checking convertion of string to double
00055 // Qt
00056 #include <QApplication>
00057 #include <QDebug>
00058 #include <QVBoxLayout>
00059 #include <QHBoxLayout>
00060 #include <QLabel>
00061 #include <QPushButton>
00062 #include <QMessageBox>
00063 #include <QString>
00064 #include <QLineEdit>
00065 #include <QTreeWidgetItem>
00066 #include <QHeaderView>
00067 // Cycle checking
00068 #include <boost/utility.hpp>
00069 #include <boost/graph/adjacency_list.hpp>
00070 #include <boost/graph/depth_first_search.hpp>
00071 #include <boost/graph/visitors.hpp>
00072 
00073 namespace moveit_setup_assistant
00074 {
00075 
00076 // Name of rviz topic in ROS
00077 static const std::string VIS_TOPIC_NAME = "planning_components_visualization";
00078 
00079 // Used for checking for cycles in a subgroup hierarchy
00080 struct cycle_detector : public boost::dfs_visitor<>
00081 {
00082   cycle_detector(bool& has_cycle)
00083     : m_has_cycle(has_cycle) { }
00084 
00085   template <class Edge, class Graph>
00086   void back_edge(Edge, Graph&) { m_has_cycle = true; }
00087 protected:
00088   bool& m_has_cycle;
00089 };
00090 
00091 // ******************************************************************************************
00092 // Constructor
00093 // ******************************************************************************************
00094 PlanningGroupsWidget::PlanningGroupsWidget( QWidget *parent, moveit_setup_assistant::MoveItConfigDataPtr config_data )
00095   : SetupScreenWidget( parent ), config_data_(config_data)
00096 {
00097   // Basic widget container
00098   QVBoxLayout *layout = new QVBoxLayout();
00099 
00100   // Top Label Area ------------------------------------------------
00101   HeaderWidget *header = new HeaderWidget( "Planning Groups",
00102                                            "Create and edit planning groups for your robot based on joint collections, link collections, kinematic chains and subgroups.",
00103                                            this);
00104   layout->addWidget( header );
00105 
00106   // Left Side ---------------------------------------------
00107 
00108   // Create left side widgets
00109   groups_tree_widget_ = createContentsWidget(); // included in this file
00110 
00111   // Joints edit widget
00112   joints_widget_ = new DoubleListWidget( this, config_data_, "Joint Collection", "Joint" );
00113   connect( joints_widget_, SIGNAL( cancelEditing() ), this, SLOT( cancelEditing() ) );
00114   connect( joints_widget_, SIGNAL( doneEditing() ), this, SLOT( saveJointsScreen() ) );
00115   connect( joints_widget_, SIGNAL( previewSelected( std::vector<std::string> ) ),
00116            this, SLOT( previewSelectedJoints( std::vector<std::string> ) ) );
00117 
00118   // Links edit widget
00119   links_widget_ = new DoubleListWidget( this, config_data_, "Link Collection", "Link" );
00120   connect( links_widget_, SIGNAL( cancelEditing() ), this, SLOT( cancelEditing() ) );
00121   connect( links_widget_, SIGNAL( doneEditing() ), this, SLOT( saveLinksScreen() ) );
00122   connect( links_widget_, SIGNAL( previewSelected( std::vector<std::string> ) ),
00123            this, SLOT( previewSelectedLink( std::vector<std::string> ) ) );
00124 
00125   // Chain Widget
00126   chain_widget_ = new KinematicChainWidget( this, config_data );
00127   connect( chain_widget_, SIGNAL( cancelEditing() ), this, SLOT( cancelEditing() ) );
00128   connect( chain_widget_, SIGNAL( doneEditing() ), this, SLOT( saveChainScreen() ) );
00129   connect( chain_widget_, SIGNAL( unhighlightAll() ), this, SIGNAL( unhighlightAll() ) );
00130   connect( chain_widget_, SIGNAL( highlightLink(const std::string&)), this, SIGNAL(highlightLink(const std::string&)) );
00131 
00132   // Subgroups Widget
00133   subgroups_widget_ = new DoubleListWidget( this, config_data_, "Subgroup", "Subgroup" );
00134   connect( subgroups_widget_, SIGNAL( cancelEditing() ), this, SLOT( cancelEditing() ) );
00135   connect( subgroups_widget_, SIGNAL( doneEditing() ), this, SLOT( saveSubgroupsScreen() ) );
00136   connect( subgroups_widget_, SIGNAL( previewSelected( std::vector<std::string> ) ),
00137            this, SLOT( previewSelectedSubgroup( std::vector<std::string> ) ) );
00138 
00139   // Group Edit Widget
00140   group_edit_widget_ = new GroupEditWidget( this, config_data_ );
00141   connect( group_edit_widget_, SIGNAL( cancelEditing() ), this, SLOT( cancelEditing() ) );
00142   connect( group_edit_widget_, SIGNAL( deleteGroup() ), this, SLOT( deleteGroup() ) );
00143   connect( group_edit_widget_, SIGNAL( save() ), this, SLOT( saveGroupScreenEdit() ) );
00144   connect( group_edit_widget_, SIGNAL( saveJoints() ), this, SLOT( saveGroupScreenJoints() ) );
00145   connect( group_edit_widget_, SIGNAL( saveLinks() ), this, SLOT( saveGroupScreenLinks() ) );
00146   connect( group_edit_widget_, SIGNAL( saveChain() ), this, SLOT( saveGroupScreenChain() ) );
00147   connect( group_edit_widget_, SIGNAL( saveSubgroups() ), this, SLOT( saveGroupScreenSubgroups() ) );
00148 
00149 
00150   // Combine into stack
00151   stacked_layout_ = new QStackedLayout( this );
00152   stacked_layout_->addWidget( groups_tree_widget_ ); // screen index 0
00153   stacked_layout_->addWidget( joints_widget_ ); // screen index 1
00154   stacked_layout_->addWidget( links_widget_ ); // screen index 2
00155   stacked_layout_->addWidget( chain_widget_ ); // screen index 3
00156   stacked_layout_->addWidget( subgroups_widget_ ); // screen index 4
00157   stacked_layout_->addWidget( group_edit_widget_ ); // screen index 5
00158 
00159   showMainScreen();
00160 
00161   // Finish GUI -----------------------------------------------------------
00162 
00163   // Create Widget wrapper for layout
00164   QWidget *stacked_layout_widget = new QWidget( this );
00165   stacked_layout_widget->setLayout( stacked_layout_ );
00166 
00167   layout->addWidget( stacked_layout_widget );
00168 
00169   setLayout(layout);
00170 
00171   // process the gui
00172   QApplication::processEvents();
00173 }
00174 
00175 // ******************************************************************************************
00176 // Create the main tree view widget
00177 // ******************************************************************************************
00178 QWidget* PlanningGroupsWidget::createContentsWidget()
00179 {
00180   // Main widget
00181   QWidget *content_widget = new QWidget( this );
00182 
00183   // Basic widget container
00184   QVBoxLayout *layout = new QVBoxLayout( this );
00185 
00186 
00187   // Tree Box ----------------------------------------------------------------------
00188 
00189   groups_tree_ = new QTreeWidget( this );
00190   groups_tree_->setHeaderLabel( "Current Groups" );
00191   connect( groups_tree_, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int) ), this, SLOT(editSelected()));
00192   connect( groups_tree_, SIGNAL( itemClicked( QTreeWidgetItem*, int) ), this, SLOT(previewSelected()));
00193   layout->addWidget(groups_tree_);
00194 
00195 
00196   // Bottom Controls -------------------------------------------------------------
00197 
00198   QHBoxLayout *controls_layout = new QHBoxLayout( );
00199 
00200   // Expand/Contract controls
00201   QLabel *expand_controls = new QLabel( this );
00202   expand_controls->setText("<a href='expand'>Expand All</a> <a href='contract'>Collapse All</a>");
00203   connect( expand_controls, SIGNAL(linkActivated( const QString )), this, SLOT( alterTree( const QString )));
00204   controls_layout->addWidget( expand_controls );
00205 
00206   // Spacer
00207   QWidget *spacer = new QWidget( this );
00208   spacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
00209   controls_layout->addWidget( spacer );
00210 
00211   // Delete Selected Button
00212   btn_delete_ = new QPushButton( "&Delete Selected", this );
00213   btn_delete_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
00214   btn_delete_->setMaximumWidth( 300 );
00215   connect( btn_delete_, SIGNAL(clicked()), this, SLOT( deleteGroup() ) );
00216   controls_layout->addWidget( btn_delete_ );
00217   controls_layout->setAlignment(btn_delete_, Qt::AlignRight);
00218 
00219   //  Edit Selected Button
00220   btn_edit_ = new QPushButton( "&Edit Selected", this );
00221   btn_edit_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
00222   btn_edit_->setMaximumWidth(300);
00223   btn_edit_->hide(); // show once we know if there are existing groups
00224   connect(btn_edit_, SIGNAL(clicked()), this, SLOT(editSelected()));
00225   controls_layout->addWidget(btn_edit_);
00226   controls_layout->setAlignment( btn_edit_, Qt::AlignRight );
00227 
00228   // Add Group Button
00229   QPushButton *btn_add = new QPushButton( "&Add Group", this );
00230   btn_add->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
00231   btn_add->setMaximumWidth(300);
00232   connect(btn_add, SIGNAL(clicked()), this, SLOT(addGroup()));
00233   controls_layout->addWidget(btn_add);
00234   controls_layout->setAlignment( btn_add, Qt::AlignRight );
00235 
00236 
00237   // Add Controls to layout
00238   layout->addLayout( controls_layout );
00239 
00240   // Set layout
00241   content_widget->setLayout(layout);
00242 
00243   return content_widget;
00244 }
00245 
00246 // ******************************************************************************************
00247 // Displays data in the link_pairs_ data structure into a QtTableWidget
00248 // ******************************************************************************************
00249 void PlanningGroupsWidget::loadGroupsTree()
00250 {
00251   // Disable Tree
00252   groups_tree_->setUpdatesEnabled(false); // prevent table from updating until we are completely done
00253   groups_tree_->setDisabled(true); // make sure we disable it so that the cellChanged event is not called
00254   groups_tree_->clear(); // reset the tree
00255 
00256   // Display all groups by looping through them
00257   for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
00258        group_it != config_data_->srdf_->groups_.end();  ++group_it )
00259   {
00260     loadGroupsTreeRecursive( *group_it, NULL );
00261   }
00262 
00263   // Reenable Tree
00264   groups_tree_->setUpdatesEnabled(true); // prevent table from updating until we are completely done
00265   groups_tree_->setDisabled(false); // make sure we disable it so that the cellChanged event is not called
00266 
00267   // Show Edit button if there are things to edit
00268   if( !config_data_->srdf_->groups_.empty() )
00269   {
00270     btn_edit_->show();
00271     btn_delete_->show();
00272   }
00273   else
00274   {
00275     btn_edit_->hide();
00276     btn_delete_->hide();
00277   }
00278 
00279   alterTree( "expand" );
00280 }
00281 
00282 // ******************************************************************************************
00283 // Recursively Adds Groups, and subgroups to groups...
00284 // ******************************************************************************************
00285 void PlanningGroupsWidget::loadGroupsTreeRecursive( srdf::Model::Group &group_it, QTreeWidgetItem *parent )
00286 {
00287 
00288   // Fonts for tree
00289   const QFont top_level_font( "Arial", 11, QFont::Bold );
00290   const QFont type_font( "Arial", 11, QFont::Normal, QFont::StyleItalic );
00291 
00292   QTreeWidgetItem *group;
00293 
00294   // Allow a subgroup to open into a whole new group
00295   if( parent == NULL )
00296   {
00297     group = new QTreeWidgetItem( groups_tree_ );
00298     group->setText( 0, group_it.name_.c_str() );
00299     group->setFont( 0, top_level_font );
00300     group->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, GROUP ) ) );
00301     groups_tree_->addTopLevelItem( group );
00302   }
00303   else
00304   {
00305     group= new QTreeWidgetItem( parent );
00306     group->setText( 0, group_it.name_.c_str() );
00307     group->setFont( 0, top_level_font );
00308     group->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, GROUP ) ) );
00309     parent->addChild( group );
00310   }
00311 
00312   // Joints --------------------------------------------------------------
00313   QTreeWidgetItem *joints = new QTreeWidgetItem( group );
00314   joints->setText( 0, "Joints" );
00315   joints->setFont( 0, type_font );
00316   joints->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, JOINT ) ) );
00317   group->addChild( joints );
00318 
00319   // Retrieve pointer to the shared kinematic model
00320   const robot_model::RobotModelConstPtr &model = config_data_->getRobotModel();
00321 
00322   // Loop through all aval. joints
00323   for( std::vector<std::string>::const_iterator joint_it = group_it.joints_.begin();
00324        joint_it != group_it.joints_.end(); ++joint_it )
00325   {
00326     QTreeWidgetItem *j = new QTreeWidgetItem( joints );
00327     j->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, JOINT ) ) );
00328     std::string joint_name;
00329 
00330     // Get the type of joint this is
00331     const robot_model::JointModel* jm = model->getJointModel(*joint_it);
00332     if(jm) // check if joint model was found
00333     {
00334       joint_name = *joint_it + " - " + jm->getTypeName();
00335     }
00336     else
00337     {
00338       joint_name = *joint_it;
00339     }
00340 
00341     // Add to tree
00342     j->setText( 0, joint_name.c_str() );
00343     joints->addChild( j );
00344   }
00345 
00346   // Links -------------------------------------------------------------
00347   QTreeWidgetItem *links = new QTreeWidgetItem( group );
00348   links->setText( 0, "Links" );
00349   links->setFont( 0, type_font );
00350   links->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, LINK ) ) );
00351   group->addChild( links );
00352 
00353   // Loop through all aval. links
00354   for( std::vector<std::string>::const_iterator joint_it = group_it.links_.begin();
00355        joint_it != group_it.links_.end(); ++joint_it )
00356   {
00357     QTreeWidgetItem *j = new QTreeWidgetItem( links );
00358     j->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, LINK ) ) );
00359     j->setText( 0, joint_it->c_str() );
00360     links->addChild( j );
00361   }
00362 
00363   // Chains -------------------------------------------------------------
00364   QTreeWidgetItem *chains = new QTreeWidgetItem( group );
00365   chains->setText( 0, "Chain" );
00366   chains->setFont( 0, type_font );
00367   chains->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, CHAIN ) ) );
00368   group->addChild( chains );
00369 
00370   // Warn if there is more than 1 chain per group
00371   static bool warn_once = true;
00372   if( group_it.chains_.size() > 1 && warn_once )
00373   {
00374     warn_once = false;
00375     QMessageBox::warning( this, "Group with Multiple Kinematic Chains", "Warning: this MoveIt Setup Assistant is only designed to handle one kinematic chain per group. The loaded SRDF has more than one kinematic chain for a group. A possible loss of data may occur.");
00376   }
00377 
00378   // Loop through all aval. chains
00379   for( std::vector<std::pair<std::string, std::string> >::const_iterator chain_it = group_it.chains_.begin();
00380        chain_it != group_it.chains_.end(); ++chain_it )
00381   {
00382     QTreeWidgetItem *j = new QTreeWidgetItem( chains );
00383     j->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, CHAIN ) ) );
00384     j->setText( 0, QString(chain_it->first.c_str() ).append("  ->  ").append( chain_it->second.c_str() ) );
00385     chains->addChild( j );
00386   }
00387 
00388   // Subgroups -------------------------------------------------------------
00389   QTreeWidgetItem *subgroups = new QTreeWidgetItem( group );
00390   subgroups->setText( 0, "Subgroups" );
00391   subgroups->setFont( 0, type_font );
00392   subgroups->setData( 0, Qt::UserRole, QVariant::fromValue( PlanGroupType( &group_it, SUBGROUP ) ) );
00393   group->addChild( subgroups );
00394 
00395   // Loop through all aval. subgroups
00396   for( std::vector<std::string>::iterator subgroup_it = group_it.subgroups_.begin();
00397        subgroup_it != group_it.subgroups_.end(); ++subgroup_it )
00398   {
00399     // Find group with this subgroups' name
00400 
00401     srdf::Model::Group *searched_group = NULL; // used for holding our search results
00402 
00403     for( std::vector<srdf::Model::Group>::iterator group2_it = config_data_->srdf_->groups_.begin();
00404          group2_it != config_data_->srdf_->groups_.end(); ++group2_it )
00405     {
00406       if( group2_it->name_ == *subgroup_it ) // this is the group we are looking for
00407       {
00408         searched_group = &(*group2_it);  // convert to pointer from iterator
00409         break; // we are done searching
00410       }
00411     }
00412 
00413 
00414     // Check if subgroup was found
00415     if( searched_group == NULL ) // not found
00416     {
00417       QMessageBox::critical( this, "Error Loading SRDF",
00418                              QString("Subgroup '").append( subgroup_it->c_str() ).append( "' of group '")
00419                              .append( group_it.name_.c_str() ).append( "' not found. Your SRDF is invalid" ));
00420       return; // TODO: something better for error handling?
00421     }
00422 
00423     // subgroup found!
00424 
00425     // Recurse this function for each new group
00426     loadGroupsTreeRecursive( *searched_group, subgroups );
00427   }
00428 
00429 
00430 }
00431 
00432 // ******************************************************************************************
00433 // Highlight the group of whatever element is selected in the tree view
00434 // ******************************************************************************************
00435 void PlanningGroupsWidget::previewSelected()
00436 {
00437   QTreeWidgetItem* item = groups_tree_->currentItem();
00438 
00439   // Check that something was actually selected
00440   if(item == NULL)
00441     return;
00442 
00443   // Get the user custom properties of the currently selected row
00444   PlanGroupType plan_group = item->data( 0, Qt::UserRole ).value<PlanGroupType>();
00445 
00446   // Unhighlight all links
00447   Q_EMIT unhighlightAll();
00448 
00449   // Highlight the group
00450   Q_EMIT( highlightGroup( plan_group.group_->name_ ) );
00451 }
00452 
00453 // ******************************************************************************************
00454 // Edit whatever element is selected in the tree view
00455 // ******************************************************************************************
00456 void PlanningGroupsWidget::editSelected()
00457 {
00458   QTreeWidgetItem* item = groups_tree_->currentItem();
00459 
00460   // Check that something was actually selected
00461   if(item == NULL)
00462     return;
00463 
00464   adding_new_group_ = false;
00465 
00466   // Get the user custom properties of the currently selected row
00467   PlanGroupType plan_group = item->data( 0, Qt::UserRole ).value<PlanGroupType>();
00468 
00469   if( plan_group.type_ == JOINT )
00470   {
00471     // Load the data
00472     loadJointsScreen( plan_group.group_ );
00473 
00474     // Switch to screen
00475     changeScreen( 1 ); // 1 is index of joints
00476   }
00477   else if( plan_group.type_ == LINK )
00478   {
00479     // Load the data
00480     loadLinksScreen( plan_group.group_ );
00481 
00482     // Switch to screen
00483     changeScreen( 2 );
00484   }
00485   else if( plan_group.type_ == CHAIN )
00486   {
00487     // Load the data
00488     loadChainScreen( plan_group.group_ );
00489 
00490     // Switch to screen
00491     changeScreen( 3 );
00492   }
00493   else if( plan_group.type_ == SUBGROUP )
00494   {
00495     // Load the data
00496     loadSubgroupsScreen( plan_group.group_ );
00497 
00498     // Switch to screen
00499     changeScreen( 4 );
00500   }
00501   else if( plan_group.type_ == GROUP )
00502   {
00503     // Load the data
00504     loadGroupScreen( plan_group.group_ );
00505 
00506     // Switch to screen
00507     changeScreen( 5 );
00508   }
00509   else
00510   {
00511     QMessageBox::critical( this, "Error Loading", "An internal error has occured while loading.");
00512   }
00513 }
00514 
00515 // ******************************************************************************************
00516 // Load the popup screen with correct data for joints
00517 // ******************************************************************************************
00518 void PlanningGroupsWidget::loadJointsScreen( srdf::Model::Group *this_group )
00519 {
00520   // Retrieve pointer to the shared kinematic model
00521   const robot_model::RobotModelConstPtr &model = config_data_->getRobotModel();
00522 
00523   // Get the names of the all joints
00524   const std::vector<std::string> &joints = model->getJointModelNames();
00525 
00526   if( joints.size() == 0 )
00527   {
00528     QMessageBox::critical( this, "Error Loading", "No joints found for robot model");
00529     return;
00530   }
00531 
00532   // Set the available joints (left box)
00533   joints_widget_->setAvailable( joints );
00534 
00535   // Set the selected joints (right box)
00536   joints_widget_->setSelected( this_group->joints_ );
00537 
00538   // Set the title
00539   joints_widget_->title_->setText( QString("Edit '").append( QString::fromUtf8( this_group->name_.c_str() ) )
00540                                    .append( "' Joint Collection") );
00541 
00542   // Remember what is currently being edited so we can later save changes
00543   current_edit_group_ = this_group->name_;
00544   current_edit_element_ = JOINT;
00545 }
00546 
00547 // ******************************************************************************************
00548 // Load the popup screen with correct data for links
00549 // ******************************************************************************************
00550 void PlanningGroupsWidget::loadLinksScreen( srdf::Model::Group *this_group )
00551 {
00552   // Retrieve pointer to the shared kinematic model
00553   const robot_model::RobotModelConstPtr &model = config_data_->getRobotModel();
00554 
00555   // Get the names of the all links
00556   const std::vector<std::string> &links = model->getLinkModelNames();
00557 
00558   if( links.size() == 0 )
00559   {
00560     QMessageBox::critical( this, "Error Loading", "No links found for robot model");
00561     return;
00562   }
00563 
00564   // Set the available links (left box)
00565   links_widget_->setAvailable( links );
00566 
00567   // Set the selected links (right box)
00568   links_widget_->setSelected( this_group->links_ );
00569 
00570   // Set the title
00571   links_widget_->title_->setText( QString("Edit '").append( QString::fromUtf8( this_group->name_.c_str() ) )
00572                                   .append( "' Link Collection") );
00573 
00574   // Remember what is currently being edited so we can later save changes
00575   current_edit_group_ = this_group->name_;
00576   current_edit_element_ = LINK;
00577 }
00578 
00579 // ******************************************************************************************
00580 // Load the popup screen with correct data for chains
00581 // ******************************************************************************************
00582 void PlanningGroupsWidget::loadChainScreen( srdf::Model::Group *this_group )
00583 {
00584   // Tell the kin chain widget to load up the chain from a kinematic model
00585   chain_widget_->setAvailable();
00586 
00587   // Make sure there isn't more than 1 chain pair
00588   if( this_group->chains_.size() > 1 )
00589   {
00590     QMessageBox::warning( this, "Multiple Kinematic Chains", "Warning: This setup assistant is only designed to handle one kinematic chain per group. The loaded SRDF has more than one kinematic chain for a group. A possible loss of data may occur.");
00591   }
00592 
00593   // Set the selected tip and base of chain if one exists
00594   if( this_group->chains_.size() > 0 )
00595   {
00596     chain_widget_->setSelected( this_group->chains_[0].first, this_group->chains_[0].second );
00597   }
00598 
00599   // Set the title
00600   chain_widget_->title_->setText( QString("Edit '").append( QString::fromUtf8( this_group->name_.c_str() ) )
00601                                   .append( "' Kinematic Chain") );
00602 
00603   // Remember what is currently being edited so we can later save changes
00604   current_edit_group_ = this_group->name_;
00605   current_edit_element_ = CHAIN;
00606 }
00607 
00608 // ******************************************************************************************
00609 // Load the popup screen with correct data for subgroups
00610 // ******************************************************************************************
00611 void PlanningGroupsWidget::loadSubgroupsScreen( srdf::Model::Group *this_group )
00612 {
00613   // Load all groups into the subgroup screen except the current group
00614   std::vector<std::string> subgroups;
00615 
00616   // Display all groups by looping through them
00617   for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
00618        group_it != config_data_->srdf_->groups_.end();  ++group_it )
00619   {
00620     if( group_it->name_ != this_group->name_ ) //  do not include current group
00621     {
00622       // add to available subgroups list
00623       subgroups.push_back( group_it->name_ );
00624     }
00625   }
00626 
00627   // Set the available subgroups (left box)
00628   subgroups_widget_->setAvailable( subgroups );
00629 
00630   // Set the selected subgroups (right box)
00631   subgroups_widget_->setSelected( this_group->subgroups_ );
00632 
00633   // Set the title
00634   subgroups_widget_->title_->setText( QString("Edit '").append( QString::fromUtf8( this_group->name_.c_str() ) )
00635                                       .append( "' Subgroups") );
00636 
00637   // Remember what is currently being edited so we can later save changes
00638   current_edit_group_ = this_group->name_;
00639   current_edit_element_ = SUBGROUP;
00640 }
00641 
00642 // ******************************************************************************************
00643 // Load the popup screen with correct data for groups
00644 // ******************************************************************************************
00645 void PlanningGroupsWidget::loadGroupScreen( srdf::Model::Group *this_group )
00646 {
00647   // Load the avail kin solvers. This function only runs once
00648   group_edit_widget_->loadKinematicPlannersComboBox();
00649 
00650   if( this_group == NULL ) // this is a new screen
00651   {
00652     current_edit_group_.clear(); // provide a blank group name
00653     group_edit_widget_->title_->setText( "Create New Planning Group" );
00654     group_edit_widget_->btn_delete_->hide();
00655     group_edit_widget_->new_buttons_widget_->show(); // helps user choose next step
00656     group_edit_widget_->btn_save_->hide(); // this is only for edit mode
00657   }
00658   else // load the group name into the widget
00659   {
00660     current_edit_group_ = this_group->name_;
00661     group_edit_widget_->title_->setText( QString("Edit Planning Group '")
00662                                          .append( current_edit_group_.c_str() ).append("'") );
00663     group_edit_widget_->btn_delete_->show();
00664     group_edit_widget_->new_buttons_widget_->hide(); // not necessary for existing groups
00665     group_edit_widget_->btn_save_->show(); // this is only for edit mode
00666   }
00667 
00668   // Set the data in the edit box
00669   group_edit_widget_->setSelected( current_edit_group_ );
00670 
00671 
00672   // Remember what is currently being edited so we can later save changes
00673   current_edit_element_ = GROUP;
00674 }
00675 
00676 // ******************************************************************************************
00677 // Delete a group
00678 // ******************************************************************************************
00679 void PlanningGroupsWidget::deleteGroup()
00680 {
00681   std::string group = current_edit_group_;
00682   if (group.empty())
00683   {
00684     QTreeWidgetItem* item = groups_tree_->currentItem();
00685     // Check that something was actually selected
00686     if(item == NULL)
00687       return;
00688     // Get the user custom properties of the currently selected row
00689     PlanGroupType plan_group = item->data( 0, Qt::UserRole ).value<PlanGroupType>();
00690     if (plan_group.group_)
00691       group = plan_group.group_->name_;
00692   }
00693   else
00694     current_edit_group_.clear();
00695   if (group.empty())
00696     return;
00697 
00698   // Find the group we are editing based on the goup name string
00699   srdf::Model::Group *searched_group = config_data_->findGroupByName( group );
00700 
00701   // Confirm user wants to delete group
00702   if( QMessageBox::question( this, "Confirm Group Deletion",
00703                              QString("Are you sure you want to delete the planning group '")
00704                              .append( searched_group->name_.c_str() )
00705                              .append( "'? This will also delete all references in subgroups, robot poses and end effectors." ),
00706                              QMessageBox::Ok | QMessageBox::Cancel)
00707       == QMessageBox::Cancel )
00708   {
00709     return;
00710   }
00711 
00712   // delete all robot poses that use that group's name
00713   bool haveConfirmedGroupStateDeletion = false;
00714   bool haveDeletedGroupState = true;
00715   while( haveDeletedGroupState )
00716   {
00717     haveDeletedGroupState = false;
00718     for( std::vector<srdf::Model::GroupState>::iterator pose_it = config_data_->srdf_->group_states_.begin();
00719          pose_it != config_data_->srdf_->group_states_.end(); ++pose_it )
00720     {
00721       // check if this group state depends on the currently being deleted group
00722       if( pose_it->group_ == searched_group->name_ )
00723       {
00724         if( !haveConfirmedGroupStateDeletion )
00725         {
00726           haveConfirmedGroupStateDeletion = true;
00727 
00728           // confirm the user wants to delete group states
00729           if( QMessageBox::question( this, "Confirm Group State Deletion",
00730                                      QString("The group that is about to be deleted has robot poses (robot states) that depend on this group. Are you sure you want to delete this group as well as all dependend robot poses?"),
00731                                      QMessageBox::Ok | QMessageBox::Cancel)
00732               == QMessageBox::Cancel )
00733           {
00734             return;
00735           }
00736         }
00737 
00738         // the user has confirmed, now delete this group state
00739         config_data_->srdf_->group_states_.erase( pose_it );
00740         haveDeletedGroupState = true;
00741         break; // you can only delete 1 item in vector before invalidating iterator
00742       }
00743     }
00744   }
00745 
00746   // delete all end effectors that use that group's name
00747   bool haveConfirmedEndEffectorDeletion = false;
00748   bool haveDeletedEndEffector = true;
00749   while( haveDeletedEndEffector )
00750   {
00751     haveDeletedEndEffector = false;
00752     for( std::vector<srdf::Model::EndEffector>::iterator effector_it = config_data_->srdf_->end_effectors_.begin();
00753          effector_it != config_data_->srdf_->end_effectors_.end(); ++effector_it )
00754     {
00755       // check if this group state depends on the currently being deleted group
00756       if( effector_it->component_group_ == searched_group->name_ )
00757       {
00758         if( !haveConfirmedEndEffectorDeletion )
00759         {
00760           haveConfirmedEndEffectorDeletion = true;
00761 
00762           // confirm the user wants to delete group states
00763           if( QMessageBox::question( this, "Confirm End Effector Deletion",
00764                                      QString("The group that is about to be deleted has end effectors (grippers) that depend on this group. Are you sure you want to delete this group as well as all dependend end effectors?"),
00765                                      QMessageBox::Ok | QMessageBox::Cancel)
00766               == QMessageBox::Cancel )
00767           {
00768             return;
00769           }
00770         }
00771 
00772         // the user has confirmed, now delete this group state
00773         config_data_->srdf_->end_effectors_.erase( effector_it );
00774         haveDeletedEndEffector = true;
00775         break; // you can only delete 1 item in vector before invalidating iterator
00776       }
00777     }
00778   }
00779 
00780   // delete actual group
00781   for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
00782        group_it != config_data_->srdf_->groups_.end(); ++group_it )
00783   {
00784     // check if this is the group we want to delete
00785     if( group_it->name_ == group ) // string match
00786     {
00787       config_data_->srdf_->groups_.erase( group_it );
00788       break;
00789     }
00790   }
00791 
00792   // loop again to delete all subgroup references
00793   for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
00794        group_it != config_data_->srdf_->groups_.end(); ++group_it )
00795   {
00796     // delete all subgroup references
00797     bool deleted_subgroup = true;
00798     while( deleted_subgroup )
00799     {
00800       deleted_subgroup = false;
00801 
00802       // check if the subgroups reference our deleted group
00803       for( std::vector<std::string>::iterator subgroup_it = group_it->subgroups_.begin();
00804            subgroup_it != group_it->subgroups_.end(); ++subgroup_it )
00805       {
00806         // Check if that subgroup references the deletion group. if so, delete it
00807         if( subgroup_it->compare( group ) == 0 ) // same name
00808         {
00809           group_it->subgroups_.erase( subgroup_it ); // delete
00810           deleted_subgroup = true;
00811           break;
00812         }
00813       }
00814     }
00815   }
00816 
00817   // Switch to main screen
00818   showMainScreen();
00819 
00820   // Reload main screen table
00821   loadGroupsTree();
00822 
00823   // Update the kinematic model with changes
00824   config_data_->updateRobotModel();
00825 }
00826 
00827 // ******************************************************************************************
00828 // Create a new, empty group
00829 // ******************************************************************************************
00830 void PlanningGroupsWidget::addGroup()
00831 {
00832   adding_new_group_ = true;
00833 
00834   // Load the data
00835   loadGroupScreen( NULL ); // NULL indicates this is a new group, not an existing one
00836 
00837   // Switch to screen
00838   changeScreen( 5 );
00839 }
00840 
00841 
00842 // ******************************************************************************************
00843 // Call when joints edit sceen is done and needs to be saved
00844 // ******************************************************************************************
00845 void PlanningGroupsWidget::saveJointsScreen()
00846 {
00847   // Find the group we are editing based on the goup name string
00848   srdf::Model::Group *searched_group = config_data_->findGroupByName( current_edit_group_ );
00849 
00850   // clear the old data
00851   searched_group->joints_.clear();
00852 
00853   // copy the data
00854   for( int i = 0; i < joints_widget_->selected_data_table_->rowCount(); ++i )
00855   {
00856     searched_group->joints_.push_back( joints_widget_->selected_data_table_->item( i, 0 )->text().toStdString() );
00857   }
00858 
00859   // Switch to main screen
00860   showMainScreen();
00861 
00862   // Reload main screen table
00863   loadGroupsTree();
00864 
00865   // Update the kinematic model with changes
00866   config_data_->updateRobotModel();
00867 }
00868 
00869 // ******************************************************************************************
00870 // Call when links edit sceen is done and needs to be saved
00871 // ******************************************************************************************
00872 void PlanningGroupsWidget::saveLinksScreen()
00873 {
00874   // Find the group we are editing based on the goup name string
00875   srdf::Model::Group *searched_group = config_data_->findGroupByName( current_edit_group_ );
00876 
00877   // Find the group we are editing based on the goup name string
00878   // clear the old data
00879   searched_group->links_.clear();
00880 
00881   // copy the data
00882   for( int i = 0; i < links_widget_->selected_data_table_->rowCount(); ++i )
00883   {
00884     searched_group->links_.push_back( links_widget_->selected_data_table_->item( i, 0 )->text().toStdString() );
00885   }
00886 
00887   // Switch to main screen
00888   showMainScreen();
00889 
00890   // Reload main screen table
00891   loadGroupsTree();
00892 
00893   // Update the kinematic model with changes
00894   config_data_->updateRobotModel();
00895 }
00896 
00897 // ******************************************************************************************
00898 // Call when chains edit sceen is done and needs to be saved
00899 // ******************************************************************************************
00900 void PlanningGroupsWidget::saveChainScreen()
00901 {
00902   // Find the group we are editing based on the goup name string
00903   srdf::Model::Group *searched_group = config_data_->findGroupByName( current_edit_group_ );
00904 
00905   // Get a reference to the supplied strings
00906   const std::string &tip = chain_widget_->tip_link_field_->text().toStdString();
00907   const std::string &base = chain_widget_->base_link_field_->text().toStdString();
00908 
00909   // Check that box the tip and base, or neither, have text
00910   if( ( !tip.empty() && base.empty() ) ||
00911       ( tip.empty() && !base.empty() ) )
00912   {
00913     QMessageBox::warning( this, "Error Saving", "You must specify a link for both the base and tip, or leave both blank.");
00914     return;
00915   }
00916 
00917   // Check that both given links are valid links, unless they are both blank
00918   if( !tip.empty() && !base.empty() )
00919   {
00920     // Check that they are not the same link
00921     if( tip.compare( base ) == 0 ) // they are same
00922     {
00923       QMessageBox::warning( this, "Error Saving", "Tip and base link cannot be the same link.");
00924       return;
00925     }
00926 
00927     bool found_tip = false;
00928     bool found_base = false;
00929     const std::vector<std::string> &links = config_data_->getRobotModel()->getLinkModelNames();
00930 
00931     for( std::vector<std::string>::const_iterator link_it = links.begin(); link_it != links.end(); ++link_it )
00932     {
00933       // Check if string matches either of user specefied links
00934       if( link_it->compare(tip) == 0) // they are same
00935         found_tip = true;
00936       else if( link_it->compare(base) == 0) // they are same
00937         found_base = true;
00938 
00939       // Check if we are done searching
00940       if( found_tip && found_base )
00941         break;
00942     }
00943 
00944     // Check if we found both links
00945     if( !found_tip || !found_base )
00946     {
00947       QMessageBox::warning( this, "Error Saving", "Tip or base link(s) were not found in kinematic chain.");
00948       return;
00949     }
00950 
00951   }
00952 
00953   // clear the old data
00954   searched_group->chains_.clear();
00955 
00956   // Save the data if there is data to save
00957   if( !tip.empty() && !base.empty() )
00958   {
00959     searched_group->chains_.push_back( std::pair<std::string,std::string>( base, tip ) );
00960   }
00961 
00962   // Switch to main screen
00963   showMainScreen();
00964 
00965   // Reload main screen table
00966   loadGroupsTree();
00967 
00968   // Update the kinematic model with changes
00969   config_data_->updateRobotModel();
00970 }
00971 
00972 // ******************************************************************************************
00973 // Call when subgroups edit sceen is done and needs to be saved
00974 // ******************************************************************************************
00975 void PlanningGroupsWidget::saveSubgroupsScreen()
00976 {
00977   // Find the group we are editing based on the goup name string
00978   srdf::Model::Group *searched_group = config_data_->findGroupByName( current_edit_group_ );
00979 
00980   // Check for cycles -------------------------------
00981 
00982   // Create vector index of all nodes
00983   std::map<std::string,int> group_nodes;
00984 
00985   // Create vector of all nodes for use as id's
00986   int node_id = 0;
00987   for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
00988        group_it != config_data_->srdf_->groups_.end(); ++group_it )
00989   {
00990     // Add string to vector
00991     group_nodes.insert( std::pair<std::string,int>(group_it->name_, node_id) );
00992     ++node_id;
00993   }
00994 
00995   // Create the empty graph
00996   typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS> Graph;
00997   typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
00998   Graph g( group_nodes.size() );
00999 
01000 
01001   // Traverse the group list again, this time inserting subgroups into graph
01002   int from_id = 0; // track the outer node we are on to reduce searches performed
01003   for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
01004        group_it != config_data_->srdf_->groups_.end(); ++group_it )
01005   {
01006 
01007     // Check if group_it is same as current group
01008     if( group_it->name_ == searched_group->name_ ) // yes, same group
01009     {
01010 
01011       // add new subgroup list from widget, not old one. this way we can check for new cycles
01012       for( int i = 0; i < subgroups_widget_->selected_data_table_->rowCount(); ++i )
01013       {
01014         // Get std::string of subgroup
01015         const std::string to_string = subgroups_widget_->selected_data_table_->item( i, 0 )->text().toStdString();
01016 
01017         // convert subgroup string to associated id
01018         int to_id = group_nodes[ to_string ];
01019 
01020         // Add edge from from_id to to_id
01021         add_edge( from_id, to_id, g);
01022       }
01023     }
01024     else //this group is not the group we are editing, so just add subgroups from memory
01025     {
01026       // add new subgroup list from widget, not old one. this way we can check for new cycles
01027       for( unsigned int i = 0; i < group_it->subgroups_.size(); ++i )
01028       {
01029         // Get std::string of subgroup
01030         const std::string to_string = group_it->subgroups_.at(i);
01031 
01032         // convert subgroup string to associated id
01033         int to_id = group_nodes[ to_string ];
01034 
01035         // Add edge from from_id to to_id
01036         add_edge( from_id, to_id, g);
01037       }
01038     }
01039 
01040     ++from_id;
01041   }
01042 
01043   // Check for cycles
01044   bool has_cycle = false;
01045   cycle_detector vis(has_cycle);
01046   boost::depth_first_search(g, visitor(vis));
01047 
01048   if( has_cycle )
01049   {
01050     // report to user the error
01051     QMessageBox::warning( this, "Error Saving", "Depth first search reveals a cycle in the subgroups");
01052     return;
01053   }
01054 
01055   // clear the old data
01056   searched_group->subgroups_.clear();
01057 
01058   // copy the data
01059   for( int i = 0; i < subgroups_widget_->selected_data_table_->rowCount(); ++i )
01060   {
01061     searched_group->subgroups_.push_back( subgroups_widget_->selected_data_table_->item( i, 0 )->text().toStdString() );
01062   }
01063 
01064   // Switch to main screen
01065   showMainScreen();
01066 
01067   // Reload main screen table
01068   loadGroupsTree();
01069 
01070   // Update the kinematic model with changes
01071   config_data_->updateRobotModel();
01072 }
01073 
01074 // ******************************************************************************************
01075 // Call when groups edit sceen is done and needs to be saved
01076 // ******************************************************************************************
01077 bool PlanningGroupsWidget::saveGroupScreen()
01078 {
01079   // Get a reference to the supplied strings
01080   const std::string &group_name = group_edit_widget_->group_name_field_->text().toStdString();
01081   const std::string &kinematics_solver = group_edit_widget_->kinematics_solver_field_->currentText().toStdString();
01082   const std::string &kinematics_resolution = group_edit_widget_->kinematics_resolution_field_->text().toStdString();
01083   const std::string &kinematics_timeout = group_edit_widget_->kinematics_timeout_field_->text().toStdString();
01084   const std::string &kinematics_attempts = group_edit_widget_->kinematics_attempts_field_->text().toStdString();
01085 
01086   // Used for editing existing groups
01087   srdf::Model::Group *searched_group = NULL;
01088 
01089   // Check that a valid group name has been given
01090   if( group_name.empty() )
01091   {
01092     QMessageBox::warning( this, "Error Saving", "A name must be given for the group!" );
01093     return false;
01094   }
01095 
01096   // Check if this is an existing group
01097   if( !current_edit_group_.empty() )
01098   {
01099     // Find the group we are editing based on the goup name string
01100     searched_group = config_data_->findGroupByName( current_edit_group_ );
01101   }
01102 
01103   // Check that the group name is unique
01104   for( std::vector<srdf::Model::Group>::const_iterator group_it = config_data_->srdf_->groups_.begin();
01105        group_it != config_data_->srdf_->groups_.end();  ++group_it )
01106   {
01107 
01108     if( group_it->name_.compare( group_name ) == 0 ) // the names are the same
01109     {
01110       // is this our existing group? check if group pointers are same
01111       if( &(*group_it) != searched_group )
01112       {
01113         QMessageBox::warning( this, "Error Saving", "A group already exists with that name!" );
01114         return false;
01115       }
01116     }
01117   }
01118 
01119   // Check that the resolution is an double number
01120   double kinematics_resolution_double;
01121   try
01122   {
01123     kinematics_resolution_double = boost::lexical_cast<double>(kinematics_resolution);
01124   }
01125   catch( boost::bad_lexical_cast& )
01126   {
01127     QMessageBox::warning( this, "Error Saving", "Unable to convert kinematics resolution to a double number." );
01128     return false;
01129   }
01130 
01131   // Check that the timeout is a double number
01132   double kinematics_timeout_double;
01133   try
01134   {
01135     kinematics_timeout_double = boost::lexical_cast<double>(kinematics_timeout);
01136   }
01137   catch( boost::bad_lexical_cast& )
01138   {
01139     QMessageBox::warning( this, "Error Saving", "Unable to convert kinematics solver timeout to a double number." );
01140     return false;
01141   }
01142 
01143   // Check that the attempts is an int number
01144   int kinematics_attempts_int;
01145   try
01146   {
01147     kinematics_attempts_int = boost::lexical_cast<int>(kinematics_attempts);
01148   }
01149   catch( boost::bad_lexical_cast& )
01150   {
01151     QMessageBox::warning( this, "Error Saving", "Unable to convert kinematics solver attempts to an int number." );
01152     return false;
01153   }
01154 
01155   // Check that all numbers are >0
01156   if(kinematics_resolution_double <= 0)
01157   {
01158     QMessageBox::warning( this, "Error Saving", "Kinematics solver search resolution must be greater than 0." );
01159     return false;
01160   }
01161   if(kinematics_timeout_double <= 0)
01162   {
01163     QMessageBox::warning( this, "Error Saving", "Kinematics solver search timeout must be greater than 0." );
01164     return false;
01165   }
01166   if(kinematics_attempts_int <= 0)
01167   {
01168     QMessageBox::warning( this, "Error Saving", "Kinematics solver attempts must be greater than 0." );
01169     return false;
01170   }
01171 
01172   adding_new_group_ = false;
01173 
01174   // Save the new group name or create the new group
01175   if( searched_group == NULL ) // create new
01176   {
01177     srdf::Model::Group new_group;
01178     new_group.name_ = group_name;
01179     config_data_->srdf_->groups_.push_back( new_group );
01180     adding_new_group_ = true; // remember this group is new
01181   }
01182   else
01183   {
01184     // Remember old group name
01185     const std::string old_group_name = searched_group->name_;
01186 
01187     // Change group name
01188     searched_group->name_ = group_name;
01189 
01190     // Change all references to this group name in other subgroups
01191     // Loop through every group
01192     for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
01193          group_it != config_data_->srdf_->groups_.end();  ++group_it )
01194     {
01195       // Loop through every subgroup
01196       for( std::vector<std::string>::iterator subgroup_it = group_it->subgroups_.begin();
01197            subgroup_it != group_it->subgroups_.end(); ++subgroup_it )
01198       {
01199         // Check if that subgroup references old group name. if so, update it
01200         if( subgroup_it->compare( old_group_name ) == 0 ) // same name
01201         {
01202           subgroup_it->assign(group_name); // updated
01203         }
01204       }
01205     }
01206   }
01207 
01208   // Save the group meta data
01209   config_data_->group_meta_data_[ group_name ].kinematics_solver_ = kinematics_solver;
01210   config_data_->group_meta_data_[ group_name ].kinematics_solver_search_resolution_ = kinematics_resolution_double;
01211   config_data_->group_meta_data_[ group_name ].kinematics_solver_timeout_ = kinematics_timeout_double;
01212   config_data_->group_meta_data_[ group_name ].kinematics_solver_attempts_ = kinematics_attempts_int;
01213 
01214   // Reload main screen table
01215   loadGroupsTree();
01216 
01217   // Update the current edit group so that we can proceed to the next screen, if user desires
01218   current_edit_group_ = group_name;
01219 
01220   return true;
01221 }
01222 
01223 // ******************************************************************************************
01224 // Call when a new group is created and ready to progress to next screen
01225 // ******************************************************************************************
01226 void PlanningGroupsWidget::saveGroupScreenEdit()
01227 {
01228   // Save the group
01229   if( !saveGroupScreen() )
01230     return;
01231 
01232   // Switch to main screen
01233   showMainScreen();
01234 }
01235 
01236 // ******************************************************************************************
01237 // Call when a new group is created and ready to progress to next screen
01238 // ******************************************************************************************
01239 void PlanningGroupsWidget::saveGroupScreenJoints()
01240 {
01241   // Save the group
01242   if( !saveGroupScreen() )
01243     return;
01244 
01245   // Find the group we are editing based on the goup name string
01246   loadJointsScreen( config_data_->findGroupByName( current_edit_group_ ) );
01247 
01248   // Switch to screen
01249   changeScreen( 1 ); // 1 is index of joints
01250 }
01251 
01252 // ******************************************************************************************
01253 // Call when a new group is created and ready to progress to next screen
01254 // ******************************************************************************************
01255 void PlanningGroupsWidget::saveGroupScreenLinks()
01256 {
01257   // Save the group
01258   if( !saveGroupScreen() )
01259     return;
01260 
01261   // Find the group we are editing based on the goup name string
01262   loadLinksScreen( config_data_->findGroupByName( current_edit_group_ ) );
01263 
01264   // Switch to screen
01265   changeScreen( 2 ); // 2 is index of links
01266 }
01267 
01268 // ******************************************************************************************
01269 // Call when a new group is created and ready to progress to next screen
01270 // ******************************************************************************************
01271 void PlanningGroupsWidget::saveGroupScreenChain()
01272 {
01273   // Save the group
01274   if( !saveGroupScreen() )
01275     return;
01276 
01277   // Find the group we are editing based on the goup name string
01278   loadChainScreen( config_data_->findGroupByName( current_edit_group_ ) );
01279 
01280   // Switch to screen
01281   changeScreen( 3 );
01282 }
01283 
01284 // ******************************************************************************************
01285 // Call when a new group is created and ready to progress to next screen
01286 // ******************************************************************************************
01287 void PlanningGroupsWidget::saveGroupScreenSubgroups()
01288 {
01289   // Save the group
01290   if( !saveGroupScreen() )
01291     return;
01292 
01293   // Find the group we are editing based on the goup name string
01294   loadSubgroupsScreen( config_data_->findGroupByName( current_edit_group_ ) );
01295 
01296   // Switch to screen
01297   changeScreen( 4 );
01298 }
01299 
01300 // ******************************************************************************************
01301 // Call when edit screen is canceled
01302 // ******************************************************************************************
01303 void PlanningGroupsWidget::cancelEditing()
01304 {
01305   if (!current_edit_group_.empty() && adding_new_group_)
01306   {
01307     srdf::Model::Group *editing = config_data_->findGroupByName( current_edit_group_ );
01308     if( editing && editing->joints_.empty() && editing->links_.empty() &&
01309         editing->chains_.empty() && editing->subgroups_.empty())
01310     {
01311       config_data_->group_meta_data_.erase(editing->name_);
01312       for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
01313            group_it != config_data_->srdf_->groups_.end();  ++group_it )
01314         if (&(*group_it) == editing)
01315         {
01316           config_data_->srdf_->groups_.erase(group_it);
01317           break;
01318         }
01319       current_edit_group_.clear();
01320       // Load the data to the tree
01321       loadGroupsTree();
01322     }
01323   }
01324 
01325   // Switch to main screen
01326   showMainScreen();
01327 }
01328 
01329 // ******************************************************************************************
01330 // Called when setup assistant navigation switches to this screen
01331 // ******************************************************************************************
01332 void PlanningGroupsWidget::focusGiven()
01333 {
01334   // Show the current groups screen
01335   showMainScreen();
01336 
01337   // Load the data to the tree
01338   loadGroupsTree();
01339 
01340 }
01341 
01342 // ******************************************************************************************
01343 // Expand/Collapse Tree
01344 // ******************************************************************************************
01345 void PlanningGroupsWidget::alterTree( const QString &link )
01346 {
01347   if( link.contains("expand") )
01348     groups_tree_->expandAll();
01349   else
01350     groups_tree_->collapseAll();
01351 }
01352 
01353 // ******************************************************************************************
01354 // Switch to current groups view
01355 // ******************************************************************************************
01356 void PlanningGroupsWidget::showMainScreen()
01357 {
01358   stacked_layout_->setCurrentIndex( 0 );
01359 
01360   // Announce that this widget is not in modal mode
01361   Q_EMIT isModal( false );
01362 }
01363 
01364 // ******************************************************************************************
01365 // Switch which screen is being shown
01366 // ******************************************************************************************
01367 void PlanningGroupsWidget::changeScreen( int index )
01368 {
01369   stacked_layout_->setCurrentIndex( index );
01370 
01371   // Announce this widget's mode
01372   Q_EMIT isModal( index != 0 );
01373 }
01374 
01375 // ******************************************************************************************
01376 // Called from Double List widget to highlight a link
01377 // ******************************************************************************************
01378 void PlanningGroupsWidget::previewSelectedLink( std::vector<std::string> links )
01379 {
01380   // Unhighlight all links
01381   Q_EMIT unhighlightAll();
01382 
01383   for(int i = 0; i < links.size(); ++i)
01384   {
01385     if( links[i].empty() )
01386     {
01387       continue;
01388     }
01389 
01390     std::cout << "    previewSelectedLink " << links[i] << std::endl;
01391 
01392     // Highlight link
01393     Q_EMIT highlightLink( links[i] );
01394   }
01395 }
01396 
01397 // ******************************************************************************************
01398 // Called from Double List widget to highlight joints
01399 // ******************************************************************************************
01400 void PlanningGroupsWidget::previewSelectedJoints( std::vector<std::string> joints )
01401 {
01402   // Unhighlight all links
01403   Q_EMIT unhighlightAll();
01404 
01405   for(int i = 0; i < joints.size(); ++i)
01406   {
01407 
01408     const robot_model::JointModel *joint_model = config_data_->getRobotModel()->getJointModel( joints[i] );
01409 
01410     // Check that a joint model was found
01411     if( !joint_model )
01412     {
01413       continue;
01414     }
01415 
01416     // Get the name of the link
01417     const std::string link = joint_model->getChildLinkModel()->getName();
01418 
01419     if( link.empty() )
01420     {
01421       continue;
01422     }
01423 
01424     // Highlight link
01425     Q_EMIT highlightLink( link );
01426   }
01427 }
01428 
01429 // ******************************************************************************************
01430 // Called from Double List widget to highlight a subgroup
01431 // ******************************************************************************************
01432 void PlanningGroupsWidget::previewSelectedSubgroup( std::vector<std::string> groups )
01433 {
01434   // Unhighlight all links
01435   Q_EMIT unhighlightAll();
01436 
01437   for(int i = 0; i < groups.size(); ++i)
01438   {
01439     // Highlight group
01440     Q_EMIT highlightGroup( groups[i] );
01441   }
01442 }
01443 
01444 
01445 
01446 } // namespace
01447 
01448 
01449 // ******************************************************************************************
01450 // ******************************************************************************************
01451 // CLASS
01452 // ******************************************************************************************
01453 // ******************************************************************************************
01454 
01455 PlanGroupType::PlanGroupType( srdf::Model::Group *group, const moveit_setup_assistant::GroupType type )
01456   : group_( group ), type_( type )
01457 {
01458 }


moveit_setup_assistant
Author(s): Dave Coleman
autogenerated on Mon Oct 6 2014 02:32:27