コード例 #1
0
    def _handle_run_program(self, req):
        print 'Running program...'

        input = StringIO(req.code)
        storage = SimpleFormat(input)
        count = storage.deserialize_data()
        assert(count > 0)
        self._sequences = []
        for index in range(count):
            sequence = ActionSequence()
            sequence.deserialize(storage)
            print 'Loaded sequence %d with %d poses' % (index + 1, len(sequence.actions()))
            sequence.executing_action_signal.connect(self._progress)
            sequence.execute_sequence_finished_signal.connect(self._finished)
            self._sequences.append(sequence)

        self._event = Event()
        # wait until default pose has finished
        print 'Execute default pose'
        self._default_pose.execute_finished_signal.connect(self._event.set)
        self._default_pose.execute()
        self._event.wait()
        self._default_pose.execute_finished_signal.disconnect(self._event.set)

        # enable interactive mode
        print 'Enable interactive mode'
        self._event.clear()
        self._default_pose.execute_finished_signal.connect(self._finished)
        self._ps3_subscriber.buttons_changed.connect(self._check_ps3_buttons)
        self._event.wait()
        self._default_pose.execute_finished_signal.disconnect(self._finished)
        self._ps3_subscriber.buttons_changed.disconnect(self._check_ps3_buttons)

        self._stop_current_sequence()

        for sequence in self._sequences:
            sequence.executing_action_signal.disconnect(self._progress)
            sequence.execute_sequence_finished_signal.disconnect(self._finished)
        self._sequences = []

        print 'Running program finished'
        return CallProgramResponse(0, "Slider Program Successful")
コード例 #2
0
class PosesDataModel(QAbstractTableModel):

    actions_changed = Signal()
    duration_modified = Signal()

    _mime_type = 'application/x-slider-action'

    def __init__(self, editable=False):
        super(PosesDataModel, self).__init__()
        self._action_sequence = ActionSequence()
        self._editable = editable
        self._joint_columns = {}

        action = DefaultAction()
        self._add_joint(1, action, 'head_pan_joint', 'Hd Turn')
        self._add_joint(2, action, 'head_tilt_joint', 'Hd Nod')
        self._add_joint(3, action, 'torso_lift_joint', 'Torso', 2)
        self._add_joint(4, action, 'l_shoulder_pan_joint', 'Lp1')
        self._add_joint(5, action, 'l_shoulder_lift_joint', 'Ll2')
        self._add_joint(6, action, 'l_upper_arm_roll_joint', 'Lu3')
        self._add_joint(7, action, 'l_elbow_flex_joint', 'Le4')
        self._add_joint(8, action, 'l_forearm_roll_joint', 'Lf5')
        self._add_joint(9, action, 'l_wrist_flex_joint', 'Lw6')
        self._add_joint(10, action, 'l_wrist_roll_joint', 'Lr7')
        self._add_joint(11, action, 'l_gripper', 'LGrip', 3)
        self._add_joint(12, action, 'r_shoulder_pan_joint', 'Rp1')
        self._add_joint(13, action, 'r_shoulder_lift_joint', 'Rl2')
        self._add_joint(14, action, 'r_upper_arm_roll_joint', 'Ru3')
        self._add_joint(15, action, 'r_elbow_flex_joint', 'Re4')
        self._add_joint(16, action, 'r_forearm_roll_joint', 'Rf5')
        self._add_joint(17, action, 'r_wrist_flex_joint', 'Rw6')
        self._add_joint(18, action, 'r_wrist_roll_joint', 'Rr7')
        self._add_joint(19, action, 'r_gripper', 'RGrip', 3)

        # keep reference to delegates to prevent being garbaged
        self._delegates = []

    def _add_joint(self, column, action, label, header, precision=None):
        info = copy(action.get_joint_info(label))
        info['header'] = header
        info['decimals'] = precision
        self._joint_columns[column] = info

    def set_editable(self, editable):
        if self._editable != editable:
            self._editable = editable
            self.reset()

    def add_action(self, action, index = None):
        self._add_action(action, index)
        self.actions_changed.emit()
        self.duration_modified.emit()

    def _add_action(self, action, index = None):
        model_index = QModelIndex()
        if index is None or index == len(self._action_sequence.actions()):
            rows = len(self._action_sequence.actions())
            index = None
        else:
            assert(index >=0 and index < len(self._action_sequence.actions()))
            rows = index

        # insert at model-index of parent-item
        self.beginInsertRows(model_index, rows, rows)
        self._action_sequence.add_action(action, index)
        self.endInsertRows()

    def move_action(self, source_index, destination_index):
        assert(source_index >=0 and source_index < len(self._action_sequence.actions()))
        assert(destination_index >=0 and destination_index <= len(self._action_sequence.actions()))
        action = self._action_sequence.actions()[source_index]
        self._remove_action(source_index)
        if destination_index > source_index:
            destination_index -= 1
        self._add_action(action, destination_index)
        self.actions_changed.emit()

    def remove_action(self, index):
        self._remove_action(index)
        self.actions_changed.emit()
        self.duration_modified.emit()

    def _remove_action(self, index):
        assert(index >=0 and index < len(self._action_sequence.actions()))
        # delete at model-index of parent-item
        model_index = QModelIndex()
        self.beginRemoveRows(model_index, index, index)
        self._action_sequence.remove_action(index)
        self.endRemoveRows()

    def remove_all_actions(self):
        index = QModelIndex()
        rows = len(self._action_sequence.actions())
        self.beginRemoveRows(index, 0, rows - 1)
        self._action_sequence.remove_all_actions()
        self.endRemoveRows()
        self.actions_changed.emit()
        self.duration_modified.emit()

    def action_sequence(self):
        return self._action_sequence

    def rowCount(self, parent=None):
        return len(self._action_sequence.actions())

    def columnCount(self, parent=None):
        if self._editable:
            return 1 + len(self._joint_columns)
        else:
            return 1 + 1

    def data(self, index, role=None):
        if role is None:
            role = Qt.DisplayRole
        if index.row() >= 0 and index.row() < len(self._action_sequence.actions()):
            if role == Qt.DisplayRole:
                if index.column() == 0:
                    return '%.1f' % self._action_sequence.actions()[index.row()].get_duration()
                elif not self._editable and index.column() == 1:
                    return self._action_sequence.actions()[index.row()].to_string()
                elif self._editable and index.column() in self._joint_columns.keys():
                    joint_info = self._joint_columns[index.column()]
                    try:
                        value = self._action_sequence.actions()[index.row()].get_value(joint_info['label'])
                        if joint_info['decimals'] is not None:
                            value = round(value, joint_info['decimals'])
                        else:
                            value = int(round(value))
                        return value
                    except:
                        return ''
            if role == Qt.EditRole:
                if index.column() == 0:
                    return self._action_sequence.actions()[index.row()].get_duration()
                elif self._editable and index.column() in self._joint_columns.keys():
                    joint_info = self._joint_columns[index.column()]
                    try:
                        value = self._action_sequence.actions()[index.row()].get_value(joint_info['label'])
                        if joint_info['decimals'] is not None:
                            value = round(value, joint_info['decimals'])
                        else:
                            value = int(round(value))
                        return value
                    except:
                        return ''
        return None

    def setData(self, index, value, role):
        if role == Qt.EditRole:
            if index.column() == 0:
                value = float(value)
                self._action_sequence.actions()[index.row()].set_duration(value)
                self.duration_modified.emit()
                return True
            elif self._editable:
                value = float(value)
                try:
                    self._action_sequence.actions()[index.row()].update_value(self._joint_columns[index.column()]['label'], value)
                except:
                    return False
                return True
        return super(PosesDataModel, self).setData(index, value, role)

    def flags(self, index):
        f = super(PosesDataModel, self).flags(index)
        if index.isValid():
            if index.column() == 0:
                f |= Qt.ItemIsEditable
            elif self._editable and index.column() in self._joint_columns.keys():
                try:
                    # only cell which have real values can be edited
                    self._action_sequence.actions()[index.row()].get_value(self._joint_columns[index.column()]['label'])
                    f |= Qt.ItemIsEditable
                except:
                    pass
            f |= Qt.ItemIsDragEnabled
        f |= Qt.ItemIsDropEnabled
        return f

    def headerData(self, section, orientation, role=None):
        if role is None:
            role = Qt.DisplayRole
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                if section == 0:
                    return 'Time'
                elif not self._editable and section == 1:
                    return 'Joints'
                elif self._editable and section in self._joint_columns.keys():
                    return self._joint_columns[section]['header']
            elif orientation == Qt.Vertical:
                return 'Pose %d' % (section + 1)
        return None

    def supportedDropActions(self):
        return Qt.CopyAction | Qt.MoveAction

    def mimeTypes(self):
        return [self._mime_type]

    def mimeData(self, indexes):
        #print 'mimeData()'
        row = None
        for index in indexes:
            if index.isValid():
                if row is None:
                    row = index.row()
                if row != index.row():
                    row = None
                    break

        mimeData = QMimeData()
        if row is not None:
            mimeData.setData(self._mime_type, QByteArray.number(row))
        return mimeData;

    def dropMimeData(self, data, action, row, column, parent):
        #print 'dropMimeData()'
        if action == Qt.MoveAction:
            before_row = None
            if row != -1:
                before_row = row
            elif parent.isValid():
                before_row = parent.row()
            else:
                before_row = self.rowCount()
            if data.hasFormat(self._mime_type):
                byte_array = data.data(self._mime_type)
                source_row, is_int = byte_array.toInt()
                if is_int and before_row != source_row + 1:
                    #print 'dropMimeData()', source_row, '->', before_row
                    self.move_action(source_row, before_row)
                    return True
        return super(PosesDataModel, self).dropMimeData(data, action, row, column, parent)

    def add_delegates(self, table_view):
        for i in self._joint_columns.keys():
            joint_info = self._joint_columns[i]
            if joint_info['decimals'] is not None:
                delegate = DoubleSpinBoxDelegate()
                delegate.setDecimals(joint_info['decimals'])
            else:
                delegate = IntegerSpinBoxDelegate()
            delegate.setMinimum(joint_info['min'])
            delegate.setMaximum(joint_info['max'])
            delegate.setSingleStep(joint_info['single_step'])
            table_view.setItemDelegateForColumn(i, delegate)
            self._delegates.append(delegate)
コード例 #3
0
class PosesDataModel(QAbstractTableModel):

    actions_changed = Signal()
    duration_modified = Signal()

    _mime_type = 'application/x-slider-action'

    def __init__(self, editable=False):
        super(PosesDataModel, self).__init__()
        self._action_sequence = ActionSequence()
        self._editable = editable
        self._joint_columns = {}

        action = DefaultAction()
        self._add_joint(2, action, 'head_pan_joint', 'Hd Turn')
        self._add_joint(3, action, 'head_tilt_joint', 'Hd Nod')
        self._add_joint(4, action, 'torso_lift_joint', 'Torso', 2)
        self._add_joint(5, action, 'l_shoulder_pan_joint', 'LSpan')
        self._add_joint(6, action, 'l_shoulder_lift_joint', 'LSlift')
        self._add_joint(7, action, 'l_upper_arm_roll_joint', 'LUArmRoll')
        self._add_joint(8, action, 'l_elbow_flex_joint', 'LElbFlex')
        self._add_joint(9, action, 'l_forearm_roll_joint', 'LFArmRoll')
        self._add_joint(10, action, 'l_wrist_flex_joint', 'LWrstFlex')
        self._add_joint(11, action, 'l_wrist_roll_joint', 'LWrstRoll')
        self._add_joint(12, action, 'l_gripper', 'LGrip', 3)
        self._add_joint(13, action, 'r_shoulder_pan_joint', 'RSpan')
        self._add_joint(14, action, 'r_shoulder_lift_joint', 'RSlift')
        self._add_joint(15, action, 'r_upper_arm_roll_joint', 'RUArmRoll')
        self._add_joint(16, action, 'r_elbow_flex_joint', 'RElbFlex')
        self._add_joint(17, action, 'r_forearm_roll_joint', 'RFArmRoll')
        self._add_joint(18, action, 'r_wrist_flex_joint', 'RWrstFlex')
        self._add_joint(19, action, 'r_wrist_roll_joint', 'RWrstRoll')
        self._add_joint(20, action, 'r_gripper', 'RGrip', 3)

        # keep reference to delegates to prevent being garbaged
        self._delegates = []

    def _add_joint(self, column, action, label, header, precision=None):
        info = copy(action.get_joint_info(label))
        info['header'] = header
        info['decimals'] = precision
        self._joint_columns[column] = info

    def set_editable(self, editable):
        if self._editable != editable:
            self._editable = editable
            self.reset()

    def editable(self):
        return self._editable

    def add_action(self, action, index = None):
        self._add_action(action, index)
        self.actions_changed.emit()
        self.duration_modified.emit()

    def _add_action(self, action, index = None):
        model_index = QModelIndex()
        if index is None or index == len(self._action_sequence.actions()):
            rows = len(self._action_sequence.actions())
            index = None
        else:
            assert(index >=0 and index < len(self._action_sequence.actions()))
            rows = index

        # insert at model-index of parent-item
        self.beginInsertRows(model_index, rows, rows)
        self._action_sequence.add_action(action, index)
        self.endInsertRows()

    def move_action(self, source_index, destination_index):
        assert(source_index >=0 and source_index < len(self._action_sequence.actions()))
        assert(destination_index >=0 and destination_index <= len(self._action_sequence.actions()))
        action = self._action_sequence.actions()[source_index]
        self._remove_action(source_index)
        if destination_index > source_index:
            destination_index -= 1
        self._add_action(action, destination_index)
        self.actions_changed.emit()

    def remove_action(self, index):
        self._remove_action(index)
        self.actions_changed.emit()
        self.duration_modified.emit()

    def _remove_action(self, index):
        assert(index >=0 and index < len(self._action_sequence.actions()))
        # delete at model-index of parent-item
        model_index = QModelIndex()
        self.beginRemoveRows(model_index, index, index)
        self._action_sequence.remove_action(index)
        self.endRemoveRows()

    def remove_all_actions(self):
        index = QModelIndex()
        rows = len(self._action_sequence.actions())
        self.beginRemoveRows(index, 0, rows - 1)
        self._action_sequence.remove_all_actions()
        self.endRemoveRows()
        self.actions_changed.emit()
        self.duration_modified.emit()

    def action_sequence(self):
        return self._action_sequence

    def rowCount(self, parent=None):
        return len(self._action_sequence.actions())

    def columnCount(self, parent=None):
        if self._editable:
            # Time, speech, and all the joints:
            return 2 + len(self._joint_columns)
        else:
            # Time, speech, and the single column for all the joints:
            return 2 + 1

    def data(self, index, role=None):
        if role is None:
            role = Qt.DisplayRole
        if index.row() >= 0 and index.row() < len(self._action_sequence.actions()):
            if role == Qt.DisplayRole:
                if index.column() == 0: # duration column
                    return '%.1f' % self._action_sequence.actions()[index.row()].get_duration()
                
                elif index.column() == 1: # speech column:
                    actionSets = self._action_sequence.actions()
                    actionIndex = index.row()
                    actionSetAtIndex = actionSets[actionIndex]
                    try:
                        waitTillDone = actionSetAtIndex.get_value('waitForSpeechDone')
                        utterance = actionSetAtIndex.get_value('text')
                    except KeyError:
                        return (None,None)
                    if not self._editable:
                        res = ('WaitForDone,' if waitTillDone else "NoWaiting,") + "'" + utterance + "'"
                    else:
                        res = (waitTillDone, utterance)
                    return res
                
                elif not self._editable and index.column() == 1:
                    return self._action_sequence.actions()[index.row()].to_string()
                
                elif not self._editable and index.column() in self._joint_columns.keys():
                    # For displaying, put all joint values into column 2:
                    valString = ""
                    # Joints run from 2 to number of joints. The offset
                    # is to make room for time and speech columns: 
                    for jointIndex in range(2, 2 + len(self._joint_columns)):
                        joint_info        = self._joint_columns[jointIndex]
                        jointLabel        = joint_info['label']
                        jointAbbreviation = joint_info['header']
                        try:
                            value = self._action_sequence.actions()[index.row()].get_value(jointLabel)
                        except KeyError:
                            # For rows that have speech instead of a pose,
                            # the above value seek fails:
                            continue
                        if joint_info['decimals'] is not None:
                            value = round(value, joint_info['decimals'])
                        else:
                            value = int(round(value))
                        valString += "%s:%d;" % (jointAbbreviation,value)
                    return valString
                    
                elif self._editable and index.column() in self._joint_columns.keys():
                    joint_info = self._joint_columns[index.column()]
                    try:
                        value = self._action_sequence.actions()[index.row()].get_value(joint_info['label'])
                        if joint_info['decimals'] is not None:
                            value = round(value, joint_info['decimals'])
                        else:
                            value = int(round(value))
                        return value
                    except:
                        return ''
            if role == Qt.EditRole:
                if index.column() == 0:
                    return self._action_sequence.actions()[index.row()].get_duration()
                elif index.column() == 1: # speech column:
                    actionSets = self._action_sequence.actions()
                    actionIndex = index.row()
                    actionSetAtIndex = actionSets[actionIndex]
                    try:
                        waitTillDone = actionSetAtIndex.get_value('waitForSpeechDone')
                        utterance = actionSetAtIndex.get_value('text')
                    except KeyError:
                        return (None,None)
                    res = (waitTillDone, utterance)
                    return res
                elif self._editable and index.column() in self._joint_columns.keys():
                    joint_info = self._joint_columns[index.column()]
                    try:
                        value = self._action_sequence.actions()[index.row()].get_value(joint_info['label'])
                        if joint_info['decimals'] is not None:
                            value = round(value, joint_info['decimals'])
                        else:
                            value = int(round(value))
                        return value
                    except:
                        return ''
        return None

    def setData(self, index, value, role):
        if role == Qt.EditRole:
            if index.column() == 0: # duration
                value = float(value)
                self._action_sequence.actions()[index.row()].set_duration(value)
                self.duration_modified.emit()
                return True
            elif index.column() == 1: # speech
                try:
                    actionSets = self._action_sequence.actions()
                    actionIndex = index.row()
                    actionSetAtIndex = actionSets[actionIndex]
                    actionSetAtIndex._actions[0].update_value('waitForSpeechDone', value[0]) # Wait/Don't Wait
                    actionSetAtIndex._actions[0].update_value('text', value[1]) # Utterance
                except Exception as e:
                    return False
                return True
            elif self._editable:
                value = float(value)
                try:
                    self._action_sequence.actions()[index.row()].update_value(self._joint_columns[index.column()]['label'], value)
                except:
                    return False
                return True
        return super(PosesDataModel, self).setData(index, value, role)

    def flags(self, index):
        f = super(PosesDataModel, self).flags(index)
        if index.isValid():
            if index.column() == 0:
                # Duration is editable:
                f |= Qt.ItemIsEditable
            elif index.column() == 1:
                # Speech column is editable:
                f |= Qt.ItemIsEditable
            elif self._editable and index.column() in self._joint_columns.keys():
                try:
                    # only cell which have real values can be edited
                    self._action_sequence.actions()[index.row()].get_value(self._joint_columns[index.column()]['label'])
                    f |= Qt.ItemIsEditable
                except:
                    pass
            f |= Qt.ItemIsDragEnabled
        f |= Qt.ItemIsDropEnabled
        return f

    def headerData(self, section, orientation, role=None):
        if role is None:
            role = Qt.DisplayRole
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                if section == 0:
                    return 'Time'
                elif section == 1:
                    return 'Speech'
                elif not self._editable and section == 2:
                    return 'Joints'
                elif self._editable and section in self._joint_columns.keys():
                    return self._joint_columns[section]['header']
            elif orientation == Qt.Vertical:
                return 'Pose %d' % (section + 1)
        return None

    def supportedDropActions(self):
        return Qt.CopyAction | Qt.MoveAction

    def mimeTypes(self):
        return [self._mime_type]

    def mimeData(self, indexes):
        #print 'mimeData()'
        row = None
        for index in indexes:
            if index.isValid():
                if row is None:
                    row = index.row()
                if row != index.row():
                    row = None
                    break

        mimeData = QMimeData()
        if row is not None:
            mimeData.setData(self._mime_type, QByteArray.number(row))
        return mimeData;

    def dropMimeData(self, data, action, row, column, parent):
        #print 'dropMimeData()'
        if action == Qt.MoveAction:
            before_row = None
            if row != -1:
                before_row = row
            elif parent.isValid():
                before_row = parent.row()
            else:
                before_row = self.rowCount()
            if data.hasFormat(self._mime_type):
                byte_array = data.data(self._mime_type)
                source_row, is_int = byte_array.toInt()
                if is_int and before_row != source_row + 1:
                    #print 'dropMimeData()', source_row, '->', before_row
                    self.move_action(source_row, before_row)
                    return True
        return super(PosesDataModel, self).dropMimeData(data, action, row, column, parent)

    def add_delegates(self, table_view):
        for i in self._joint_columns.keys():
            joint_info = self._joint_columns[i]
            
            if joint_info['decimals'] is None:
                delegate = IntegerSpinBoxDelegate()
            else: 
                delegate = DoubleSpinBoxDelegate()
                delegate.setDecimals(joint_info['decimals'])
            delegate.setMinimum(joint_info['min'])
            delegate.setMaximum(joint_info['max'])
            delegate.setSingleStep(joint_info['single_step'])
            table_view.setItemDelegateForColumn(i, delegate)
            self._delegates.append(delegate)
コード例 #4
0
class PosesDataModel(QAbstractTableModel):

    actions_changed = Signal()
    duration_modified = Signal()

    _mime_type = 'application/x-slider-action'

    def __init__(self, editable=False):
        super(PosesDataModel, self).__init__()
        self._action_sequence = ActionSequence()
        self._editable = editable
        self._joint_columns = {}

        action = DefaultAction()
        self._add_joint(1, action, 'head_pan_joint', 'Hd Turn')
        self._add_joint(2, action, 'head_tilt_joint', 'Hd Nod')
        self._add_joint(3, action, 'torso_lift_joint', 'Torso', 2)
        self._add_joint(4, action, 'l_shoulder_pan_joint', 'Lp1')
        self._add_joint(5, action, 'l_shoulder_lift_joint', 'Ll2')
        self._add_joint(6, action, 'l_upper_arm_roll_joint', 'Lu3')
        self._add_joint(7, action, 'l_elbow_flex_joint', 'Le4')
        self._add_joint(8, action, 'l_forearm_roll_joint', 'Lf5')
        self._add_joint(9, action, 'l_wrist_flex_joint', 'Lw6')
        self._add_joint(10, action, 'l_wrist_roll_joint', 'Lr7')
        self._add_joint(11, action, 'l_gripper', 'LGrip', 3)
        self._add_joint(12, action, 'r_shoulder_pan_joint', 'Rp1')
        self._add_joint(13, action, 'r_shoulder_lift_joint', 'Rl2')
        self._add_joint(14, action, 'r_upper_arm_roll_joint', 'Ru3')
        self._add_joint(15, action, 'r_elbow_flex_joint', 'Re4')
        self._add_joint(16, action, 'r_forearm_roll_joint', 'Rf5')
        self._add_joint(17, action, 'r_wrist_flex_joint', 'Rw6')
        self._add_joint(18, action, 'r_wrist_roll_joint', 'Rr7')
        self._add_joint(19, action, 'r_gripper', 'RGrip', 3)

        # keep reference to delegates to prevent being garbaged
        self._delegates = []

    def _add_joint(self, column, action, label, header, precision=None):
        info = copy(action.get_joint_info(label))
        info['header'] = header
        info['decimals'] = precision
        self._joint_columns[column] = info

    def set_editable(self, editable):
        if self._editable != editable:
            self._editable = editable
            self.reset()

    def add_action(self, action, index=None):
        self._add_action(action, index)
        self.actions_changed.emit()
        self.duration_modified.emit()

    def _add_action(self, action, index=None):
        model_index = QModelIndex()
        if index is None or index == len(self._action_sequence.actions()):
            rows = len(self._action_sequence.actions())
            index = None
        else:
            assert (index >= 0
                    and index < len(self._action_sequence.actions()))
            rows = index

        # insert at model-index of parent-item
        self.beginInsertRows(model_index, rows, rows)
        self._action_sequence.add_action(action, index)
        self.endInsertRows()

    def move_action(self, source_index, destination_index):
        assert (source_index >= 0
                and source_index < len(self._action_sequence.actions()))
        assert (destination_index >= 0
                and destination_index <= len(self._action_sequence.actions()))
        action = self._action_sequence.actions()[source_index]
        self._remove_action(source_index)
        if destination_index > source_index:
            destination_index -= 1
        self._add_action(action, destination_index)
        self.actions_changed.emit()

    def remove_action(self, index):
        self._remove_action(index)
        self.actions_changed.emit()
        self.duration_modified.emit()

    def _remove_action(self, index):
        assert (index >= 0 and index < len(self._action_sequence.actions()))
        # delete at model-index of parent-item
        model_index = QModelIndex()
        self.beginRemoveRows(model_index, index, index)
        self._action_sequence.remove_action(index)
        self.endRemoveRows()

    def remove_all_actions(self):
        index = QModelIndex()
        rows = len(self._action_sequence.actions())
        self.beginRemoveRows(index, 0, rows - 1)
        self._action_sequence.remove_all_actions()
        self.endRemoveRows()
        self.actions_changed.emit()
        self.duration_modified.emit()

    def action_sequence(self):
        return self._action_sequence

    def rowCount(self, parent=None):
        return len(self._action_sequence.actions())

    def columnCount(self, parent=None):
        if self._editable:
            return 1 + len(self._joint_columns)
        else:
            return 1 + 1

    def data(self, index, role=None):
        if role is None:
            role = Qt.DisplayRole
        if index.row() >= 0 and index.row() < len(
                self._action_sequence.actions()):
            if role == Qt.DisplayRole:
                if index.column() == 0:
                    return '%.1f' % self._action_sequence.actions()[
                        index.row()].get_duration()
                elif not self._editable and index.column() == 1:
                    return self._action_sequence.actions()[
                        index.row()].to_string()
                elif self._editable and index.column(
                ) in self._joint_columns.keys():
                    joint_info = self._joint_columns[index.column()]
                    try:
                        value = self._action_sequence.actions()[
                            index.row()].get_value(joint_info['label'])
                        if joint_info['decimals'] is not None:
                            value = round(value, joint_info['decimals'])
                        else:
                            value = int(round(value))
                        return value
                    except:
                        return ''
            if role == Qt.EditRole:
                if index.column() == 0:
                    return self._action_sequence.actions()[
                        index.row()].get_duration()
                elif self._editable and index.column(
                ) in self._joint_columns.keys():
                    joint_info = self._joint_columns[index.column()]
                    try:
                        value = self._action_sequence.actions()[
                            index.row()].get_value(joint_info['label'])
                        if joint_info['decimals'] is not None:
                            value = round(value, joint_info['decimals'])
                        else:
                            value = int(round(value))
                        return value
                    except:
                        return ''
        return None

    def setData(self, index, value, role):
        if role == Qt.EditRole:
            if index.column() == 0:
                value = float(value)
                self._action_sequence.actions()[index.row()].set_duration(
                    value)
                self.duration_modified.emit()
                return True
            elif self._editable:
                value = float(value)
                try:
                    self._action_sequence.actions()[index.row()].update_value(
                        self._joint_columns[index.column()]['label'], value)
                except:
                    return False
                return True
        return super(PosesDataModel, self).setData(index, value, role)

    def flags(self, index):
        f = super(PosesDataModel, self).flags(index)
        if index.isValid():
            if index.column() == 0:
                f |= Qt.ItemIsEditable
            elif self._editable and index.column() in self._joint_columns.keys(
            ):
                try:
                    # only cell which have real values can be edited
                    self._action_sequence.actions()[index.row()].get_value(
                        self._joint_columns[index.column()]['label'])
                    f |= Qt.ItemIsEditable
                except:
                    pass
            f |= Qt.ItemIsDragEnabled
        f |= Qt.ItemIsDropEnabled
        return f

    def headerData(self, section, orientation, role=None):
        if role is None:
            role = Qt.DisplayRole
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                if section == 0:
                    return 'Time'
                elif not self._editable and section == 1:
                    return 'Joints'
                elif self._editable and section in self._joint_columns.keys():
                    return self._joint_columns[section]['header']
            elif orientation == Qt.Vertical:
                return 'Pose %d' % (section + 1)
        return None

    def supportedDropActions(self):
        return Qt.CopyAction | Qt.MoveAction

    def mimeTypes(self):
        return [self._mime_type]

    def mimeData(self, indexes):
        #print 'mimeData()'
        row = None
        for index in indexes:
            if index.isValid():
                if row is None:
                    row = index.row()
                if row != index.row():
                    row = None
                    break

        mimeData = QMimeData()
        if row is not None:
            mimeData.setData(self._mime_type, QByteArray.number(row))
        return mimeData

    def dropMimeData(self, data, action, row, column, parent):
        #print 'dropMimeData()'
        if action == Qt.MoveAction:
            before_row = None
            if row != -1:
                before_row = row
            elif parent.isValid():
                before_row = parent.row()
            else:
                before_row = self.rowCount()
            if data.hasFormat(self._mime_type):
                byte_array = data.data(self._mime_type)
                source_row, is_int = byte_array.toInt()
                if is_int and before_row != source_row + 1:
                    #print 'dropMimeData()', source_row, '->', before_row
                    self.move_action(source_row, before_row)
                    return True
        return super(PosesDataModel,
                     self).dropMimeData(data, action, row, column, parent)

    def add_delegates(self, table_view):
        for i in self._joint_columns.keys():
            joint_info = self._joint_columns[i]
            if joint_info['decimals'] is not None:
                delegate = DoubleSpinBoxDelegate()
                delegate.setDecimals(joint_info['decimals'])
            else:
                delegate = IntegerSpinBoxDelegate()
            delegate.setMinimum(joint_info['min'])
            delegate.setMaximum(joint_info['max'])
            delegate.setSingleStep(joint_info['single_step'])
            table_view.setItemDelegateForColumn(i, delegate)
            self._delegates.append(delegate)