00001
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
00025 self.setHeaderLabels(["Name", "Type", "Value"])
00026 self.sortItems(0, Qt.AscendingOrder)
00027
00028 self.setContextMenuPolicy(Qt.CustomContextMenu)
00029 self.itemActivated.connect(self.edit_item)
00030 self.currentItemChanged.connect(self.current_item_changed)
00031
00032
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)
00040 self._action_item_remove = QAction(QIcon.fromTheme('list-remove'), 'Remove', self)
00041 self._action_item_remove.setEnabled(False)
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
00071
00072
00073
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
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
00105 def get_parameter_set(self):
00106 params = self.root.get_params()
00107
00108
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
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
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
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
00196 def add_param(self, param):
00197
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
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
00216 param.set_name(param.get_name().strip('/'))
00217 i = param.get_name().find('/')
00218
00219
00220 if i == -1:
00221 QParameterTreeWidgetItem(self, self.logger, param, namespace = self.get_namespace() + '/' + self.get_name())
00222
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)