class MidiLearnDialog(QDialog, Ui_midiLearnDialog):
    def __init__(self, deviceId, parent = None):
        super(MidiLearnDialog, self).__init__(parent)
        self.setupUi(self)
        self.thread = MidiControlThread(deviceId)
        self._midiData = None
        self.buttonBox.clicked.connect(self._buttonClicked)

    def exec_(self):
        self.thread.midiReceived.connect(self._midiReceived)
        self.thread.start()
        return super(MidiLearnDialog, self).exec_()

    def reject(self):
        self.thread.close()
        self.thread.wait()
        super(MidiLearnDialog, self).reject()

    def accept(self):
        self.thread.close()
        self.thread.wait()
        super(MidiLearnDialog, self).accept()

    def _midiReceived(self, midiMsg):
        self._midiData = midiMsg
        self.accept()

    def getMidiData(self):
        return self._midiData

    def _buttonClicked(self, button):
        if button == self.buttonBox.button(self.buttonBox.Discard):
            self._midiData = None
            self.accept()
class MidiLearnPairedDialog(QDialog, Ui_MidiLearnPairedDialog):
    '''
    classdocs
    '''


    def __init__(self, midiDeviceId, parent = None):
        '''
        Constructor
        '''
        super(MidiLearnPairedDialog, self).__init__(parent)
        self.setupUi(self)
        self.secondMidiBox.setDisabled(True)
        self.thread = MidiControlThread(midiDeviceId)
        self._midiData = []
        self.buttonBox.clicked.connect(self._buttonClicked)

    def exec_(self):
        self.thread.midiReceived.connect(self._midiReceived)
        self.thread.start()
        return super(MidiLearnPairedDialog, self).exec_()

    def reject(self):
        self.thread.close()
        self.thread.wait()
        super(MidiLearnPairedDialog, self).reject()

    def accept(self):
        self.thread.close()
        self.thread.wait()
        super(MidiLearnPairedDialog, self).accept()

    def _midiReceived(self, midiMsg):
        self._midiData.append(midiMsg)
        if len(self._midiData) == 1:
            self.firstMidiBox.setChecked(True)
            self.firstMidiBox.setEnabled(False)
            self.secondMidiBox.setEnabled(True)
        else:
            self.secondMidiBox.setChecked(True)
            self.secondMidiBox.setEnabled(False)
            self._midiData = PairedMidi(*self._midiData)
            self.accept()

    def getMidiData(self):
        return self._midiData

    def _buttonClicked(self, button):
        if button == self.buttonBox.button(self.buttonBox.Discard):
            self._midiData = None
            self.accept()
 def openMidiDevice(self, deviceId):
     self.midiDevice = deviceId
     if self._midiThread is not None:
         self.closeMidiDevice()
     self._midiThread = MidiControlThread(deviceId)
     self._midiThread.midiReceived.connect(self.midiToAction)
     self._midiThread.start()
 def __init__(self, midiDeviceId, parent = None):
     '''
     Constructor
     '''
     super(MidiLearnPairedDialog, self).__init__(parent)
     self.setupUi(self)
     self.secondMidiBox.setDisabled(True)
     self.thread = MidiControlThread(midiDeviceId)
     self._midiData = []
     self.buttonBox.clicked.connect(self._buttonClicked)
 def __init__(self, deviceId, parent = None):
     super(MidiLearnDialog, self).__init__(parent)
     self.setupUi(self)
     self.thread = MidiControlThread(deviceId)
     self._midiData = None
     self.buttonBox.clicked.connect(self._buttonClicked)
class ControlSet(object):
    '''
    classdocs
    '''


    def __init__(self, midiDevice = -1):
        '''
        Constructor
        '''
        self.midiDevice = midiDevice
        self._midiThread = None
        self._midiRecogniser = MidiRecogniser()
        self._midi = {}
        self._actions = []
        self._descriptions = {}
        self._actionPairs = set()
        self._parameterActions = set()
        self._shortcuts = {}
        self._byOp = {}

    def _addAction(self, action, description):
        if action not in self._actions:
            self._actions.append(action)
            self._descriptions[action] = description
            self._shortcuts[action] = action.shortcut()
            self._byOp[action.opnum] = action

    def addSingleAction(self, action, description, opnum):
        self._addAction(SingleAction(action, opnum), description)

    def addActionPair(self, actionOn, actionOff, shortcut, description, opnum):
        actionPair = ActionPair(actionOn, actionOff, shortcut, opnum)
        self._actionPairs.add(actionPair)
        self._addAction(actionPair, description)

    def addParameterAction(self, method, description,
                           outputMin, outputMax, opnum):
        parameterAction = ParameterAction(method, outputMin, outputMax, opnum)
        self._parameterActions.add(parameterAction)
        self._addAction(parameterAction, description)

    def __getitem__(self, index):
        return self._actions[index]

    def __len__(self):
        return len(self._actions)

    def iterActions(self):
        return iter(self._actions)

    def getDescription(self, action):
        return self._descriptions.get(action, "")

    def getShortcutString(self, action):
        if action not in self._descriptions:
            raise KeyError("Unrecognised action")
        shortcut = self._shortcuts[action]
        if shortcut is None:
            return ""
        else:
            return shortcut.toString()

    def setShortcut(self, action, shortcut):
        if action not in self._descriptions:
            raise KeyError("Unrecognised action")
        action.setShortcut(shortcut)

    def getMidi(self, action):
        if action not in self._descriptions:
            raise KeyError("Unrecognised action")
        return self._midi.get(action, None)

    def getMidiAsString(self, action):
        if action not in self._descriptions:
            raise KeyError("Unrecognised action")
        if action not in self._midi:
            return ""
        return self._midi[action].unparamString()

    def isValidMidi(self, action, midiMsg):
        if isinstance(midiMsg, SysExMessage):
            return False
        elif action in self._actionPairs:
            return isinstance(midiMsg, PairedMidi)
        else:
            return isinstance(midiMsg, MidiMessage)

    def setMidi(self, action, midiData):
        if action not in self._descriptions:
            raise KeyError("Unrecognised action")
        if midiData is None and action in self._midi:
            midiData = self._midi[action]
            if action.numActions() == 1:
                self._midiRecogniser.removeMessageTarget(midiData)
            else:
                self._midiRecogniser.removeMessageTarget(midiData.midiOn)
                self._midiRecogniser.removeMessageTarget(midiData.midiOff)
            del self._midi[action]
        elif midiData is not None:
            if action.numActions() == 1:
                self._midi[action] = midiData
                self._midiRecogniser.addMessageTarget(midiData, action)
            elif not isinstance(midiData, PairedMidi):
                raise TypeError("On/Off actions require two MIDI messages")
            else:
                self._midi[action] = midiData
                self._midiRecogniser.addMessageTarget(midiData.midiOn,
                                                      action.actionOn)
                self._midiRecogniser.addMessageTarget(midiData.midiOff,
                                                      action.actionOff)


    def openMidiDevice(self, deviceId):
        self.midiDevice = deviceId
        if self._midiThread is not None:
            self.closeMidiDevice()
        self._midiThread = MidiControlThread(deviceId)
        self._midiThread.midiReceived.connect(self.midiToAction)
        self._midiThread.start()

    def closeMidiDevice(self):
        if self._midiThread is not None:
            self._midiThread.close()
            self._midiThread.wait()

    def midiToAction(self, midiData):
        target = self._midiRecogniser.getTarget(midiData)
        if target is None:
            return
        if target in self._parameterActions:
            target.trigger(midiData.parameterValue())
        else:
            target.trigger()

    def save(self, handle, midiDict = None):
        if midiDict is None:
            midiDict = self._midi
        for action in self.iterActions():
            opnum = action.opnum
            midiMsg = midiDict.get(action, None)
            pickle.dump((opnum, midiMsg), handle)

    def load(self, handle):
        newMidi = dict((action, None) for action in self.iterActions())
        try:
            while True:
                opnum, midiMsg = pickle.load(handle)
                newMidi[self._byOp[opnum]] = midiMsg
        except EOFError:
            return newMidi
        return None