00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <QStyledItemDelegate>
00031 #include <QLineEdit>
00032 #include <QPainter>
00033 #include <QMouseEvent>
00034
00035 #include "rviz/properties/property_tree_widget.h"
00036 #include "rviz/properties/property_widget_item.h"
00037 #include "rviz/properties/property.h"
00038 #include "rviz/properties/topic_info_variant.h"
00039 #include "rviz/properties/ros_topic_editor.h"
00040 #include "rviz/properties/color_editor.h"
00041
00042 namespace rviz
00043 {
00044
00046
00048 class PropertyTreeDelegate: public QStyledItemDelegate
00049 {
00050 private:
00051 PropertyTreeWidget* tree_widget_;
00052
00053 public:
00054 PropertyTreeDelegate( PropertyTreeWidget* tree_widget )
00055 : QStyledItemDelegate( tree_widget )
00056 , tree_widget_( tree_widget )
00057 {
00058 }
00059
00060 virtual void paint( QPainter * painter,
00061 const QStyleOptionViewItem & option,
00062 const QModelIndex & index ) const
00063 {
00064 PropertyWidgetItem* item = tree_widget_->getItem( index );
00065 if( index.column() == 0 || !item->paint( painter, option ))
00066 {
00067 QStyledItemDelegate::paint( painter, option, index );
00068 }
00069 }
00070
00071 virtual QWidget *createEditor( QWidget *parent,
00072 const QStyleOptionViewItem & option,
00073 const QModelIndex &index ) const
00074 {
00075 if( index.column() != 1 )
00076 {
00077 return 0;
00078 }
00079 PropertyWidgetItem* item = tree_widget_->getItem( index );
00080 if( !item )
00081 {
00082 return 0;
00083 }
00084 QWidget* editor = item->createEditor( parent, option );
00085 if( editor != 0 )
00086 {
00087 return editor;
00088 }
00089
00090
00091
00092
00093
00094
00095 QVariant originalValue = index.model()->data(index, Qt::UserRole);
00096
00097 if( originalValue.canConvert<ros::master::TopicInfo>() )
00098 {
00099 RosTopicEditor* editor = new RosTopicEditor( parent );
00100 editor->setFrame( false );
00101 return editor;
00102 }
00103 else
00104 {
00105 QValidator *validator;
00106 QLineEdit *lineEdit = new QLineEdit(parent);
00107
00108 switch (originalValue.type()) {
00109 case QVariant::Int:
00110 {
00111 validator = new QIntValidator( (int) item->min_, (int) item->max_, lineEdit );
00112 break;
00113 }
00114 case QMetaType::Float:
00115 {
00116 validator = new QDoubleValidator( item->min_, item->max_, 1000, lineEdit );
00117 break;
00118 }
00119 default:
00120 validator = NULL;
00121 }
00122 lineEdit->setValidator( validator );
00123 lineEdit->setFrame( false );
00124 return lineEdit;
00125 }
00126 }
00127
00128
00129
00130 void setEditorData(QWidget *editor, const QModelIndex &index) const
00131 {
00132 if( index.column() == 1 )
00133 {
00134 PropertyWidgetItem* item = tree_widget_->getItem( index );
00135 if( !item || item->setEditorData( editor ))
00136 {
00137 return;
00138 }
00139 }
00140
00141 QVariant value = index.model()->data(index, Qt::UserRole);
00142
00143 if( RosTopicEditor* topic_editor = qobject_cast<RosTopicEditor*>( editor ))
00144 {
00145 topic_editor->setTopic( value.value<ros::master::TopicInfo>() );
00146 }
00147 else if( QLineEdit *lineEdit = qobject_cast<QLineEdit *>( editor ))
00148 {
00149 lineEdit->setText(value.toString());
00150 }
00151 }
00152
00153
00154 void setModelData( QWidget *editor, QAbstractItemModel *model,
00155 const QModelIndex &index ) const
00156 {
00157 PropertyWidgetItem* item = tree_widget_->getItem( index );
00158 if( !item || item->setModelData( editor ))
00159 {
00160 return;
00161 }
00162
00163 QVariant originalValue = index.model()->data( index, Qt::UserRole );
00164 QVariant value;
00165 QString display_string;
00166
00167 if( RosTopicEditor* topic_editor = qobject_cast<RosTopicEditor*>( editor ))
00168 {
00169 if( !topic_editor->isModified() )
00170 {
00171 return;
00172 }
00173 ros::master::TopicInfo topic = topic_editor->getTopic();
00174 value = QVariant::fromValue( topic );
00175 display_string = QString::fromStdString( topic.name );
00176 }
00177 else if( QLineEdit* lineEdit = qobject_cast<QLineEdit *>( editor ))
00178 {
00179 if( !lineEdit->isModified() )
00180 {
00181 return;
00182 }
00183
00184 QString text = lineEdit->text();
00185 const QValidator *validator = lineEdit->validator();
00186 if( validator ) {
00187 int pos;
00188 if( validator->validate( text, pos ) != QValidator::Acceptable )
00189 {
00190 return;
00191 }
00192 }
00193
00194 switch (originalValue.type()) {
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 default:
00246 value = text;
00247 value.convert( originalValue.type() );
00248 }
00249 display_string = value.toString();
00250 }
00251
00252
00253 model->setData(index, value, Qt::UserRole);
00254
00255
00256 bool ign = tree_widget_->setIgnoreChanges( true );
00257 model->setData(index, display_string, Qt::DisplayRole);
00258 tree_widget_->setIgnoreChanges( ign );
00259 }
00260 };
00261
00263
00265 class SplitterHandle: public QWidget
00266 {
00267 public:
00268 SplitterHandle( PropertyTreeWidget* parent = 0 )
00269 : QWidget( parent )
00270 , parent_( parent )
00271 , first_column_size_ratio_( 0.5f )
00272 {
00273 setCursor( Qt::SplitHCursor );
00274 int w = 7;
00275 setGeometry( parent_->width() / 2 - w/2, 0, w, parent_->height() );
00276 }
00277
00278 void onParentResized()
00279 {
00280 int new_column_width = int( first_column_size_ratio_ * parent_->width() );
00281 parent_->setColumnWidth( 0, new_column_width );
00282 setGeometry( new_column_width - width() / 2, 0, width(), parent_->height() );
00283 }
00284
00285 void setRatio( float ratio )
00286 {
00287 first_column_size_ratio_ = ratio;
00288 onParentResized();
00289 }
00290
00291 float getRatio()
00292 {
00293 return first_column_size_ratio_;
00294 }
00295
00296 protected:
00297 void mousePressEvent( QMouseEvent* event )
00298 {
00299 if( event->button() == Qt::LeftButton )
00300 {
00301 x_press_offset_ = event->x();
00302 }
00303 }
00304
00305 void mouseMoveEvent( QMouseEvent* event )
00306 {
00307 int padding = 55;
00308
00309 if( event->buttons() & Qt::LeftButton )
00310 {
00311 QPoint pos_rel_parent = parent_->mapFromGlobal( event->globalPos() );
00312
00313 int new_x = pos_rel_parent.x() - x_press_offset_;
00314
00315 if( new_x > parent_->width() - width() - padding )
00316 {
00317 new_x = parent_->width() - width() - padding;
00318 }
00319
00320 if( new_x < padding )
00321 {
00322 new_x = padding;
00323 }
00324
00325 if( new_x != x() )
00326 {
00327 move( new_x, 0 );
00328
00329 int new_column_width = new_x + width() / 2;
00330 parent_->setColumnWidth( 0, new_column_width );
00331
00332 first_column_size_ratio_ = new_column_width / (float) parent_->width();
00333 }
00334 }
00335 }
00336
00337 private:
00338 PropertyTreeWidget* parent_;
00339 int x_press_offset_;
00340
00343 float first_column_size_ratio_;
00344 };
00345
00347
00349 PropertyTreeWidget::PropertyTreeWidget( QWidget* parent )
00350 : QTreeWidget( parent )
00351 , ignore_changes_( false )
00352 , splitter_handle_( new SplitterHandle( this ))
00353 {
00354 setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
00355 setHeaderHidden( true );
00356 setUniformRowHeights( true );
00357 setItemDelegate( new PropertyTreeDelegate( this ));
00358 setEditTriggers( QAbstractItemView::AllEditTriggers );
00359 setColumnCount( 2 );
00360 setSelectionMode( QAbstractItemView::ExtendedSelection );
00361
00362 connect( this, SIGNAL( itemChanged( QTreeWidgetItem *, int )),
00363 this, SLOT( onItemChanged( QTreeWidgetItem *, int )));
00364 }
00365
00366 void PropertyTreeWidget::onItemChanged( QTreeWidgetItem* item, int column_number )
00367 {
00368 if( !ignore_changes_ )
00369 {
00370 PropertyWidgetItem* pwi = dynamic_cast<PropertyWidgetItem*>( item );
00371 if( pwi )
00372 {
00373 pwi->getProperty()->readFromGrid();
00374 }
00375 }
00376 }
00377
00378 PropertyWidgetItem* PropertyTreeWidget::getItem( const QModelIndex & index )
00379 {
00380 return dynamic_cast<PropertyWidgetItem*>( itemFromIndex( index ));
00381 }
00382
00383 void PropertyTreeWidget::resizeEvent( QResizeEvent* event )
00384 {
00385 splitter_handle_->onParentResized();
00386 }
00387
00388 void PropertyTreeWidget::dropEvent( QDropEvent* event )
00389 {
00390 QTreeWidget::dropEvent( event );
00391 Q_EMIT orderChanged();
00392 }
00393
00396 std::string PropertyTreeWidget::saveEditableState()
00397 {
00398 std::ostringstream output;
00399
00400 bool first = true;
00401 saveExpandedState( output, invisibleRootItem(), first );
00402
00403 output << ";splitterratio=" << splitter_handle_->getRatio();
00404
00405 return output.str();
00406
00407
00408
00409
00410
00411
00412
00413 }
00414
00415 void PropertyTreeWidget::saveExpandedState( std::ostream& output,
00416 QTreeWidgetItem* parent_item,
00417 bool& first )
00418 {
00419 for( int child_index = 0; child_index < parent_item->childCount(); child_index++ )
00420 {
00421 QTreeWidgetItem* item = parent_item->child( child_index );
00422 if( item->isExpanded() && item->childCount() > 0 )
00423 {
00424 if( first )
00425 {
00426 output << "expanded=";
00427 first = false;
00428 }
00429 else
00430 {
00431 output << ',';
00432 }
00433 PropertyWidgetItem* pwi = dynamic_cast<PropertyWidgetItem*>( item );
00434 if( pwi )
00435 {
00436 output << pwi->getProperty()->getPrefix() << pwi->getProperty()->getName();
00437 saveExpandedState( output, item, first );
00438 }
00439 }
00440 }
00441 }
00442
00444 void PropertyTreeWidget::restoreEditableState( const std::string& state )
00445 {
00446 std::istringstream iss( state );
00447 std::string assignment;
00448 while( std::getline( iss, assignment, ';' ))
00449 {
00450 size_t equal_pos = assignment.find( '=' );
00451 if( equal_pos != std::string::npos )
00452 {
00453 std::istringstream value_stream( assignment.substr( equal_pos + 1 ));
00454 if( 0 == assignment.compare( 0, equal_pos, "splitterratio" ))
00455 {
00456 float ratio;
00457 value_stream >> ratio;
00458 splitter_handle_->setRatio( ratio );
00459 }
00460 else if( 0 == assignment.compare( 0, equal_pos, "expanded" ))
00461 {
00462 std::set<std::string> expanded_entries;
00463 std::string entry;
00464 while( std::getline( value_stream, entry, ',' ))
00465 {
00466 expanded_entries.insert( entry );
00467 }
00468
00469 restoreExpandedState( expanded_entries, invisibleRootItem() );
00470 }
00471 }
00472 }
00473 }
00474
00477 void PropertyTreeWidget::restoreExpandedState( const std::set<std::string>& expanded_entries,
00478 QTreeWidgetItem* parent_item )
00479 {
00480
00481
00482
00483 for( int child_index = 0; child_index < parent_item->childCount(); child_index++ )
00484 {
00485 QTreeWidgetItem* item = parent_item->child( child_index );
00486 PropertyWidgetItem* pwi = dynamic_cast<PropertyWidgetItem*>( item );
00487 if( pwi )
00488 {
00489 std::string entry_name = pwi->getProperty()->getPrefix() + pwi->getProperty()->getName();
00490 if( expanded_entries.find( entry_name ) != expanded_entries.end() )
00491 {
00492 item->setExpanded( true );
00493 if( item->childCount() > 0 )
00494 {
00495 restoreExpandedState( expanded_entries, item );
00496 }
00497 }
00498 else
00499 {
00500 item->setExpanded( false );
00501 }
00502 }
00503 }
00504 }
00505
00506 }