$search
00001 /* 00002 * Copyright (c) 2008, Willow Garage, Inc. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of the Willow Garage, Inc. nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include <QColor> 00031 00032 #include <tf/transform_listener.h> 00033 00034 #include "rviz/config.h" 00035 #include "rviz/frame_manager.h" 00036 #include "rviz/properties/property.h" 00037 #include "rviz/properties/property_manager.h" 00038 #include "rviz/properties/property_widget_item.h" 00039 #include "rviz/properties/property_tree_widget.h" 00040 #include "rviz/properties/topic_info_variant.h" 00041 #include "rviz/properties/color_item.h" 00042 #include "rviz/properties/enum_item.h" 00043 #include "rviz/properties/edit_enum_item.h" 00044 #include "rviz/properties/compound_widget_item.h" 00045 00046 namespace rviz 00047 { 00048 00049 static const QColor ERROR_COLOR(178, 23, 46); 00050 static const QColor WARN_COLOR(222, 213, 17); 00051 00052 void PropertyBase::writeToGrid() 00053 { 00054 // Any change events coming from the grid during a "writeToGrid()" 00055 // call are caused by us, not by the user, so make sure we don't 00056 // end up calling readFromGrid() as a result (i.e. ignore them). 00057 bool ign = grid_->setIgnoreChanges( true ); 00058 doWriteToGrid(); 00059 grid_->setIgnoreChanges( ign ); 00060 } 00061 00062 PropertyWidgetItem* getCategoryPGProperty(const CategoryPropertyWPtr& wprop) 00063 { 00064 CategoryPropertyPtr prop = wprop.lock(); 00065 00066 if (prop) 00067 { 00068 return prop->getWidgetItem(); 00069 } 00070 00071 return NULL; 00072 } 00073 00074 void setPropertyHelpText(PropertyTreeWidget* grid, PropertyWidgetItem* widget_item, const std::string& text) 00075 { 00076 if( widget_item ) 00077 { 00078 bool ign = grid->setIgnoreChanges( true ); 00079 widget_item->setWhatsThis( 0, QString::fromStdString( text )); 00080 widget_item->setWhatsThis( 1, QString::fromStdString( text )); 00081 grid->setIgnoreChanges( ign ); 00082 } 00083 } 00084 00085 void setPropertyToColors(PropertyTreeWidget* grid, PropertyWidgetItem* widget_item, const QColor& fg_color, const QColor& bg_color, uint32_t column) 00086 { 00087 if( widget_item ) 00088 { 00089 bool ign = grid->setIgnoreChanges( true ); 00090 widget_item->setForeground( column, fg_color ); 00091 widget_item->setBackground( column, bg_color ); 00092 grid->setIgnoreChanges( ign ); 00093 } 00094 } 00095 00096 void setPropertyToError(PropertyTreeWidget* grid, PropertyWidgetItem* property, uint32_t column) 00097 { 00098 setPropertyToColors(grid, property, Qt::white, ERROR_COLOR, column); 00099 } 00100 00101 void setPropertyToWarn(PropertyTreeWidget* grid, PropertyWidgetItem* property, uint32_t column) 00102 { 00103 setPropertyToColors(grid, property, Qt::white, WARN_COLOR, column); 00104 } 00105 00106 void setPropertyToOK(PropertyTreeWidget* grid, PropertyWidgetItem* property, uint32_t column) 00107 { 00108 setPropertyToColors(grid, property, Qt::black, Qt::white, column); 00109 } 00110 00111 void setPropertyToDisabled(PropertyTreeWidget* grid, PropertyWidgetItem* property, uint32_t column) 00112 { 00113 setPropertyToColors(grid, property, QColor(0x33, 0x44, 0x44), QColor(0xaa, 0xaa, 0xaa), column); 00114 } 00115 00116 PropertyBase::PropertyBase() 00117 : grid_(NULL) 00118 , widget_item_(NULL) 00119 , user_data_(NULL) 00120 , manager_(NULL) 00121 { 00122 } 00123 00124 PropertyBase::~PropertyBase() 00125 { 00126 delete widget_item_; 00127 } 00128 00129 void PropertyBase::reset() 00130 { 00131 grid_ = 0; 00132 00133 delete widget_item_; 00134 widget_item_ = 0; 00135 } 00136 00137 void PropertyBase::setPropertyTreeWidget(PropertyTreeWidget* grid) 00138 { 00139 grid_ = grid; 00140 } 00141 00142 void PropertyBase::hide() 00143 { 00144 if( widget_item_ ) 00145 { 00146 widget_item_->setHidden( true ); 00147 } 00148 } 00149 00150 void PropertyBase::show() 00151 { 00152 if( widget_item_ ) 00153 { 00154 widget_item_->setHidden( false ); 00155 } 00156 } 00157 00158 bool PropertyBase::isSelected() 00159 { 00160 if( widget_item_ && grid_ ) 00161 { 00162 return grid_->currentItem() == widget_item_; 00163 } 00164 00165 return false; 00166 } 00167 00168 void PropertyBase::changed() 00169 { 00170 // I needed to purge boost::signal, and I didn't really want to make 00171 // every Property a QObject. There is only one class which needs to 00172 // be notified of property changes, and that is PropertyManager. 00173 // Therefore I'm making an explicit function call connection instead 00174 // of a Qt signal or a boost signal. 00175 if( manager_ ) 00176 { 00177 manager_->propertySet( shared_from_this() ); 00178 } 00179 } 00180 00181 StatusProperty::StatusProperty(const std::string& name, const std::string& prefix, const CategoryPropertyWPtr& parent, void* user_data) 00182 : name_(name) 00183 , prefix_(prefix) 00184 , parent_(parent) 00185 , top_widget_item_(0) 00186 , enabled_(true) 00187 , prefix_changed_(false) 00188 , top_status_(status_levels::Ok) 00189 { 00190 user_data_ = user_data; 00191 } 00192 00193 StatusProperty::~StatusProperty() 00194 { 00195 delete top_widget_item_; 00196 } 00197 00198 void StatusProperty::enable() 00199 { 00200 boost::mutex::scoped_lock lock(status_mutex_); 00201 enabled_ = true; 00202 00203 changed(); 00204 } 00205 00206 void StatusProperty::disable() 00207 { 00208 clear(); 00209 00210 boost::mutex::scoped_lock lock(status_mutex_); 00211 enabled_ = false; 00212 00213 changed(); 00214 } 00215 00216 void StatusProperty::setPrefix(const std::string& prefix) 00217 { 00218 boost::mutex::scoped_lock lock(status_mutex_); 00219 prefix_ = prefix; 00220 prefix_changed_ = true; 00221 changed(); 00222 } 00223 00224 void StatusProperty::clear() 00225 { 00226 boost::mutex::scoped_lock lock(status_mutex_); 00227 00228 if (!enabled_) 00229 { 00230 return; 00231 } 00232 00233 M_StringToStatus::iterator it = statuses_.begin(); 00234 M_StringToStatus::iterator end = statuses_.end(); 00235 for (; it != end; ++it) 00236 { 00237 Status& status = it->second; 00238 status.kill = true; 00239 } 00240 00241 // Update the top level status here so that it can be used immediately 00242 updateTopLevelStatus(); 00243 00244 changed(); 00245 } 00246 00247 void StatusProperty::updateTopLevelStatus() 00248 { 00249 top_status_ = status_levels::Ok; 00250 M_StringToStatus::iterator it = statuses_.begin(); 00251 M_StringToStatus::iterator end = statuses_.end(); 00252 for (; it != end; ++it) 00253 { 00254 Status& status = it->second; 00255 00256 if (status.kill) 00257 { 00258 continue; 00259 } 00260 00261 if (status.level > top_status_) 00262 { 00263 top_status_ = status.level; 00264 } 00265 } 00266 } 00267 00268 void StatusProperty::setStatus(StatusLevel level, const std::string& name, const std::string& text) 00269 { 00270 boost::mutex::scoped_lock lock(status_mutex_); 00271 00272 if (!enabled_) 00273 { 00274 return; 00275 } 00276 00277 Status& status = statuses_[name]; 00278 00279 // Status hasn't changed, return 00280 if (status.level == level && status.text == text && !status.kill) 00281 { 00282 return; 00283 } 00284 00285 status.name = name; 00286 status.text = text; 00287 status.level = level; 00288 status.kill = false; 00289 00290 // Update the top level status here so that it can be used immediately 00291 updateTopLevelStatus(); 00292 00293 changed(); 00294 } 00295 00296 void StatusProperty::deleteStatus(const std::string& name) 00297 { 00298 boost::mutex::scoped_lock lock(status_mutex_); 00299 00300 if (!enabled_) 00301 { 00302 return; 00303 } 00304 00305 M_StringToStatus::iterator it = statuses_.find(name); 00306 if (it != statuses_.end()) 00307 { 00308 Status& status = it->second; 00309 status.kill = true; 00310 } 00311 00312 // Update the top level status here so that it can be used immediately 00313 updateTopLevelStatus(); 00314 00315 changed(); 00316 } 00317 00318 void StatusProperty::doWriteToGrid() 00319 { 00320 boost::mutex::scoped_lock lock(status_mutex_); 00321 00322 if ( !top_widget_item_ ) 00323 { 00324 std::string top_name = name_ + "TopStatus"; 00325 00326 top_widget_item_ = new PropertyWidgetItem( this, "", false, false, true ); 00327 top_widget_item_->addToParent(); 00328 } 00329 00330 bool expanded = top_widget_item_->isExpanded(); 00331 00332 top_status_ = status_levels::Ok; 00333 00334 std::vector<std::string> to_erase; 00335 M_StringToStatus::iterator it = statuses_.begin(); 00336 M_StringToStatus::iterator end = statuses_.end(); 00337 for( ; it != end; ++it ) 00338 { 00339 Status& status = it->second; 00340 00341 if( status.kill ) 00342 { 00343 to_erase.push_back(it->first); 00344 continue; 00345 } 00346 00347 if( !status.widget_item ) 00348 { 00349 status.widget_item = new PropertyWidgetItem( this, status.name, false, false, false ); 00350 status.widget_item->addToParent( top_widget_item_ ); 00351 } 00352 00353 if( status.level > top_status_ ) 00354 { 00355 top_status_ = status.level; 00356 } 00357 00358 if( enabled_ ) 00359 { 00360 switch( status.level ) 00361 { 00362 case status_levels::Ok: 00363 setPropertyToOK( grid_, status.widget_item ); 00364 break; 00365 case status_levels::Warn: 00366 setPropertyToColors( grid_, status.widget_item, WARN_COLOR, Qt::white ); 00367 break; 00368 case status_levels::Error: 00369 setPropertyToColors( grid_, status.widget_item, ERROR_COLOR, Qt::white ); 00370 break; 00371 } 00372 } 00373 else 00374 { 00375 setPropertyToDisabled( grid_, status.widget_item ); 00376 } 00377 00378 status.widget_item->setRightText( status.text ); 00379 setPropertyHelpText( grid_, status.widget_item, status.text ); 00380 } 00381 00382 std::vector<std::string>::iterator kill_it = to_erase.begin(); 00383 std::vector<std::string>::iterator kill_end = to_erase.end(); 00384 for( ; kill_it != kill_end; ++kill_it ) 00385 { 00386 Status& status = statuses_[*kill_it]; 00387 delete status.widget_item; 00388 statuses_.erase( *kill_it ); 00389 } 00390 00391 top_widget_item_->setExpanded( expanded ); 00392 00393 std::string label; 00394 if( enabled_ ) 00395 { 00396 switch( top_status_ ) 00397 { 00398 case status_levels::Ok: 00399 setPropertyToColors( grid_, top_widget_item_, Qt::black, Qt::white ); 00400 label = name_ + ": OK"; 00401 break; 00402 case status_levels::Warn: 00403 setPropertyToColors( grid_, top_widget_item_, WARN_COLOR, Qt::white ); 00404 label = name_ + ": Warning"; 00405 break; 00406 case status_levels::Error: 00407 setPropertyToColors( grid_, top_widget_item_, ERROR_COLOR, Qt::white ); 00408 label = name_ + ": Error"; 00409 break; 00410 } 00411 } 00412 else 00413 { 00414 setPropertyToDisabled( grid_, top_widget_item_ ); 00415 label = name_ + ": Disabled"; 00416 } 00417 00418 top_widget_item_->setLeftText( label ); 00419 top_widget_item_->sortChildren( 0, Qt::AscendingOrder ); 00420 } 00421 00422 StatusLevel StatusProperty::getTopLevelStatus() 00423 { 00424 return top_status_; 00425 } 00426 00427 void BoolProperty::doWriteToGrid() 00428 { 00429 if ( !widget_item_ ) 00430 { 00431 widget_item_ = new PropertyWidgetItem( this, name_, hasSetter(), true ); 00432 widget_item_->addToParent(); 00433 } 00434 bool ign = getPropertyTreeWidget()->setIgnoreChanges( true ); 00435 00436 widget_item_->setData( 1, Qt::CheckStateRole, get() ? Qt::Checked : Qt::Unchecked ); 00437 setPropertyHelpText(grid_, widget_item_, help_text_); 00438 00439 getPropertyTreeWidget()->setIgnoreChanges( ign ); 00440 } 00441 00442 void BoolProperty::readFromGrid() 00443 { 00444 QVariant check_state = widget_item_->data( 1, Qt::CheckStateRole ); 00445 set( check_state == Qt::Checked ); 00446 } 00447 00448 void BoolProperty::saveToConfig( Config* config ) 00449 { 00450 config->set( prefix_ + name_, (int)get() ); 00451 } 00452 00453 void BoolProperty::loadFromConfig( Config* config ) 00454 { 00455 int val; 00456 if( !config->get( prefix_ + name_, &val, get() )) 00457 { 00458 V_string::iterator it = legacy_names_.begin(); 00459 V_string::iterator end = legacy_names_.end(); 00460 for (; it != end; ++it) 00461 { 00462 if (config->get( prefix_ + *it, &val, get() )) 00463 { 00464 break; 00465 } 00466 } 00467 } 00468 00469 set( (bool) val ); 00470 } 00471 00472 void IntProperty::setMin( int min ) 00473 { 00474 if( widget_item_ ) 00475 { 00476 widget_item_->min_ = min; 00477 } 00478 min_ = min; 00479 } 00480 00481 void IntProperty::setMax( int max ) 00482 { 00483 if (widget_item_) 00484 { 00485 widget_item_->max_ = max; 00486 } 00487 max_ = max; 00488 } 00489 00490 void IntProperty::doWriteToGrid() 00491 { 00492 if ( !widget_item_ ) 00493 { 00494 widget_item_ = new PropertyWidgetItem( this, name_, hasSetter() ); 00495 widget_item_->addToParent(); 00496 widget_item_->max_ = max_; 00497 widget_item_->min_ = min_; 00498 } 00499 00500 widget_item_->setUserData( get() ); 00501 00502 setPropertyHelpText(grid_, widget_item_, help_text_); 00503 } 00504 00505 void IntProperty::readFromGrid() 00506 { 00507 set( widget_item_->userData().toInt() ); 00508 } 00509 00510 void IntProperty::saveToConfig( Config* config ) 00511 { 00512 config->set( prefix_ + name_, (int)get() ); 00513 } 00514 00515 void IntProperty::loadFromConfig( Config* config ) 00516 { 00517 int val; 00518 if (!config->get( prefix_ + name_, &val, get() )) 00519 { 00520 V_string::iterator it = legacy_names_.begin(); 00521 V_string::iterator end = legacy_names_.end(); 00522 for (; it != end; ++it) 00523 { 00524 if (config->get( prefix_ + *it, &val, get() )) 00525 { 00526 break; 00527 } 00528 } 00529 } 00530 00531 set( val ); 00532 } 00533 00534 void FloatProperty::setMin( float min ) 00535 { 00536 if (widget_item_) 00537 { 00538 widget_item_->min_ = min; 00539 } 00540 min_ = min; 00541 } 00542 00543 void FloatProperty::setMax( float max ) 00544 { 00545 if (widget_item_) 00546 { 00547 widget_item_->max_ = max; 00548 } 00549 max_ = max; 00550 } 00551 00552 void FloatProperty::doWriteToGrid() 00553 { 00554 if( !widget_item_ ) 00555 { 00556 widget_item_ = new PropertyWidgetItem( this, name_, hasSetter() ); 00557 widget_item_->addToParent(); 00558 widget_item_->max_ = max_; 00559 widget_item_->min_ = min_; 00560 } 00561 00562 widget_item_->setUserData( QVariant( get() )); 00563 00564 setPropertyHelpText(grid_, widget_item_, help_text_); 00565 } 00566 00567 void FloatProperty::readFromGrid() 00568 { 00569 set( widget_item_->userData().toFloat() ); 00570 } 00571 00572 void FloatProperty::saveToConfig( Config* config ) 00573 { 00574 config->set( prefix_ + name_, (float)get() ); 00575 } 00576 00577 void FloatProperty::loadFromConfig( Config* config ) 00578 { 00579 float val; 00580 if (!config->get( prefix_ + name_, &val, get() )) 00581 { 00582 V_string::iterator it = legacy_names_.begin(); 00583 V_string::iterator end = legacy_names_.end(); 00584 for (; it != end; ++it) 00585 { 00586 if (config->get( prefix_ + *it, &val, get() )) 00587 { 00588 break; 00589 } 00590 } 00591 } 00592 00593 set( val ); 00594 } 00595 00596 void StringProperty::doWriteToGrid() 00597 { 00598 if( !widget_item_ ) 00599 { 00600 widget_item_ = new PropertyWidgetItem( this, name_, hasSetter() ); 00601 widget_item_->addToParent(); 00602 } 00603 00604 widget_item_->setUserData( QString::fromStdString( get() )); 00605 00606 setPropertyHelpText( grid_, widget_item_, help_text_ ); 00607 } 00608 00609 void StringProperty::readFromGrid() 00610 { 00611 set( widget_item_->userData().toString().toStdString() ); 00612 } 00613 00614 void StringProperty::saveToConfig( Config* config ) 00615 { 00616 config->set( prefix_ + name_, get() ); 00617 } 00618 00619 void StringProperty::loadFromConfig( Config* config ) 00620 { 00621 std::string val; 00622 if (!config->get( prefix_ + name_, &val, get() )) 00623 { 00624 V_string::iterator it = legacy_names_.begin(); 00625 V_string::iterator end = legacy_names_.end(); 00626 for (; it != end; ++it) 00627 { 00628 if (config->get( prefix_ + *it, &val, get() )) 00629 { 00630 break; 00631 } 00632 } 00633 } 00634 00635 set( val ); 00636 } 00637 00638 void ROSTopicStringProperty::doWriteToGrid() 00639 { 00640 if ( !widget_item_ ) 00641 { 00642 widget_item_ = new PropertyWidgetItem( this, name_, hasSetter() ); 00643 widget_item_->addToParent(); 00644 } 00645 ros::master::TopicInfo topic; 00646 topic.name = get(); 00647 topic.datatype = message_type_; 00648 00649 widget_item_->setUserData( QVariant::fromValue( topic )); 00650 00651 setPropertyHelpText(grid_, widget_item_, help_text_); 00652 } 00653 00654 void ROSTopicStringProperty::readFromGrid() 00655 { 00656 ros::master::TopicInfo topic = widget_item_->userData().value<ros::master::TopicInfo>(); 00657 set( topic.name ); 00658 } 00659 00660 void ColorProperty::doWriteToGrid() 00661 { 00662 if( !widget_item_ ) 00663 { 00664 widget_item_ = new ColorItem( this ); 00665 widget_item_->addToParent(); 00666 } 00667 00668 Color c = get(); 00669 widget_item_->setUserData( QVariant::fromValue( QColor( c.r_ * 255, c.g_ * 255, c.b_ * 255 ))); 00670 00671 setPropertyHelpText( grid_, widget_item_, help_text_ ); 00672 } 00673 00674 void ColorProperty::readFromGrid() 00675 { 00676 QColor col = widget_item_->userData().value<QColor>(); 00677 set( Color( col.red() / 255.0f, col.green() / 255.0f, col.blue() / 255.0f ) ); 00678 } 00679 00680 void ColorProperty::saveToConfig( Config* config ) 00681 { 00682 Color c = get(); 00683 00684 config->set( prefix_ + name_ + "R", c.r_ ); 00685 config->set( prefix_ + name_ + "G", c.g_ ); 00686 config->set( prefix_ + name_ + "B", c.b_ ); 00687 } 00688 00689 void ColorProperty::loadFromConfig( Config* config ) 00690 { 00691 Color c = get(); 00692 float r, g, b; 00693 bool found = true; 00694 found &= config->get( prefix_ + name_ + "R", &r, c.r_ ); 00695 found &= config->get( prefix_ + name_ + "G", &g, c.g_ ); 00696 found &= config->get( prefix_ + name_ + "B", &b, c.b_ ); 00697 00698 if (!found) 00699 { 00700 V_string::iterator it = legacy_names_.begin(); 00701 V_string::iterator end = legacy_names_.end(); 00702 for (; it != end; ++it) 00703 { 00704 found = true; 00705 found &= config->get( prefix_ + *it + "R", &r, c.r_ ); 00706 found &= config->get( prefix_ + *it + "G", &g, c.g_ ); 00707 found &= config->get( prefix_ + *it + "B", &b, c.b_ ); 00708 00709 if (found) 00710 { 00711 break; 00712 } 00713 } 00714 } 00715 00716 set( Color( r, g, b ) ); 00717 } 00718 00719 void EnumProperty::addOption( const std::string& name, int value ) 00720 { 00721 boost::mutex::scoped_lock lock(mutex_); 00722 choices_.push_back( Choice( name, value )); 00723 changed(); 00724 } 00725 00726 void EnumProperty::clear () 00727 { 00728 boost::mutex::scoped_lock lock(mutex_); 00729 choices_.clear(); 00730 changed(); 00731 } 00732 00733 void EnumProperty::doWriteToGrid() 00734 { 00735 boost::mutex::scoped_lock lock(mutex_); 00736 00737 if (isSelected()) 00738 { 00739 changed(); 00740 return; 00741 } 00742 00743 if( !widget_item_ ) 00744 { 00745 widget_item_ = new EnumItem( this ); 00746 widget_item_->addToParent(); 00747 } 00748 EnumItem* enum_item = dynamic_cast<EnumItem*>( widget_item_ ); 00749 ROS_ASSERT( enum_item ); 00750 enum_item->setChoices( choices_ ); 00751 enum_item->setChoiceValue( get() ); 00752 00753 setPropertyHelpText( grid_, widget_item_, help_text_ ); 00754 } 00755 00756 void EnumProperty::readFromGrid() 00757 { 00758 EnumItem* enum_item = dynamic_cast<EnumItem*>( widget_item_ ); 00759 ROS_ASSERT( enum_item ); 00760 set( enum_item->getChoiceValue() ); 00761 } 00762 00763 void EnumProperty::saveToConfig( Config* config ) 00764 { 00765 config->set( prefix_ + name_, (int)get() ); 00766 } 00767 00768 void EnumProperty::loadFromConfig( Config* config ) 00769 { 00770 int val = INT_MAX; 00771 if( !config->get( prefix_ + name_, &val, get() )) 00772 { 00773 V_string::iterator it = legacy_names_.begin(); 00774 V_string::iterator end = legacy_names_.end(); 00775 for (; it != end; ++it) 00776 { 00777 if (config->get( prefix_ + *it, &val, get() )) 00778 { 00779 break; 00780 } 00781 } 00782 } 00783 00784 set( val ); 00785 } 00786 00787 void EditEnumProperty::addOption( const std::string& name ) 00788 { 00789 boost::mutex::scoped_lock lock(mutex_); 00790 choices_.push_back( name ); 00791 changed(); 00792 } 00793 00794 void EditEnumProperty::setOptionCallback(const EditEnumOptionCallback& cb) 00795 { 00796 option_cb_ = cb; 00797 if( EditEnumItem* ee_item = dynamic_cast<EditEnumItem*>( widget_item_ )) 00798 { 00799 ee_item->setOptionCallback( cb ); 00800 } 00801 00802 changed(); 00803 } 00804 00805 void EditEnumProperty::clear () 00806 { 00807 boost::mutex::scoped_lock lock(mutex_); 00808 choices_.clear(); 00809 changed(); 00810 } 00811 00812 void EditEnumProperty::doWriteToGrid() 00813 { 00814 boost::mutex::scoped_lock lock(mutex_); 00815 00816 if (isSelected()) 00817 { 00818 changed(); 00819 return; 00820 } 00821 00822 if ( !widget_item_ ) 00823 { 00824 widget_item_ = new EditEnumItem( this ); 00825 widget_item_->addToParent(); 00826 } 00827 EditEnumItem* ee_item = dynamic_cast<EditEnumItem*>( widget_item_ ); 00828 ROS_ASSERT( ee_item ); 00829 ee_item->setOptionCallback( option_cb_ ); 00830 ee_item->setChoices( choices_ ); 00831 ee_item->setChoice( get() ); 00832 00833 setPropertyHelpText(grid_, widget_item_, help_text_); 00834 } 00835 00836 void EditEnumProperty::readFromGrid() 00837 { 00838 EditEnumItem* ee_item = dynamic_cast<EditEnumItem*>( widget_item_ ); 00839 ROS_ASSERT( ee_item ); 00840 set( ee_item->getChoice() ); 00841 } 00842 00843 void EditEnumProperty::saveToConfig( Config* config ) 00844 { 00845 config->set( prefix_ + name_, get() ); 00846 } 00847 00848 void EditEnumProperty::loadFromConfig( Config* config ) 00849 { 00850 std::string val; 00851 if (!config->get( prefix_ + name_, &val, get() )) 00852 { 00853 V_string::iterator it = legacy_names_.begin(); 00854 V_string::iterator end = legacy_names_.end(); 00855 for (; it != end; ++it) 00856 { 00857 if (config->get( prefix_ + *it, &val, get() )) 00858 { 00859 break; 00860 } 00861 } 00862 } 00863 00864 set( val ); 00865 } 00866 00867 void TFFrameProperty::optionCallback( V_string& options_out ) 00868 { 00869 typedef std::vector<std::string> V_string; 00870 FrameManager::instance()->getTFClient()->getFrameStrings( options_out ); 00871 std::sort(options_out.begin(), options_out.end()); 00872 00873 options_out.insert( options_out.begin(), FIXED_FRAME_STRING ); 00874 } 00875 00876 void TFFrameProperty::doWriteToGrid() 00877 { 00878 EditEnumProperty::doWriteToGrid(); 00879 00880 EditEnumItem* ee_item = dynamic_cast<EditEnumItem*>( widget_item_ ); 00881 ROS_ASSERT( ee_item ); 00882 ee_item->setOptionCallback( boost::bind( &TFFrameProperty::optionCallback, this, _1 )); 00883 } 00884 00885 CategoryProperty::~CategoryProperty() 00886 { 00887 if( widget_item_ ) 00888 { 00889 // QTreeWidgetItem's destructor deletes all its children, but 00890 // PropertyManager also deletes each property (child or not) 00891 // individually. Therefore before we destroy a category property 00892 // we need to disconnect (take) all of the widget item's children, 00893 // which will then be deleted by their respective Property 00894 // objects. 00895 widget_item_->takeChildren(); 00896 } 00897 } 00898 00899 void CategoryProperty::reset() 00900 { 00901 if( widget_item_ ) 00902 { 00903 // QTreeWidgetItem's destructor deletes all its children, but 00904 // PropertyManager also deletes each property (child or not) 00905 // individually. Therefore before we destroy a category property 00906 // we need to disconnect (take) all of the widget item's children, 00907 // which will then be deleted by their respective Property 00908 // objects. 00909 widget_item_->takeChildren(); 00910 } 00911 Property<bool>::reset(); // manually chain reset() like a virtual destructor 00912 } 00913 00914 void CategoryProperty::setLabel( const std::string& label ) 00915 { 00916 label_ = label; 00917 00918 if( widget_item_ ) 00919 { 00920 widget_item_->setLeftText( label_ ); 00921 } 00922 } 00923 00924 void CategoryProperty::expand() 00925 { 00926 if (widget_item_) 00927 { 00928 widget_item_->setExpanded( true ); 00929 } 00930 } 00931 00932 void CategoryProperty::collapse() 00933 { 00934 if (widget_item_) 00935 { 00936 widget_item_->setExpanded( false ); 00937 } 00938 } 00939 00940 void CategoryProperty::doWriteToGrid() 00941 { 00942 if( !widget_item_ ) 00943 { 00944 widget_item_ = new PropertyWidgetItem( this, label_, checkbox_, checkbox_, !checkbox_ ); 00945 widget_item_->addToParent(); 00946 widget_item_->setExpanded( true ); 00947 } 00948 // setData() call must be before any setProperty...() calls, because 00949 // those can trigger the itemChanged() signal which ultimately 00950 // causes readFromGrid() to be called, which calls the Setter and 00951 // clobbers our new data. 00952 if( checkbox_ ) 00953 { 00954 widget_item_->setData( 1, Qt::CheckStateRole, get() ? Qt::Checked : Qt::Unchecked ); 00955 } 00956 setPropertyToColors( grid_, widget_item_, Qt::white, QColor( 4, 89, 127 )); 00957 setPropertyHelpText( grid_, widget_item_, help_text_ ); 00958 } 00959 00960 void CategoryProperty::readFromGrid() 00961 { 00962 if (checkbox_) 00963 { 00964 QVariant check_state = widget_item_->data( 1, Qt::CheckStateRole ); 00965 ROS_ASSERT( !check_state.isNull() ); 00966 set( check_state != Qt::Unchecked ); 00967 } 00968 } 00969 00970 void CategoryProperty::saveToConfig( Config* config ) 00971 { 00972 if (checkbox_) 00973 { 00974 config->set( prefix_ + name_, get() ); 00975 } 00976 } 00977 00978 void CategoryProperty::loadFromConfig( Config* config ) 00979 { 00980 if (checkbox_) 00981 { 00982 int val; 00983 if (!config->get( prefix_ + name_, &val, get() )) 00984 { 00985 V_string::iterator it = legacy_names_.begin(); 00986 V_string::iterator end = legacy_names_.end(); 00987 for (; it != end; ++it) 00988 { 00989 if (config->get( prefix_ + *it, &val, get() )) 00990 { 00991 break; 00992 } 00993 } 00994 } 00995 00996 set( (bool) val ); 00997 } 00998 } 00999 01000 void CategoryProperty::setToOK() 01001 { 01002 if (grid_) 01003 { 01004 setPropertyToOK(grid_, widget_item_, 0); 01005 if( widget_item_ ) 01006 { 01007 QFont font = widget_item_->font( 0 ); 01008 font.setBold( true ); 01009 widget_item_->setFont( 0, font ); 01010 } 01011 } 01012 } 01013 01014 void Vector3Property::doWriteToGrid() 01015 { 01016 if( !widget_item_ ) 01017 { 01018 widget_item_ = new CompoundWidgetItem( this, name_, hasSetter() ); 01019 widget_item_->addToParent(); 01020 x_ = new PropertyWidgetItem( this, "X", hasSetter() ); 01021 x_->addToParent( widget_item_ ); 01022 y_ = new PropertyWidgetItem( this, "Y", hasSetter() ); 01023 y_->addToParent( widget_item_ ); 01024 z_ = new PropertyWidgetItem( this, "Z", hasSetter() ); 01025 z_->addToParent( widget_item_ ); 01026 01027 widget_item_->setExpanded( false ); 01028 } 01029 01030 Ogre::Vector3 v = get(); 01031 x_->setUserData( QVariant( v.x )); 01032 y_->setUserData( QVariant( v.y )); 01033 z_->setUserData( QVariant( v.z )); 01034 01035 CompoundWidgetItem* cwi = dynamic_cast<CompoundWidgetItem*>( widget_item_ ); 01036 ROS_ASSERT( cwi ); 01037 cwi->updateText(); 01038 01039 setPropertyHelpText( grid_, widget_item_, help_text_ ); 01040 setPropertyHelpText( grid_, x_, help_text_ ); 01041 setPropertyHelpText( grid_, y_, help_text_ ); 01042 setPropertyHelpText( grid_, z_, help_text_ ); 01043 } 01044 01045 void Vector3Property::readFromGrid() 01046 { 01047 float x = x_->userData().toFloat(); 01048 float y = y_->userData().toFloat(); 01049 float z = z_->userData().toFloat(); 01050 01051 CompoundWidgetItem* cwi = dynamic_cast<CompoundWidgetItem*>( widget_item_ ); 01052 ROS_ASSERT( cwi ); 01053 cwi->updateText(); 01054 01055 set( Ogre::Vector3( x, y, z )); 01056 } 01057 01058 void Vector3Property::saveToConfig( Config* config ) 01059 { 01060 Ogre::Vector3 v = get(); 01061 01062 config->set( prefix_ + name_ + "X", v.x ); 01063 config->set( prefix_ + name_ + "Y", v.y ); 01064 config->set( prefix_ + name_ + "Z", v.z ); 01065 } 01066 01067 void Vector3Property::loadFromConfig( Config* config ) 01068 { 01069 Ogre::Vector3 v = get(); 01070 float x, y, z; 01071 bool found = true; 01072 found &= config->get( prefix_ + name_ + "X", &x, v.x ); 01073 found &= config->get( prefix_ + name_ + "Y", &y, v.y ); 01074 found &= config->get( prefix_ + name_ + "Z", &z, v.z ); 01075 01076 if (!found) 01077 { 01078 V_string::iterator it = legacy_names_.begin(); 01079 V_string::iterator end = legacy_names_.end(); 01080 for (; it != end; ++it) 01081 { 01082 found = true; 01083 found &= config->get( prefix_ + *it + "X", &x, v.x ); 01084 found &= config->get( prefix_ + *it + "Y", &y, v.y ); 01085 found &= config->get( prefix_ + *it + "Z", &z, v.z ); 01086 01087 if (found) 01088 { 01089 break; 01090 } 01091 } 01092 } 01093 01094 set( Ogre::Vector3( x, y, z ) ); 01095 } 01096 01097 void Vector3Property::reset() 01098 { 01099 Property<Ogre::Vector3>::reset(); 01100 01101 // Widget item children of widget_item_ are deleted by their parent, 01102 // in PropertyBase::reset(), so don't need to be deleted here. 01103 x_ = 0; 01104 y_ = 0; 01105 z_ = 0; 01106 } 01107 01108 void QuaternionProperty::doWriteToGrid() 01109 { 01110 if( !widget_item_ ) 01111 { 01112 widget_item_ = new CompoundWidgetItem( this, name_, hasSetter() ); 01113 widget_item_->addToParent(); 01114 x_ = new PropertyWidgetItem( this, "X", hasSetter() ); 01115 x_->addToParent( widget_item_ ); 01116 y_ = new PropertyWidgetItem( this, "Y", hasSetter() ); 01117 y_->addToParent( widget_item_ ); 01118 z_ = new PropertyWidgetItem( this, "Z", hasSetter() ); 01119 z_->addToParent( widget_item_ ); 01120 w_ = new PropertyWidgetItem( this, "W", hasSetter() ); 01121 w_->addToParent( widget_item_ ); 01122 01123 widget_item_->setExpanded( false ); 01124 } 01125 01126 Ogre::Quaternion q = get(); 01127 x_->setUserData( QVariant( q.x )); 01128 y_->setUserData( QVariant( q.y )); 01129 z_->setUserData( QVariant( q.z )); 01130 w_->setUserData( QVariant( q.w )); 01131 01132 CompoundWidgetItem* cwi = dynamic_cast<CompoundWidgetItem*>( widget_item_ ); 01133 ROS_ASSERT( cwi ); 01134 cwi->updateText(); 01135 01136 setPropertyHelpText( grid_, widget_item_, help_text_ ); 01137 setPropertyHelpText( grid_, x_, help_text_ ); 01138 setPropertyHelpText( grid_, y_, help_text_ ); 01139 setPropertyHelpText( grid_, z_, help_text_ ); 01140 setPropertyHelpText( grid_, w_, help_text_ ); 01141 } 01142 01143 void QuaternionProperty::readFromGrid() 01144 { 01145 float x = x_->userData().toFloat(); 01146 float y = y_->userData().toFloat(); 01147 float z = z_->userData().toFloat(); 01148 float w = w_->userData().toFloat(); 01149 01150 CompoundWidgetItem* cwi = dynamic_cast<CompoundWidgetItem*>( widget_item_ ); 01151 ROS_ASSERT( cwi ); 01152 cwi->updateText(); 01153 01154 set( Ogre::Quaternion( w, x, y, z )); 01155 } 01156 01157 void QuaternionProperty::saveToConfig( Config* config ) 01158 { 01159 Ogre::Quaternion q = get(); 01160 01161 config->set( prefix_ + name_ + "X", q.x ); 01162 config->set( prefix_ + name_ + "Y", q.y ); 01163 config->set( prefix_ + name_ + "Z", q.z ); 01164 config->set( prefix_ + name_ + "W", q.w ); 01165 } 01166 01167 void QuaternionProperty::loadFromConfig( Config* config ) 01168 { 01169 Ogre::Quaternion q = get(); 01170 float x, y, z, w; 01171 bool found = true; 01172 found &= config->get( prefix_ + name_ + "X", &x, q.x ); 01173 found &= config->get( prefix_ + name_ + "Y", &y, q.y ); 01174 found &= config->get( prefix_ + name_ + "Z", &z, q.z ); 01175 found &= config->get( prefix_ + name_ + "W", &w, q.w ); 01176 01177 if (!found) 01178 { 01179 V_string::iterator it = legacy_names_.begin(); 01180 V_string::iterator end = legacy_names_.end(); 01181 for (; it != end; ++it) 01182 { 01183 found = true; 01184 found &= config->get( prefix_ + *it + "X", &x, q.x ); 01185 found &= config->get( prefix_ + *it + "Y", &y, q.y ); 01186 found &= config->get( prefix_ + *it + "Z", &z, q.z ); 01187 found &= config->get( prefix_ + *it + "W", &w, q.w ); 01188 01189 if (found) 01190 { 01191 break; 01192 } 01193 } 01194 } 01195 01196 set( Ogre::Quaternion( w, x, y, z ) ); 01197 } 01198 01199 void QuaternionProperty::reset() 01200 { 01201 Property<Ogre::Quaternion>::reset(); 01202 01203 // Widget item children of widget_item_ are deleted by their parent, 01204 // in PropertyBase::reset(), so don't need to be deleted here. 01205 x_ = 0; 01206 y_ = 0; 01207 z_ = 0; 01208 w_ = 0; 01209 } 01210 01211 }