parameter_tree_widget.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 import rospy
00004 import actionlib
00005 import std_msgs.msg
00006 import vigir_footstep_planning_msgs.msg
00007 
00008 from python_qt_binding.QtCore import Qt, QPoint, QModelIndex, Slot
00009 from python_qt_binding.QtGui import QWidget, QTreeWidget, QTreeWidgetItem, QMenu, QAction, QAbstractItemView, QColor, QIcon
00010 
00011 from vigir_generic_params.msg import ParameterSetMsg
00012 from vigir_footstep_planning_msgs.parameter import *
00013 from vigir_footstep_planning_lib.logging import *
00014 
00015 
00016 class QParameterTreeWidget(QTreeWidget):
00017 
00018     logger = Logger()
00019 
00020     def __init__(self, parent=None, logger=Logger()):
00021         QTreeWidget.__init__(self, parent)
00022         self.set_logger(logger)
00023 
00024         # init tree
00025         self.setHeaderLabels(["Name", "Type", "Value"])
00026         self.sortItems(0, Qt.AscendingOrder)
00027         #self.setSelectionMode(QAbstractItemView.NoSelection)
00028         self.setContextMenuPolicy(Qt.CustomContextMenu)
00029         self.itemActivated.connect(self.edit_item)
00030         self.currentItemChanged.connect(self.current_item_changed)
00031 
00032         # context menu
00033         self.customContextMenuRequested.connect(self.context_menu_request)
00034         self._action_item_expand = QAction(QIcon.fromTheme('zoom-in'), 'Expand Selected', self)
00035         self._action_item_expand.triggered.connect(self._handle_action_item_expand)
00036         self._action_item_collapse = QAction(QIcon.fromTheme('zoom-out'), 'Collapse Selected', self)
00037         self._action_item_collapse.triggered.connect(self._handle_action_item_collapse)
00038         self._action_item_add = QAction(QIcon.fromTheme('list-add'), 'Add', self)
00039         self._action_item_add.setEnabled(False)  # TODO
00040         self._action_item_remove = QAction(QIcon.fromTheme('list-remove'), 'Remove', self)
00041         self._action_item_remove.setEnabled(False)  # TODO
00042 
00043     def set_logger(self, logger):
00044         self.logger = logger
00045 
00046     @Slot(QPoint)
00047     def context_menu_request(self, point):
00048         if self.selectionModel().hasSelection():
00049             menu = QMenu(self)
00050             menu.addAction(self._action_item_add)
00051             menu.addAction(self._action_item_remove)
00052             menu.addSeparator()
00053             menu.addAction(self._action_item_expand)
00054             menu.addAction(self._action_item_collapse)
00055             menu.exec_(self.mapToGlobal(point))
00056 
00057     @Slot()
00058     def _handle_action_item_collapse(self):
00059         self._handle_action_set_expanded(False)
00060 
00061     @Slot()
00062     def _handle_action_item_expand(self):
00063         self._handle_action_set_expanded(True)
00064 
00065     @Slot(bool)
00066     def _handle_action_set_expanded(self, expanded):
00067         def recursive_set_expanded(index):
00068             if (index != QModelIndex()) and (index.column() == 0):
00069                 self.setExpanded(index, expanded)
00070                 #for i in range(index.model().childCount()):
00071                 #    index.model().child(i).setExpanded(expanded)
00072                 #for i in range(index.model().rowCount()):
00073                 #    recursive_set_expanded(index.child(i, 0))
00074 
00075         for index in self.selectedIndexes():
00076             recursive_set_expanded(index)
00077 
00078     @Slot(QTreeWidgetItem, int)
00079     def edit_item(self, item, column):
00080         if (column == 0) or (item.is_leaf() and (column == 2)):
00081             item.setFlags(item.flags() | Qt.ItemIsEditable)
00082             self.editItem(item, column)
00083             item.setFlags(item.flags() & ~Qt.ItemIsEditable)
00084 
00085     @Slot(QTreeWidgetItem, QTreeWidgetItem)
00086     def current_item_changed(self, prev, current):
00087         if prev is not None:
00088             if not prev.update_value():
00089                 self.logger.log_error("Couldn't update value for '" + prev.get_name() + "' in '" + prev.get_namespace() + "'. Check input syntax!")
00090         if current is not None:
00091             if not current.update_value():
00092                 self.logger.log_error("Couldn't update value for '" + current.get_name() + "' in '" + current.get_namespace() + "'. Check input syntax!")
00093 
00094     # set parameter set from msg
00095     def set_parameter_set(self, param_set_msg):
00096         self.clear()
00097 
00098         self.root = QParameterTreeWidgetItem(self, self.logger, name=param_set_msg.name.data)
00099         self.root.setExpanded(True)
00100 
00101         for p in param_set_msg.params:
00102             self.root.add_param(Parameter(msg=p))
00103 
00104     # get parameter set as msg
00105     def get_parameter_set(self):
00106         params = self.root.get_params()
00107 
00108         # remove top-level namespace
00109         top_len = len(self.root.get_name()) + 2
00110         for p in params:
00111             p.set_name(p.get_name()[top_len:])
00112 
00113         # generate msg
00114         param_set_msg = ParameterSet()
00115         param_set_msg.name.data = self.root.get_name()
00116         for p in params:
00117             param_set_msg.parameters.append(p.to_msg())
00118 
00119         return param_set_msg
00120 
00121 
00122 class QParameterTreeWidgetItem(QTreeWidgetItem):
00123 
00124     logger = Logger()
00125     param = None
00126     namespace = str()
00127 
00128     def __init__(self, parent=None, logger=Logger(), param = None, name=str(), namespace=str()):
00129         QTreeWidgetItem.__init__(self, parent)
00130         self.set_logger(logger)
00131 
00132         if param is not None:
00133             self.set_param(param)
00134         elif len(name) > 0:
00135             self.set_name(name)
00136         self.namespace = namespace
00137 
00138     def set_logger(self, logger):
00139         self.logger = logger
00140 
00141     def is_leaf(self):
00142         return self.param is not None
00143 
00144     def update_value(self):
00145         result = True
00146         if self.is_leaf():
00147             self.param.set_name(self.text(0))
00148             result = self.param.set_value(self.text(2))
00149             #self.setText(2, str(self.param.get_value()))
00150             if result:
00151                 for i in range(self.columnCount()):
00152                     self.setBackgroundColor(i, Qt.white)
00153             else:
00154                 for i in range(self.columnCount()):
00155                     self.setBackgroundColor(i, QColor(255, 165, 0))
00156         return result
00157 
00158     def set_name(self, name):
00159         self.setText(0, name)
00160         if self.is_leaf():
00161             self.param.set_name(name)
00162 
00163     def get_name(self):
00164         return self.text(0)
00165 
00166     def get_namespace(self):
00167         return self.namespace
00168 
00169     def set_param(self, param, namespace = str()):
00170         self.param = param
00171         self.namespace = namespace
00172         if self.is_leaf():
00173             self.setText(0, self.param.get_name())
00174             self.setText(1, str(self.param.get_type_as_text()))
00175             self.setText(2, str(self.param.get_value()))
00176 
00177     def get_param(self):
00178         return self.param
00179 
00180     def get_params(self):
00181         params = []
00182         if self.is_leaf():
00183             # sync with recent changes from UI
00184             if not self.update_value():
00185                 self.logger.log_warn("Value for '" + self.get_name() + "' in '" + self.get_namespace() + "' has invalid changes. Check input syntax!")
00186 
00187             p = self.get_param()
00188             p.set_name(self.get_namespace() + '/' + p.get_name())
00189             params.append(p)
00190         else:
00191             for i in range(self.childCount()):
00192                 params.extend(self.child(i).get_params())
00193         return params
00194 
00195     # adds param recursively (based on namespace)
00196     def add_param(self, param):
00197         # finds branch matching the name
00198         def find_branch(name):
00199             for i in range(self.childCount()):
00200                 if self.child(i).text(0) == name:
00201                     return self.child(i)
00202             return None
00203 
00204         # adds param to existing branch or create new branch recursively
00205         def add_param_to_branch(param, branch_name):
00206             branch = find_branch(branch_name)
00207             if branch is None:
00208                 branch = QParameterTreeWidgetItem(self, self.logger, name = branch_name, namespace = self.get_namespace() + '/' + self.get_name())
00209             branch.add_param(param)
00210 
00211         if self.is_leaf():
00212             print "Error: Can't add parameter '" + param.get_name() + "' to the leaf '" + self.get_name() + "'!"
00213             return
00214 
00215         # check if param has namespace
00216         param.set_name(param.get_name().strip('/'))
00217         i = param.get_name().find('/')
00218 
00219         # add as leaf
00220         if i == -1:
00221             QParameterTreeWidgetItem(self, self.logger, param, namespace = self.get_namespace() + '/' + self.get_name())
00222         # add into branch
00223         else:
00224             branch_name = param.get_name()[:i]
00225             param.set_name(param.get_name()[i+1:])
00226             add_param_to_branch(param, branch_name)


vigir_footstep_planning_lib
Author(s): Alexander Stumpf
autogenerated on Sat Jul 15 2017 02:47:56