00001 from copy import copy
00002
00003 from actions.ActionSequence import ActionSequence
00004 from actions.DefaultAction import DefaultAction
00005 from DoubleSpinBoxDelegate import DoubleSpinBoxDelegate
00006 from IntegerSpinBoxDelegate import IntegerSpinBoxDelegate
00007
00008 import python_qt_binding.QtBindingHelper
00009 from QtCore import QAbstractTableModel, QByteArray, QMimeData, QModelIndex, Qt, Signal
00010
00011 class PosesDataModel(QAbstractTableModel):
00012
00013 actions_changed = Signal()
00014 duration_modified = Signal()
00015
00016 _mime_type = 'application/x-slider-action'
00017
00018 def __init__(self, editable=False):
00019 super(PosesDataModel, self).__init__()
00020 self._action_sequence = ActionSequence()
00021 self._editable = editable
00022 self._joint_columns = {}
00023
00024 action = DefaultAction()
00025 self._add_joint(1, action, 'head_pan_joint', 'Hd Turn')
00026 self._add_joint(2, action, 'head_tilt_joint', 'Hd Nod')
00027 self._add_joint(3, action, 'torso_lift_joint', 'Torso', 2)
00028 self._add_joint(4, action, 'l_shoulder_pan_joint', 'Lp1')
00029 self._add_joint(5, action, 'l_shoulder_lift_joint', 'Ll2')
00030 self._add_joint(6, action, 'l_upper_arm_roll_joint', 'Lu3')
00031 self._add_joint(7, action, 'l_elbow_flex_joint', 'Le4')
00032 self._add_joint(8, action, 'l_forearm_roll_joint', 'Lf5')
00033 self._add_joint(9, action, 'l_wrist_flex_joint', 'Lw6')
00034 self._add_joint(10, action, 'l_wrist_roll_joint', 'Lr7')
00035 self._add_joint(11, action, 'l_gripper', 'LGrip', 3)
00036 self._add_joint(12, action, 'r_shoulder_pan_joint', 'Rp1')
00037 self._add_joint(13, action, 'r_shoulder_lift_joint', 'Rl2')
00038 self._add_joint(14, action, 'r_upper_arm_roll_joint', 'Ru3')
00039 self._add_joint(15, action, 'r_elbow_flex_joint', 'Re4')
00040 self._add_joint(16, action, 'r_forearm_roll_joint', 'Rf5')
00041 self._add_joint(17, action, 'r_wrist_flex_joint', 'Rw6')
00042 self._add_joint(18, action, 'r_wrist_roll_joint', 'Rr7')
00043 self._add_joint(19, action, 'r_gripper', 'RGrip', 3)
00044
00045
00046 self._delegates = []
00047
00048 def _add_joint(self, column, action, label, header, precision=None):
00049 info = copy(action.get_joint_info(label))
00050 info['header'] = header
00051 info['decimals'] = precision
00052 self._joint_columns[column] = info
00053
00054 def set_editable(self, editable):
00055 if self._editable != editable:
00056 self._editable = editable
00057 self.reset()
00058
00059 def add_action(self, action, index = None):
00060 self._add_action(action, index)
00061 self.actions_changed.emit()
00062 self.duration_modified.emit()
00063
00064 def _add_action(self, action, index = None):
00065 model_index = QModelIndex()
00066 if index is None or index == len(self._action_sequence.actions()):
00067 rows = len(self._action_sequence.actions())
00068 index = None
00069 else:
00070 assert(index >=0 and index < len(self._action_sequence.actions()))
00071 rows = index
00072
00073
00074 self.beginInsertRows(model_index, rows, rows)
00075 self._action_sequence.add_action(action, index)
00076 self.endInsertRows()
00077
00078 def move_action(self, source_index, destination_index):
00079 assert(source_index >=0 and source_index < len(self._action_sequence.actions()))
00080 assert(destination_index >=0 and destination_index <= len(self._action_sequence.actions()))
00081 action = self._action_sequence.actions()[source_index]
00082 self._remove_action(source_index)
00083 if destination_index > source_index:
00084 destination_index -= 1
00085 self._add_action(action, destination_index)
00086 self.actions_changed.emit()
00087
00088 def remove_action(self, index):
00089 self._remove_action(index)
00090 self.actions_changed.emit()
00091 self.duration_modified.emit()
00092
00093 def _remove_action(self, index):
00094 assert(index >=0 and index < len(self._action_sequence.actions()))
00095
00096 model_index = QModelIndex()
00097 self.beginRemoveRows(model_index, index, index)
00098 self._action_sequence.remove_action(index)
00099 self.endRemoveRows()
00100
00101 def remove_all_actions(self):
00102 index = QModelIndex()
00103 rows = len(self._action_sequence.actions())
00104 self.beginRemoveRows(index, 0, rows - 1)
00105 self._action_sequence.remove_all_actions()
00106 self.endRemoveRows()
00107 self.actions_changed.emit()
00108 self.duration_modified.emit()
00109
00110 def action_sequence(self):
00111 return self._action_sequence
00112
00113 def rowCount(self, parent=None):
00114 return len(self._action_sequence.actions())
00115
00116 def columnCount(self, parent=None):
00117 if self._editable:
00118 return 1 + len(self._joint_columns)
00119 else:
00120 return 1 + 1
00121
00122 def data(self, index, role=None):
00123 if role is None:
00124 role = Qt.DisplayRole
00125 if index.row() >= 0 and index.row() < len(self._action_sequence.actions()):
00126 if role == Qt.DisplayRole:
00127 if index.column() == 0:
00128 return '%.1f' % self._action_sequence.actions()[index.row()].get_duration()
00129 elif not self._editable and index.column() == 1:
00130 return self._action_sequence.actions()[index.row()].to_string()
00131 elif self._editable and index.column() in self._joint_columns.keys():
00132 joint_info = self._joint_columns[index.column()]
00133 try:
00134 value = self._action_sequence.actions()[index.row()].get_value(joint_info['label'])
00135 if joint_info['decimals'] is not None:
00136 value = round(value, joint_info['decimals'])
00137 else:
00138 value = int(round(value))
00139 return value
00140 except:
00141 return ''
00142 if role == Qt.EditRole:
00143 if index.column() == 0:
00144 return self._action_sequence.actions()[index.row()].get_duration()
00145 elif self._editable and index.column() in self._joint_columns.keys():
00146 joint_info = self._joint_columns[index.column()]
00147 try:
00148 value = self._action_sequence.actions()[index.row()].get_value(joint_info['label'])
00149 if joint_info['decimals'] is not None:
00150 value = round(value, joint_info['decimals'])
00151 else:
00152 value = int(round(value))
00153 return value
00154 except:
00155 return ''
00156 return None
00157
00158 def setData(self, index, value, role):
00159 if role == Qt.EditRole:
00160 if index.column() == 0:
00161 value = float(value)
00162 self._action_sequence.actions()[index.row()].set_duration(value)
00163 self.duration_modified.emit()
00164 return True
00165 elif self._editable:
00166 value = float(value)
00167 try:
00168 self._action_sequence.actions()[index.row()].update_value(self._joint_columns[index.column()]['label'], value)
00169 except:
00170 return False
00171 return True
00172 return super(PosesDataModel, self).setData(index, value, role)
00173
00174 def flags(self, index):
00175 f = super(PosesDataModel, self).flags(index)
00176 if index.isValid():
00177 if index.column() == 0:
00178 f |= Qt.ItemIsEditable
00179 elif self._editable and index.column() in self._joint_columns.keys():
00180 try:
00181
00182 self._action_sequence.actions()[index.row()].get_value(self._joint_columns[index.column()]['label'])
00183 f |= Qt.ItemIsEditable
00184 except:
00185 pass
00186 f |= Qt.ItemIsDragEnabled
00187 f |= Qt.ItemIsDropEnabled
00188 return f
00189
00190 def headerData(self, section, orientation, role=None):
00191 if role is None:
00192 role = Qt.DisplayRole
00193 if role == Qt.DisplayRole:
00194 if orientation == Qt.Horizontal:
00195 if section == 0:
00196 return 'Time'
00197 elif not self._editable and section == 1:
00198 return 'Joints'
00199 elif self._editable and section in self._joint_columns.keys():
00200 return self._joint_columns[section]['header']
00201 elif orientation == Qt.Vertical:
00202 return 'Pose %d' % (section + 1)
00203 return None
00204
00205 def supportedDropActions(self):
00206 return Qt.CopyAction | Qt.MoveAction
00207
00208 def mimeTypes(self):
00209 return [self._mime_type]
00210
00211 def mimeData(self, indexes):
00212
00213 row = None
00214 for index in indexes:
00215 if index.isValid():
00216 if row is None:
00217 row = index.row()
00218 if row != index.row():
00219 row = None
00220 break
00221
00222 mimeData = QMimeData()
00223 if row is not None:
00224 mimeData.setData(self._mime_type, QByteArray.number(row))
00225 return mimeData;
00226
00227 def dropMimeData(self, data, action, row, column, parent):
00228
00229 if action == Qt.MoveAction:
00230 before_row = None
00231 if row != -1:
00232 before_row = row
00233 elif parent.isValid():
00234 before_row = parent.row()
00235 else:
00236 before_row = self.rowCount()
00237 if data.hasFormat(self._mime_type):
00238 byte_array = data.data(self._mime_type)
00239 source_row, is_int = byte_array.toInt()
00240 if is_int and before_row != source_row + 1:
00241
00242 self.move_action(source_row, before_row)
00243 return True
00244 return super(PosesDataModel, self).dropMimeData(data, action, row, column, parent)
00245
00246 def add_delegates(self, table_view):
00247 for i in self._joint_columns.keys():
00248 joint_info = self._joint_columns[i]
00249 if joint_info['decimals'] is not None:
00250 delegate = DoubleSpinBoxDelegate()
00251 delegate.setDecimals(joint_info['decimals'])
00252 else:
00253 delegate = IntegerSpinBoxDelegate()
00254 delegate.setMinimum(joint_info['min'])
00255 delegate.setMaximum(joint_info['max'])
00256 delegate.setSingleStep(joint_info['single_step'])
00257 table_view.setItemDelegateForColumn(i, delegate)
00258 self._delegates.append(delegate)