class ConservationTrackingGui(TrackingBaseGui, ExportingGui):

    withMergers = True

    @threadRouted
    def _setMergerLegend(self, labels, selection):
        param = self.topLevelOperatorView.Parameters.value
        if 'withMergerResolution' in list(param.keys()):
            if param['withMergerResolution']:
                selection = 1
        elif self._drawer.mergerResolutionBox.isChecked():
            selection = 1

        for i in range(2, len(labels) + 1):
            if i <= selection:
                labels[i - 1].setVisible(True)
            else:
                labels[i - 1].setVisible(False)

        # hide merger legend if selection < 2
        self._drawer.label_4.setVisible(selection > 1)
        labels[0].setVisible(selection > 1)

    def _loadUiFile(self):
        # Load the ui file (find it in our own directory)
        localDir = os.path.split(__file__)[0]
        self._drawer = uic.loadUi(localDir + "/drawer.ui")

        parameters = self.topLevelOperatorView.Parameters.value
        if 'maxDist' in list(parameters.keys()):
            self._drawer.maxDistBox.setValue(parameters['maxDist'])
        if 'maxObj' in list(parameters.keys()):
            self._drawer.maxObjectsBox.setValue(parameters['maxObj'])
        if 'divThreshold' in list(parameters.keys()):
            self._drawer.divThreshBox.setValue(parameters['divThreshold'])
        if 'avgSize' in list(parameters.keys()):
            self._drawer.avgSizeBox.setValue(parameters['avgSize'][0])
        if 'withTracklets' in list(parameters.keys()):
            self._drawer.trackletsBox.setChecked(parameters['withTracklets'])
        if 'sizeDependent' in list(parameters.keys()):
            self._drawer.sizeDepBox.setChecked(parameters['sizeDependent'])
        if 'divWeight' in list(parameters.keys()):
            self._drawer.divWeightBox.setValue(parameters['divWeight'])
        if 'transWeight' in list(parameters.keys()):
            self._drawer.transWeightBox.setValue(parameters['transWeight'])
        if 'withDivisions' in list(parameters.keys()):
            self._drawer.divisionsBox.setChecked(parameters['withDivisions'])
        if 'withOpticalCorrection' in list(parameters.keys()):
            self._drawer.opticalBox.setChecked(
                parameters['withOpticalCorrection'])
        if 'withClassifierPrior' in list(parameters.keys()):
            self._drawer.classifierPriorBox.setChecked(
                parameters['withClassifierPrior'])
        if 'withMergerResolution' in list(parameters.keys()):
            self._drawer.mergerResolutionBox.setChecked(
                parameters['withMergerResolution'])
        if 'borderAwareWidth' in list(parameters.keys()):
            self._drawer.bordWidthBox.setValue(parameters['borderAwareWidth'])
        if 'cplex_timeout' in list(parameters.keys()):
            self._drawer.timeoutBox.setText(str(parameters['cplex_timeout']))
        if 'appearanceCost' in list(parameters.keys()):
            self._drawer.appearanceBox.setValue(parameters['appearanceCost'])
        if 'disappearanceCost' in list(parameters.keys()):
            self._drawer.disappearanceBox.setValue(
                parameters['disappearanceCost'])
        if 'max_nearest_neighbors' in list(parameters.keys()):
            self._drawer.maxNearestNeighborsSpinBox.setValue(
                parameters['max_nearest_neighbors'])
        if 'numFramesPerSplit' in list(parameters.keys()):
            self._drawer.numFramesPerSplitSpinBox.setValue(
                parameters['numFramesPerSplit'])

        # solver: use stored value only if that solver is available
        self._drawer.solverComboBox.clear()
        availableSolvers = self.getAvailableTrackingSolverTypes()
        self._drawer.solverComboBox.addItems(availableSolvers)
        if 'solver' in list(parameters.keys()
                            ) and parameters['solver'] in availableSolvers:
            self._drawer.solverComboBox.setCurrentIndex(
                availableSolvers.index(parameters['solver']))

        # listen on the main operator's NumLabels slot for changes, and adjust the max value of the "maxNumObjects" box
        self.topLevelOperatorView.NumLabels.notifyDirty(
            self._updateMaxObjectsBoxMaxValue)
        self._updateMaxObjectsBoxMaxValue()

        # Hide division GUI widgets
        if 'withAnimalTracking' in list(parameters.keys(
        )) and parameters['withAnimalTracking'] == True:
            self._drawer.label_5.hide()
            self._drawer.divThreshBox.hide()
            self._drawer.divisionsBox.hide()
            self._drawer.divWeightBox.hide()
            self._drawer.label_6.hide()

        return self._drawer

    @threadRouted
    def _updateMaxObjectsBoxMaxValue(self, *args, **kwargs):
        if self.topLevelOperatorView.NumLabels.ready():
            if self.topLevelOperatorView.NumLabels.value > 1:
                self._drawer.maxObjectsBox.setMaximum(
                    self.topLevelOperatorView.NumLabels.value - 1)
                self._drawer.maxObjectsBox.setValue(
                    self.topLevelOperatorView.NumLabels.value - 1)
                self._drawer.TrackButton.setEnabled(True)
            else:
                self._drawer.maxObjectsBox.setMaximum(0)
                self._drawer.maxObjectsBox.setValue(0)
                self._drawer.TrackButton.setEnabled(False)

    @staticmethod
    def getAvailableTrackingSolverTypes():
        solvers = []
        try:
            if dpct:
                solvers.append('Flow-based')
        except Exception as e:
            logger.info(str(e))

        try:
            if mht:
                solvers.append('ILP')
        except Exception as e:
            logger.info(str(e))

        return solvers

    def initAppletDrawerUi(self):
        super(ConservationTrackingGui, self).initAppletDrawerUi()

        self._allowedTimeoutInputRegEx = re.compile('^[0-9]*$')
        self._drawer.timeoutBox.textChanged.connect(self._onTimeoutBoxChanged)

        if not ilastik_config.getboolean("ilastik", "debug"):

            def checkboxAssertHandler(checkbox, assertEnabled=True):
                if checkbox.isChecked() == assertEnabled:
                    checkbox.hide()
                else:
                    checkbox.setEnabled(False)

            checkboxAssertHandler(self._drawer.trackletsBox, True)

            if self._drawer.classifierPriorBox.isChecked():
                self._drawer.hardPriorBox.hide()
                self._drawer.classifierPriorBox.hide()
                self._drawer.sizeDepBox.hide()
            else:
                self._drawer.hardPriorBox.setEnabled(False)
                self._drawer.classifierPriorBox.setEnabled(False)
                self._drawer.sizeDepBox.setEnabled(False)

            checkboxAssertHandler(self._drawer.opticalBox, False)
            checkboxAssertHandler(self._drawer.mergerResolutionBox, True)

            self._drawer.maxDistBox.hide()  # hide the maximal distance box
            self._drawer.label_2.hide()  # hie the maximal distance label
            self._drawer.label_5.hide()  # hide division threshold label
            self._drawer.divThreshBox.hide()
            self._drawer.label_25.hide()  # hide avg. obj size label
            self._drawer.avgSizeBox.hide()
            self._drawer.label_24.hide()  # hide motion model weight label
            self._drawer.motionModelWeightBox.hide()

        self.mergerLabels = [
            self._drawer.merg1, self._drawer.merg2, self._drawer.merg3,
            self._drawer.merg4, self._drawer.merg5, self._drawer.merg6,
            self._drawer.merg7
        ]
        for i in range(len(self.mergerLabels)):
            self._labelSetStyleSheet(self.mergerLabels[i],
                                     QColor(self.mergerColors[i + 1]))

        self._onMaxObjectsBoxChanged()
        self._drawer.maxObjectsBox.valueChanged.connect(
            self._onMaxObjectsBoxChanged)
        self._drawer.mergerResolutionBox.stateChanged.connect(
            self._onMaxObjectsBoxChanged)

        self._drawer.exportButton.hide()

    @threadRouted
    def _onTimeoutBoxChanged(self, *args):
        inString = str(self._drawer.timeoutBox.text())
        if self._allowedTimeoutInputRegEx.match(inString) is None:
            self._drawer.timeoutBox.setText(inString[:-1])

    def _setRanges(self, *args):
        super(ConservationTrackingGui, self)._setRanges()
        maxx = self.topLevelOperatorView.LabelImage.meta.shape[1] - 1
        maxy = self.topLevelOperatorView.LabelImage.meta.shape[2] - 1
        maxz = self.topLevelOperatorView.LabelImage.meta.shape[3] - 1

        maxBorder = min(maxx, maxy)
        if maxz != 0:
            maxBorder = min(maxBorder, maxz)
        self._drawer.bordWidthBox.setRange(0, old_div(maxBorder, 2))

    def _onMaxObjectsBoxChanged(self):
        self._setMergerLegend(self.mergerLabels,
                              self._drawer.maxObjectsBox.value())

    def _onTrackButtonPressed(self):
        if not self.mainOperator.ObjectFeatures.ready():
            self._criticalMessage("You have to compute object features first.")
            return

        withMergerResolution = self._drawer.mergerResolutionBox.isChecked()
        numStages = 8
        # object features
        # detection probabilities
        # creating traxel store
        # generating probabilities
        # insert energies
        # convexify costs
        # solver
        # compute lineages
        if self._drawer.divisionsBox.isChecked():
            # division probabilities
            numStages += 1

        if withMergerResolution:
            numStages += 1  # merger resolution
        withTracklets = self._drawer.trackletsBox.isChecked()
        if withTracklets:
            numStages += 3  # initializing tracklet graph, finding tracklets, contracting edges in tracklet graph

        self.progressWindow = TrackProgressDialog(parent=self,
                                                  numStages=numStages)
        self.progressWindow.run()
        self.progressWindow.show()
        self.progressVisitor = GuiProgressVisitor(
            progressWindow=self.progressWindow)

        def _track():
            self.applet.busy = True
            self.applet.appletStateUpdateRequested()
            maxDist = self._drawer.maxDistBox.value()
            maxObj = self._drawer.maxObjectsBox.value()
            divThreshold = self._drawer.divThreshBox.value()

            from_t = self._drawer.from_time.value()
            to_t = self._drawer.to_time.value()
            from_x = self._drawer.from_x.value()
            to_x = self._drawer.to_x.value()
            from_y = self._drawer.from_y.value()
            to_y = self._drawer.to_y.value()
            from_z = self._drawer.from_z.value()
            to_z = self._drawer.to_z.value()
            from_size = self._drawer.from_size.value()
            to_size = self._drawer.to_size.value()

            self.time_range = list(range(from_t, to_t + 1))
            avgSize = [self._drawer.avgSizeBox.value()]

            cplex_timeout = None
            if len(str(self._drawer.timeoutBox.text())):
                cplex_timeout = int(self._drawer.timeoutBox.text())

            withTracklets = self._drawer.trackletsBox.isChecked()
            sizeDependent = self._drawer.sizeDepBox.isChecked()
            hardPrior = self._drawer.hardPriorBox.isChecked()
            classifierPrior = self._drawer.classifierPriorBox.isChecked()
            divWeight = self._drawer.divWeightBox.value()
            transWeight = self._drawer.transWeightBox.value()
            withDivisions = self._drawer.divisionsBox.isChecked()
            withOpticalCorrection = self._drawer.opticalBox.isChecked()
            withMergerResolution = self._drawer.mergerResolutionBox.isChecked()
            borderAwareWidth = self._drawer.bordWidthBox.value()
            withArmaCoordinates = True
            appearanceCost = self._drawer.appearanceBox.value()
            disappearanceCost = self._drawer.disappearanceBox.value()

            motionModelWeight = self._drawer.motionModelWeightBox.value()
            solver = self._drawer.solverComboBox.currentText()

            ndim = 3
            if (to_z - from_z == 0):
                ndim = 2

            try:
                self.mainOperator.track(
                    time_range=self.time_range,
                    x_range=(from_x, to_x + 1),
                    y_range=(from_y, to_y + 1),
                    z_range=(from_z, to_z + 1),
                    size_range=(from_size, to_size + 1),
                    x_scale=self._drawer.x_scale.value(),
                    y_scale=self._drawer.y_scale.value(),
                    z_scale=self._drawer.z_scale.value(),
                    maxDist=maxDist,
                    maxObj=maxObj,
                    divThreshold=divThreshold,
                    avgSize=avgSize,
                    withTracklets=withTracklets,
                    sizeDependent=sizeDependent,
                    detWeight=10.0,
                    divWeight=divWeight,
                    transWeight=transWeight,
                    withDivisions=withDivisions,
                    withOpticalCorrection=withOpticalCorrection,
                    withClassifierPrior=classifierPrior,
                    ndim=ndim,
                    withMergerResolution=withMergerResolution,
                    borderAwareWidth=borderAwareWidth,
                    withArmaCoordinates=withArmaCoordinates,
                    cplex_timeout=cplex_timeout,
                    appearance_cost=appearanceCost,
                    disappearance_cost=disappearanceCost,
                    motionModelWeight=motionModelWeight,
                    force_build_hypotheses_graph=False,
                    max_nearest_neighbors=self._drawer.
                    maxNearestNeighborsSpinBox.value(),
                    numFramesPerSplit=self._drawer.numFramesPerSplitSpinBox.
                    value(),
                    solverName=solver,
                    progressWindow=self.progressWindow,
                    progressVisitor=self.progressVisitor)

            except Exception as ex:
                self.progressWindow.onTrackDone()
                log_exception(
                    logger,
                    "Error during tracking.  See above error traceback.")
                self._criticalMessage(
                    "Error during tracking.  See error log.\n\n"
                    "Exception was:\n\n{})".format(ex))
                return

        def _handle_finished(*args):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested()
            self._drawer.TrackButton.setEnabled(True)
            self._drawer.exportButton.setEnabled(True)
            self._drawer.exportTifButton.setEnabled(True)
            self._setLayerVisible("Objects", False)

            # update showing the merger legend,
            # as it might be (no longer) needed if merger resolving
            # is disabled(enabled)
            self._setMergerLegend(self.mergerLabels,
                                  self._drawer.maxObjectsBox.value())

        def _handle_failure(exc, exc_info):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested()
            traceback.print_exception(*exc_info)
            sys.stderr.write(
                "Exception raised during tracking.  See traceback above.\n")
            self._drawer.TrackButton.setEnabled(True)

        req = Request(_track)
        req.notify_failed(_handle_failure)
        req.notify_finished(_handle_finished)
        req.submit()

    def get_raw_shape(self):
        return self.topLevelOperatorView.RawImage.meta.shape

    def get_feature_names(self):
        params = self.topLevelOperatorView.Parameters
        if params.ready() and params.value["withDivisions"]:
            return self.topLevelOperatorView.ComputedFeatureNamesWithDivFeatures(
                []).wait()
        return self.topLevelOperatorView.ComputedFeatureNames([]).wait()

    def get_color(self, pos5d):
        slicing = tuple(slice(i, i + 1) for i in pos5d)
        color = self.mainOperator.CachedOutput(slicing).wait()
        return color.flat[0]

    def get_object(self, pos5d):
        slicing = tuple(slice(i, i + 1) for i in pos5d)
        label = self.mainOperator.RelabeledImage(slicing).wait()
        return label.flat[0], pos5d[0]

    @property
    def gui_applet(self):
        return self.applet

    def get_export_dialog_title(self):
        return "Export Tracking Information"

    def handleEditorRightClick(self, position5d, win_coord):
        debug = ilastik_config.getboolean("ilastik", "debug")

        obj, time = self.get_object(position5d)
        if obj == 0:
            menu = TitledMenu(["Background"])
            if debug:
                menu.addAction("Clear Hilite",
                               IPCFacade().broadcast(Protocol.cmd("clear")))
            menu.exec_(win_coord)
            return

        # Get color and track from hypotheses graph (which is a slot in the new operator)
        hypothesesGraph = self.mainOperator.HypothesesGraph.value

        if hypothesesGraph == None:
            color = None
            track = None
        else:
            color = hypothesesGraph.getLineageId(time, obj)
            track = hypothesesGraph.getTrackId(time, obj)

        tracks = None
        children = None
        parents = None

        menu = TitledMenu([
            "Object {} of lineage id {}".format(obj, color),
            "Track id: " + (str(track) or "None"),
        ])

        if not debug:
            menu.exec_(win_coord)
            return

        if any(IPCFacade().sending):

            obj_sub_menu = menu.addMenu("Hilite Object")
            for mode in Protocol.ValidHiliteModes:
                where = Protocol.simple("and", ilastik_id=obj, time=time)
                cmd = Protocol.cmd(mode, where)
                obj_sub_menu.addAction(mode.capitalize(),
                                       IPCFacade().broadcast(cmd))

            sub_menus = [("Tracks", Protocol.simple_in, tracks),
                         ("Parents", Protocol.simple_in, parents),
                         ("Children", Protocol.simple_in, children)]
            for name, protocol, args in sub_menus:
                if args:
                    sub = menu.addMenu("Hilite {}".format(name))
                    for mode in Protocol.ValidHiliteModes[:-1]:
                        mode = mode.capitalize()
                        where = protocol("track_id*", args)
                        cmd = Protocol.cmd(mode, where)
                        sub.addAction(mode, IPCFacade().broadcast(cmd))
                else:
                    sub = menu.addAction("Hilite {}".format(name))
                    sub.setEnabled(False)

            menu.addAction("Clear Hilite",
                           IPCFacade().broadcast(Protocol.cmd("clear")))
        else:
            menu.addAction("Open IPC Server Window", IPCFacade().show_info)
            menu.addAction("Start IPC Server", IPCFacade().start)

        menu.exec_(win_coord)
class StructuredTrackingGui(TrackingBaseGui, ExportingGui):
    
    withMergers = True
    @threadRouted
    def _setMergerLegend(self, labels, selection):   
        param = self.topLevelOperatorView.Parameters.value
        if 'withMergerResolution' in list(param.keys()):
            if param['withMergerResolution']:
                selection = 1
        elif self._drawer.mergerResolutionBox.isChecked():
            selection = 1

        for i in range(2,len(labels)+1):
            if i <= selection:
                labels[i-1].setVisible(True)
            else:
                labels[i-1].setVisible(False)

        # hide merger legend if selection < 2
        self._drawer.label_4.setVisible(selection > 1)
        labels[0].setVisible(selection > 1)

    def __init__(self, parentApplet, topLevelOperatorView):
        """
        """
        self._initColors()

        self.topLevelOperatorView = topLevelOperatorView
        self.progressWindow = None
        super(TrackingBaseGui, self).__init__(parentApplet, topLevelOperatorView)
        self.mainOperator = topLevelOperatorView
        if self.mainOperator.LabelImage.meta.shape:
            self.editor.dataShape = self.mainOperator.LabelImage.meta.shape

        self.applet = self.mainOperator.parent.parent.trackingApplet
        self._drawer.mergerResolutionBox.setChecked(True)
        
        self.parentApplet = parentApplet
        self._headless = False

    def _loadUiFile(self):
        localDir = os.path.split(__file__)[0]
        self._drawer = uic.loadUi(localDir+"/drawer.ui")
        
        parameters = self.topLevelOperatorView.Parameters.value        
        if 'maxDist' in list(parameters.keys()):
            self._drawer.maxDistBox.setValue(parameters['maxDist'])
        if 'maxObj' in list(parameters.keys()):
            self._drawer.maxObjectsBox.setValue(parameters['maxObj'])
        if 'maxNearestNeighbors' in list(parameters.keys()):
            self._drawer.maxObjectsBox.setValue(parameters['maxNearestNeighbors'])
        if 'divThreshold' in list(parameters.keys()):
            self._drawer.divThreshBox.setValue(parameters['divThreshold'])
        if 'avgSize' in list(parameters.keys()):
            self._drawer.avgSizeBox.setValue(parameters['avgSize'][0])
        if 'withTracklets' in list(parameters.keys()):
            self._drawer.trackletsBox.setChecked(parameters['withTracklets'])
        if 'sizeDependent' in list(parameters.keys()):
            self._drawer.sizeDepBox.setChecked(parameters['sizeDependent'])
        if 'detWeight' in list(parameters.keys()):
            self._drawer.detWeightBox.setValue(parameters['detWeight'])
        if 'divWeight' in list(parameters.keys()):
            self._drawer.divWeightBox.setValue(parameters['divWeight'])
        if 'transWeight' in list(parameters.keys()):
            self._drawer.transWeightBox.setValue(parameters['transWeight'])
        if 'withDivisions' in list(parameters.keys()):
            self._drawer.divisionsBox.setChecked(parameters['withDivisions'])
        if 'withOpticalCorrection' in list(parameters.keys()):
            self._drawer.opticalBox.setChecked(parameters['withOpticalCorrection'])
        if 'withClassifierPrior' in list(parameters.keys()):
            self._drawer.classifierPriorBox.setChecked(parameters['withClassifierPrior'])
        if 'withMergerResolution' in list(parameters.keys()):
            self._drawer.mergerResolutionBox.setChecked(parameters['withMergerResolution'])
        if 'borderAwareWidth' in list(parameters.keys()):
            self._drawer.bordWidthBox.setValue(parameters['borderAwareWidth'])
        if 'cplex_timeout' in list(parameters.keys()):
            self._drawer.timeoutBox.setText(str(parameters['cplex_timeout']))
        if 'appearanceCost' in list(parameters.keys()):
            self._drawer.appearanceBox.setValue(parameters['appearanceCost'])
        if 'disappearanceCost' in list(parameters.keys()):
            self._drawer.disappearanceBox.setValue(parameters['disappearanceCost'])

        solverName = self.topLevelOperatorView._solver
        if solverName == "Flow-based":
            self._drawer.StructuredLearningButton.setEnabled(False)
            self._drawer.RandomButton.setEnabled(False)
            self._drawer.OnesButton.setEnabled(False)
            self._drawer.ZerosButton.setEnabled(False)

        return self._drawer

    def initAppletDrawerUi(self):
        self._maxNearestNeighbors = 1

        super(StructuredTrackingGui, self).initAppletDrawerUi()

        self.realOperator = self.topLevelOperatorView.Labels.getRealOperator()
        for i, op in enumerate(self.realOperator.innerOperators):
            self.operator = op

        self._allowedTimeoutInputRegEx = re.compile('^[0-9]*$')
        self._drawer.timeoutBox.textChanged.connect(self._onTimeoutBoxChanged)

        if not ilastik_config.getboolean("ilastik", "debug"):
            def checkboxAssertHandler(checkbox, assertEnabled=True):
                if checkbox.isChecked() == assertEnabled:
                    checkbox.hide()
                else:
                    checkbox.setEnabled(False)

            checkboxAssertHandler(self._drawer.trackletsBox, True)

            if self._drawer.classifierPriorBox.isChecked():
                self._drawer.hardPriorBox.hide()
                self._drawer.classifierPriorBox.hide()
                self._drawer.sizeDepBox.hide()
            else:
                self._drawer.hardPriorBox.setEnabled(False)
                self._drawer.classifierPriorBox.setEnabled(False)
                self._drawer.sizeDepBox.setEnabled(False)

            checkboxAssertHandler(self._drawer.opticalBox, False)
            checkboxAssertHandler(self._drawer.mergerResolutionBox, True)

            self._drawer.label_5.hide()
            self._drawer.divThreshBox.hide()
            self._drawer.label_25.hide()
            self._drawer.avgSizeBox.hide()

            self._drawer.InitialWeightsLabel.hide()
            self._drawer.ZerosButton.hide()
            self._drawer.OnesButton.hide()
            self._drawer.RandomButton.hide()

        self.mergerLabels = [
            self._drawer.merg1,
            self._drawer.merg2,
            self._drawer.merg3,
            self._drawer.merg4,
            self._drawer.merg5,
            self._drawer.merg6,
            self._drawer.merg7]

        for i in range(len(self.mergerLabels)):
            self._labelSetStyleSheet(self.mergerLabels[i], self.mergerColors[i+1])
        
        self._drawer.maxObjectsBox.valueChanged.connect(self._onMaxObjectsBoxChanged)
        self._drawer.mergerResolutionBox.stateChanged.connect(self._onMaxObjectsBoxChanged)

        self._drawer.StructuredLearningButton.clicked.connect(self._onRunStructuredLearningButtonPressed)

        self._drawer.divWeightBox.valueChanged.connect(self._onDivisionWeightBoxChanged)                
        self._drawer.detWeightBox.valueChanged.connect(self._onDetectionWeightBoxChanged)                
        self._drawer.transWeightBox.valueChanged.connect(self._onTransitionWeightBoxChanged)                
        self._drawer.appearanceBox.valueChanged.connect(self._onAppearanceWeightBoxChanged)                
        self._drawer.disappearanceBox.valueChanged.connect(self._onDisappearanceWeightBoxChanged)                
        self._drawer.maxNearestNeighborsSpinBox.valueChanged.connect(self._onMaxNearestNeighborsSpinBoxChanged)

        self._drawer.OnesButton.clicked.connect(self._onOnesButtonPressed)
        self._drawer.ZerosButton.clicked.connect(self._onZerosButtonPressed)
        self._drawer.RandomButton.clicked.connect(self._onRandomButtonPressed)

        self._divisionWeight = self.topLevelOperatorView.DivisionWeight.value
        self._detectionWeight = self.topLevelOperatorView.DetectionWeight.value
        self._transitionWeight = self.topLevelOperatorView.TransitionWeight.value
        self._appearanceWeight = self.topLevelOperatorView.AppearanceWeight.value
        self._disappearanceWeight = self.topLevelOperatorView.DisappearanceWeight.value

        self._drawer.detWeightBox.setValue(self._detectionWeight)
        self._drawer.divWeightBox.setValue(self._divisionWeight)
        self._drawer.transWeightBox.setValue(self._transitionWeight)
        self._drawer.appearanceBox.setValue(self._appearanceWeight)
        self._drawer.disappearanceBox.setValue(self._disappearanceWeight)

        self._maxNumObj = self.topLevelOperatorView.MaxNumObj.value
        self._drawer.maxObjectsBox.setValue(self.topLevelOperatorView.MaxNumObj.value)
        self._onMaxObjectsBoxChanged()
        self._drawer.maxObjectsBox.setReadOnly(False)

        self.topLevelOperatorView.Labels.notifyReady( bind(self._updateLabelsFromOperator) )
        self.topLevelOperatorView.Divisions.notifyReady( bind(self._updateDivisionsFromOperator) )
        self.topLevelOperatorView.Appearances.notifyReady( bind(self._updateAppearancesFromOperator) )
        self.topLevelOperatorView.Disappearances.notifyReady( bind(self._updateDisappearancesFromOperator) )

        self.operator.labels = self.operator.Labels.value
        self.operator.appearances = self.operator.Appearances.value
        self.operator.disappearances = self.operator.Disappearances.value

        self._drawer.exportButton.setVisible(False)
        self._drawer.exportTifButton.setVisible(False)

        self.topLevelOperatorView._detectionWeight = self._detectionWeight
        self.topLevelOperatorView._divisionWeight = self._divisionWeight
        self.topLevelOperatorView._transitionWeight = self._transitionWeight
        self.topLevelOperatorView._appearanceWeight = self._appearanceWeight
        self.topLevelOperatorView._disappearanceWeight = self._disappearanceWeight

        self._drawer.solverComboBox.clear()
        availableSolvers = self.getAvailableTrackingSolverTypes()
        self._drawer.solverComboBox.addItems(availableSolvers)
        parameters = self.topLevelOperatorView.Parameters.value
        if 'solver' in parameters.keys() and parameters['solver'] in availableSolvers:
            self._drawer.solverComboBox.setCurrentIndex(availableSolvers.index(parameters['solver']))

        # listen on the main operator's NumLabels slot for changes, and adjust the max value of the "maxNumObjects" box
        self.topLevelOperatorView.NumLabels.notifyDirty(self._updateMaxObjectsBoxMaxValue)
        self._updateMaxObjectsBoxMaxValue()

        return self._drawer

    @threadRouted
    def _updateMaxObjectsBoxMaxValue(self, *args, **kwargs):
        if self.topLevelOperatorView.NumLabels.ready():
            if self.topLevelOperatorView.NumLabels.value > 1:
                self._drawer.maxObjectsBox.setMaximum(self.topLevelOperatorView.NumLabels.value - 1)
                self._drawer.maxObjectsBox.setValue(self.topLevelOperatorView.NumLabels.value - 1)
                self._drawer.TrackButton.setEnabled(True)
            else:
                self._drawer.maxObjectsBox.setMaximum(0)
                self._drawer.maxObjectsBox.setValue(0)
                self._drawer.TrackButton.setEnabled(False)

    @staticmethod
    def getAvailableTrackingSolverTypes():
        solvers = []
        try:
            if dpct:
                solvers.append('Flow-based')
        except Exception as e:
            logger.info(str(e))

        try:
            if mht:
                solvers.append('ILP')
        except Exception as e:
            logger.info(str(e))

        return solvers

    def _onOnesButtonPressed(self):
        val = math.sqrt(old_div(1.0,5))
        self.topLevelOperatorView.DivisionWeight.setValue(val)
        self.topLevelOperatorView.DetectionWeight.setValue(val)
        self.topLevelOperatorView.TransitionWeight.setValue(val)
        self.topLevelOperatorView.AppearanceWeight.setValue(val)
        self.topLevelOperatorView.DisappearanceWeight.setValue(val)

        self._divisionWeight = self.topLevelOperatorView.DivisionWeight.value
        self._detectionWeight = self.topLevelOperatorView.DetectionWeight.value
        self._transitionWeight = self.topLevelOperatorView.TransitionWeight.value
        self._appearanceWeight = self.topLevelOperatorView.AppearanceWeight.value
        self._disappearanceWeight = self.topLevelOperatorView.DisappearanceWeight.value

        self._drawer.detWeightBox.setValue(self._detectionWeight)
        self._drawer.divWeightBox.setValue(self._divisionWeight)
        self._drawer.transWeightBox.setValue(self._transitionWeight)
        self._drawer.appearanceBox.setValue(self._appearanceWeight)
        self._drawer.disappearanceBox.setValue(self._disappearanceWeight)

    def _onRandomButtonPressed(self):
        weights = []
        for i in range(5):
            weights.append(random.random())
        sltWeightNorm = 0
        for i in range(5):
           sltWeightNorm += weights[i] * weights[i]
        sltWeightNorm = math.sqrt(sltWeightNorm)
        self.topLevelOperatorView.DivisionWeight.setValue(old_div(weights[0],sltWeightNorm))
        self.topLevelOperatorView.DetectionWeight.setValue(old_div(weights[1],sltWeightNorm))
        self.topLevelOperatorView.TransitionWeight.setValue(old_div(weights[2],sltWeightNorm))
        self.topLevelOperatorView.AppearanceWeight.setValue(old_div(weights[3],sltWeightNorm))
        self.topLevelOperatorView.DisappearanceWeight.setValue(old_div(weights[4],sltWeightNorm))

        self._divisionWeight = self.topLevelOperatorView.DivisionWeight.value
        self._detectionWeight = self.topLevelOperatorView.DetectionWeight.value
        self._transitionWeight = self.topLevelOperatorView.TransitionWeight.value
        self._appearanceWeight = self.topLevelOperatorView.AppearanceWeight.value
        self._disappearanceWeight = self.topLevelOperatorView.DisappearanceWeight.value

        self._drawer.detWeightBox.setValue(self._detectionWeight)
        self._drawer.divWeightBox.setValue(self._divisionWeight)
        self._drawer.transWeightBox.setValue(self._transitionWeight)
        self._drawer.appearanceBox.setValue(self._appearanceWeight)
        self._drawer.disappearanceBox.setValue(self._disappearanceWeight)

    def _onZerosButtonPressed(self):
        self.topLevelOperatorView.DivisionWeight.setValue(0)
        self.topLevelOperatorView.DetectionWeight.setValue(0)
        self.topLevelOperatorView.TransitionWeight.setValue(0)
        self.topLevelOperatorView.AppearanceWeight.setValue(0)
        self.topLevelOperatorView.DisappearanceWeight.setValue(0)

        self._divisionWeight = self.topLevelOperatorView.DivisionWeight.value
        self._detectionWeight = self.topLevelOperatorView.DetectionWeight.value
        self._transitionWeight = self.topLevelOperatorView.TransitionWeight.value
        self._appearanceWeight = self.topLevelOperatorView.AppearanceWeight.value
        self._disappearanceWeight = self.topLevelOperatorView.DisappearanceWeight.value

        self._drawer.detWeightBox.setValue(self._detectionWeight)
        self._drawer.divWeightBox.setValue(self._divisionWeight)
        self._drawer.transWeightBox.setValue(self._transitionWeight)
        self._drawer.appearanceBox.setValue(self._appearanceWeight)
        self._drawer.disappearanceBox.setValue(self._disappearanceWeight)

    @threadRouted
    def _onTimeoutBoxChanged(self, *args):
        inString = str(self._drawer.timeoutBox.text())
        if self._allowedTimeoutInputRegEx.match(inString) is None:
            self._drawer.timeoutBox.setText(inString[:-1])

    def _onMaxNumObjChanged(self):
        self._maxNumObj = self.topLevelOperatorView.MaxNumObj.value
        self._setMergerLegend(self.mergerLabels, self._maxNumObj)
        self._drawer.maxObjectsBox.setValue(self._maxNumObj)

    @threadRouted
    def _onDivisionWeightBoxChanged(self, *args):
        self._divisionWeight = self._drawer.divWeightBox.value()
        self.topLevelOperatorView.DivisionWeight.setValue(self._divisionWeight)

    @threadRouted
    def _onDetectionWeightBoxChanged(self, *args):
        self._detectionWeight = self._drawer.detWeightBox.value()
        self.topLevelOperatorView.DetectionWeight.setValue(self._detectionWeight)

    @threadRouted
    def _onTransitionWeightBoxChanged(self, *args):
        self._transitionWeight = self._drawer.transWeightBox.value()
        self.topLevelOperatorView.TransitionWeight.setValue(self._transitionWeight)

    @threadRouted
    def _onAppearanceWeightBoxChanged(self, *args):
        self._appearanceWeight = self._drawer.appearanceBox.value()
        self.topLevelOperatorView.AppearanceWeight.setValue(self._appearanceWeight)

    @threadRouted
    def _onDisappearanceWeightBoxChanged(self, *args):
        self._disappearanceWeight = self._drawer.disappearanceBox.value()
        self.topLevelOperatorView.DisappearanceWeight.setValue(self._disappearanceWeight)

    @threadRouted
    def _onMaxNearestNeighborsSpinBoxChanged(self, *args):
        self._maxNearestNeighbors = self._drawer.maxNearestNeighborsSpinBox.value()

    def _setRanges(self, *args):
        super(StructuredTrackingGui, self)._setRanges()
        maxx = self.topLevelOperatorView.LabelImage.meta.shape[1] - 1
        maxy = self.topLevelOperatorView.LabelImage.meta.shape[2] - 1
        maxz = self.topLevelOperatorView.LabelImage.meta.shape[3] - 1
        
        maxBorder = min(maxx, maxy)
        if maxz != 0:
            maxBorder = min(maxBorder, maxz)
        self._drawer.bordWidthBox.setRange(0, old_div(maxBorder,2))
        
    def _onMaxObjectsBoxChanged(self):
        self._setMergerLegend(self.mergerLabels, self._drawer.maxObjectsBox.value())
        self._maxNumObj = self._drawer.maxObjectsBox.value()
        self.topLevelOperatorView.MaxNumObjOut.setValue(self._maxNumObj)

    @threadRouted
    def _updateLabelsFromOperator(self):
        self.operator.labels = self.topLevelOperatorView.Labels.wait()

    @threadRouted
    def _updateDivisionsFromOperator(self):
        self.operator.divisions = self.topLevelOperatorView.Divisions.wait()

    @threadRouted
    def _updateAppearancesFromOperator(self):
        self.operator.appearances = self.topLevelOperatorView.Appearances.wait()

    @threadRouted
    def _updateDisappearancesFromOperator(self):
        self.operator.disappearances = self.topLevelOperatorView.Disappearances.wait()

    def getLabel(self, time, track):
        for label in list(self.operator.labels[time].keys()):
            if self.operator.labels[time][label] == set([track]):
                return label
        return False

    def _onRunStructuredLearningButtonPressed(self, withBatchProcessing=False):

        if not self.mainOperator.ObjectFeatures.ready():
            self._criticalMessage("You have to compute object features first.")
            return

        numStages = 6
        # object features
        # detection probabilities
        # creating traxel store
        # generating probabilities
        # insert energies
        # structured learning
        if self._drawer.divisionsBox.isChecked():
            # division probabilities
            numStages +=1

        self.progressWindow = TrackProgressDialog(parent=self,numStages=numStages)
        self.progressWindow.run()
        self.progressWindow.show()
        self.progressVisitor = GuiProgressVisitor(progressWindow=self.progressWindow)
        
        def _learn():
            self.applet.busy = True
            self.applet.appletStateUpdateRequested()
            try:
                self.topLevelOperatorView._runStructuredLearning(
                    (self._drawer.from_z.value(),self._drawer.to_z.value()),
                    self._maxNumObj,
                    self._maxNearestNeighbors,
                    self._drawer.maxDistBox.value(),
                    self._drawer.divThreshBox.value(),
                    (self._drawer.x_scale.value(), self._drawer.y_scale.value(), self._drawer.z_scale.value()),
                    (self._drawer.from_size.value(), self._drawer.to_size.value()),
                    self._drawer.divisionsBox.isChecked(),
                    self._drawer.bordWidthBox.value(),
                    self._drawer.classifierPriorBox.isChecked(),
                    withBatchProcessing,
                    progressWindow=self.progressWindow,
                    progressVisitor=self.progressVisitor
                )
            except Exception:
                ex_type, ex, tb = sys.exc_info()
                traceback.print_tb(tb)
                self._criticalMessage("Exception(" + str(ex_type) + "): " + str(ex))
                return

        def _handle_finished(*args):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested()

        def _handle_failure( exc, exc_info ):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested()
            traceback.print_exception(*exc_info)
            sys.stderr.write("Exception raised during learning.  See traceback above.\n")

            if self.progressWindow is not None:
                self.progressWindow.onTrackDone()

        req = Request( _learn )
        req.notify_failed( _handle_failure )
        req.notify_finished( _handle_finished )
        req.submit()

    def _onTrackButtonPressed( self ):
        if not self.mainOperator.ObjectFeatures.ready():
            self._criticalMessage("You have to compute object features first.")            
            return

        withMergerResolution = self._drawer.mergerResolutionBox.isChecked()
        withTracklets = True

        numStages = 6
        # creating traxel store
        # generating probabilities
        # insert energies
        # convexify costs
        # solver
        # compute lineages
        if withMergerResolution:
            numStages += 1 # merger resolution
        if withTracklets:
            numStages += 3 # initializing tracklet graph, finding tracklets, contracting edges in tracklet graph

        self.progressWindow = TrackProgressDialog(parent=self,numStages=numStages)
        self.progressWindow.run()
        self.progressWindow.show()
        self.progressVisitor = GuiProgressVisitor(progressWindow=self.progressWindow)

        def _track():
            self.applet.busy = True
            self.applet.appletStateUpdateRequested()
            maxDist = self._drawer.maxDistBox.value()
            maxObj = self._drawer.maxObjectsBox.value()        
            divThreshold = self._drawer.divThreshBox.value()
            
            from_t = self._drawer.from_time.value()
            to_t = self._drawer.to_time.value()
            from_x = self._drawer.from_x.value()
            to_x = self._drawer.to_x.value()
            from_y = self._drawer.from_y.value()
            to_y = self._drawer.to_y.value()        
            from_z = self._drawer.from_z.value()
            to_z = self._drawer.to_z.value()        
            from_size = self._drawer.from_size.value()
            to_size = self._drawer.to_size.value()        
            
            self.time_range =  list(range(from_t, to_t + 1))
            avgSize = [self._drawer.avgSizeBox.value()]

            cplex_timeout = None
            if len(str(self._drawer.timeoutBox.text())):
                cplex_timeout = int(self._drawer.timeoutBox.text())

            withTracklets = True
            sizeDependent = self._drawer.sizeDepBox.isChecked()
            hardPrior = self._drawer.hardPriorBox.isChecked()
            classifierPrior = self._drawer.classifierPriorBox.isChecked()
            detWeight = self._drawer.detWeightBox.value()
            divWeight = self._drawer.divWeightBox.value()
            transWeight = self._drawer.transWeightBox.value()
            withDivisions = self._drawer.divisionsBox.isChecked()        
            withOpticalCorrection = self._drawer.opticalBox.isChecked()
            withMergerResolution = self._drawer.mergerResolutionBox.isChecked()
            borderAwareWidth = self._drawer.bordWidthBox.value()
            withArmaCoordinates = True
            appearanceCost = self._drawer.appearanceBox.value()
            disappearanceCost = self._drawer.disappearanceBox.value()

            solverName = self._drawer.solverComboBox.currentText()

            ndim=3
            if (to_z - from_z == 0):
                ndim=2

            try:
                self.mainOperator.track(
                    time_range = self.time_range,
                    x_range = (from_x, to_x + 1),
                    y_range = (from_y, to_y + 1),
                    z_range = (from_z, to_z + 1),
                    size_range = (from_size, to_size + 1),
                    x_scale = self._drawer.x_scale.value(),
                    y_scale = self._drawer.y_scale.value(),
                    z_scale = self._drawer.z_scale.value(),
                    maxDist=maxDist,
                    maxObj = maxObj,
                    divThreshold=divThreshold,
                    avgSize=avgSize,
                    withTracklets=withTracklets,
                    sizeDependent=sizeDependent,
                    detWeight=detWeight,
                    divWeight=divWeight,
                    transWeight=transWeight,
                    withDivisions=withDivisions,
                    withOpticalCorrection=withOpticalCorrection,
                    withClassifierPrior=classifierPrior,
                    ndim=ndim,
                    withMergerResolution=withMergerResolution,
                    borderAwareWidth = borderAwareWidth,
                    withArmaCoordinates = withArmaCoordinates,
                    cplex_timeout = cplex_timeout,
                    appearance_cost = appearanceCost,
                    disappearance_cost = disappearanceCost,
                    #graph_building_parameter_changed = True,
                    #trainingToHardConstraints = self._drawer.trainingToHardConstraints.isChecked(),
                    max_nearest_neighbors = self._maxNearestNeighbors,
                    solverName=solverName,
                    progressWindow=self.progressWindow,
                    progressVisitor=self.progressVisitor
                )
            except Exception:
                self.progressWindow.onTrackDone()
                ex_type, ex, tb = sys.exc_info()
                traceback.print_tb(tb)
                self._criticalMessage("Exception(" + str(ex_type) + "): " + str(ex))
                return
        
        def _handle_finished(*args):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested()
            self._drawer.TrackButton.setEnabled(True)
            self._drawer.exportButton.setEnabled(True)
            self._drawer.exportTifButton.setEnabled(True)
            self._setLayerVisible("Objects", False) 
            
        def _handle_failure( exc, exc_info ):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested()
            traceback.print_exception(*exc_info)
            sys.stderr.write("Exception raised during tracking.  See traceback above.\n")
            self._drawer.TrackButton.setEnabled(True)

            if self.progressWindow is not None:
                self.progressWindow.onTrackDone()

        req = Request( _track )
        req.notify_failed( _handle_failure )
        req.notify_finished( _handle_finished )
        req.submit()

    def get_raw_shape(self):
        return self.topLevelOperatorView.RawImage.meta.shape

    def get_feature_names(self):
        params = self.topLevelOperatorView.Parameters
        if params.ready() and params.value["withDivisions"]:
            return self.topLevelOperatorView.ComputedFeatureNamesWithDivFeatures([]).wait()
        return self.topLevelOperatorView.ComputedFeatureNames([]).wait()

    def get_color(self, pos5d):
        slicing = tuple(slice(i, i+1) for i in pos5d)
        color = self.mainOperator.CachedOutput(slicing).wait()
        return color.flat[0]

    def get_object(self, pos5d):
        slicing = tuple(slice(i, i+1) for i in pos5d)
        label = self.mainOperator.RelabeledImage(slicing).wait()
        return label.flat[0], pos5d[0]

    @property
    def gui_applet(self):
        return self.applet

    def get_export_dialog_title(self):
        return "Export Tracking Information"

    # def handleEditorRightClick(self, position5d, win_coord):
    #     debug = ilastik_config.getboolean("ilastik", "debug")
    #
    #     obj, time = self.get_object(position5d)
    #     if obj == 0:
    #         menu = TitledMenu(["Background"])
    #         if debug:
    #             menu.addAction("Clear Hilite", IPCFacade().broadcast(Protocol.cmd("clear")))
    #         menu.exec_(win_coord)
    #         return
    #
    #     try:
    #         extra = self.mainOperator.extra_track_ids
    #     except (IndexError, KeyError):
    #         extra = {}
    #
    #     # if this is a resolved merger, find which of the merged IDs we actually clicked on
    #     if time in extra and obj in extra[time]:
    #         colors = [self.mainOperator.label2color[time][t] for t in extra[time][obj]]
    #         tracks = [self.mainOperator.track_id[time][t] for t in extra[time][obj]]
    #         selected_track = self.get_color(position5d)
    #         idx = colors.index(selected_track)
    #         color = colors[idx]
    #         track = tracks[idx]
    #     else:
    #         try:
    #             color = self.mainOperator.label2color[time][obj]
    #             track = [self.mainOperator.track_id[time][obj]][0]
    #         except (IndexError, KeyError):
    #             color = None
    #             track = []
    #
    #     if track:
    #         children, parents = self.mainOperator.track_family(track)
    #     else:
    #         children, parents = None, None
    #
    #     menu = TitledMenu([
    #         "Object {} of lineage id {}".format(obj, color),
    #         "Track id: " + (str(track) or "None"),
    #     ])
    #
    #     if not debug:
    #         menu.exec_(win_coord)
    #         return
    #
    #     if any(IPCFacade().sending):
    #
    #         obj_sub_menu = menu.addMenu("Hilite Object")
    #         for mode in Protocol.ValidHiliteModes:
    #             where = Protocol.simple("and", ilastik_id=obj, time=time)
    #             cmd = Protocol.cmd(mode, where)
    #             obj_sub_menu.addAction(mode.capitalize(), IPCFacade().broadcast(cmd))
    #
    #         sub_menus = [
    #             ("Tracks", Protocol.simple_in, tracks),
    #             ("Parents", Protocol.simple_in, parents),
    #             ("Children", Protocol.simple_in, children)
    #         ]
    #         for name, protocol, args in sub_menus:
    #             if args:
    #                 sub = menu.addMenu("Hilite {}".format(name))
    #                 for mode in Protocol.ValidHiliteModes[:-1]:
    #                     mode = mode.capitalize()
    #                     where = protocol("track_id*", args)
    #                     cmd = Protocol.cmd(mode, where)
    #                     sub.addAction(mode, IPCFacade().broadcast(cmd))
    #             else:
    #                 sub = menu.addAction("Hilite {}".format(name))
    #                 sub.setEnabled(False)
    #
    #         menu.addAction("Clear Hilite", IPCFacade().broadcast(Protocol.cmd("clear")))
    #     else:
    #         menu.addAction("Open IPC Server Window", IPCFacade().show_info)
    #         menu.addAction("Start IPC Server", IPCFacade().start)
    #
    #     menu.exec_(win_coord)

    def handleEditorRightClick(self, position5d, win_coord):
        debug = ilastik_config.getboolean("ilastik", "debug")

        obj, time = self.get_object(position5d)
        if obj == 0:
            menu = TitledMenu(["Background"])
            if debug:
                menu.addAction("Clear Hilite", IPCFacade().broadcast(Protocol.cmd("clear")))
            menu.exec_(win_coord)
            return

        hypothesesGraph = self.mainOperator.HypothesesGraph.value

        if hypothesesGraph == None:
            color = None
            track = None
        else:
            color = hypothesesGraph.getLineageId(time, obj)
            track = hypothesesGraph.getTrackId(time, obj)

        tracks = None
        children = None
        parents = None

        menu = TitledMenu([
            "Object {} of lineage id {}".format(obj, color),
            "Track id: " + (str(track) or "None"),
        ])

        if not debug:
            menu.exec_(win_coord)
            return

        if any(IPCFacade().sending):

            obj_sub_menu = menu.addMenu("Hilite Object")
            for mode in Protocol.ValidHiliteModes:
                where = Protocol.simple("and", ilastik_id=obj, time=time)
                cmd = Protocol.cmd(mode, where)
                obj_sub_menu.addAction(mode.capitalize(), IPCFacade().broadcast(cmd))

            sub_menus = [
                ("Tracks", Protocol.simple_in, tracks),
                ("Parents", Protocol.simple_in, parents),
                ("Children", Protocol.simple_in, children)
            ]
            for name, protocol, args in sub_menus:
                if args:
                    sub = menu.addMenu("Hilite {}".format(name))
                    for mode in Protocol.ValidHiliteModes[:-1]:
                        mode = mode.capitalize()
                        where = protocol("track_id*", args)
                        cmd = Protocol.cmd(mode, where)
                        sub.addAction(mode, IPCFacade().broadcast(cmd))
                else:
                    sub = menu.addAction("Hilite {}".format(name))
                    sub.setEnabled(False)

            menu.addAction("Clear Hilite", IPCFacade().broadcast(Protocol.cmd("clear")))
        else:
            menu.addAction("Open IPC Server Window", IPCFacade().show_info)
            menu.addAction("Start IPC Server", IPCFacade().start)

        menu.exec_(win_coord)

    @threadRouted
    def _informationMessage(self, prompt):
        #
        # This function used to be pass-throughs to a signal,
        # but I don't see why that's necessary.
        # (It is always called from the main thread.)
        # So now we just call the target function directly.
        #
        self.postInformationMessage(prompt)

    @threadRouted
    def postInformationMessage(self, prompt):
        QtWidgets.QMessageBox.information(self, "Info:", prompt, QtWidgets.QMessageBox.Ok)
class StructuredTrackingGui(TrackingBaseGui, ExportingGui):

    withMergers = True

    @threadRouted
    def _setMergerLegend(self, labels, selection):
        param = self.topLevelOperatorView.Parameters.value
        if 'withMergerResolution' in param.keys():
            if param['withMergerResolution']:
                selection = 1
        elif self._drawer.mergerResolutionBox.isChecked():
            selection = 1

        for i in range(2, len(labels) + 1):
            if i <= selection:
                labels[i - 1].setVisible(True)
            else:
                labels[i - 1].setVisible(False)

        # hide merger legend if selection < 2
        self._drawer.label_4.setVisible(selection > 1)
        labels[0].setVisible(selection > 1)

    def __init__(self, parentApplet, topLevelOperatorView):
        """
        """
        self._initColors()

        self.topLevelOperatorView = topLevelOperatorView
        self.progressWindow = None
        super(TrackingBaseGui, self).__init__(parentApplet,
                                              topLevelOperatorView)
        self.mainOperator = topLevelOperatorView
        if self.mainOperator.LabelImage.meta.shape:
            self.editor.dataShape = self.mainOperator.LabelImage.meta.shape

        self.applet = self.mainOperator.parent.parent.trackingApplet
        self._drawer.mergerResolutionBox.setChecked(True)
        self.connect(self, QtCore.SIGNAL('postInformationMessage(QString)'),
                     self.postInformationMessage)

        self.parentApplet = parentApplet
        self._headless = False

    def _loadUiFile(self):
        localDir = os.path.split(__file__)[0]
        self._drawer = uic.loadUi(localDir + "/drawer.ui")

        parameters = self.topLevelOperatorView.Parameters.value
        if 'maxDist' in parameters.keys():
            self._drawer.maxDistBox.setValue(parameters['maxDist'])
        if 'maxObj' in parameters.keys():
            self._drawer.maxObjectsBox.setValue(parameters['maxObj'])
        if 'maxNearestNeighbors' in parameters.keys():
            self._drawer.maxObjectsBox.setValue(
                parameters['maxNearestNeighbors'])
        if 'divThreshold' in parameters.keys():
            self._drawer.divThreshBox.setValue(parameters['divThreshold'])
        if 'avgSize' in parameters.keys():
            self._drawer.avgSizeBox.setValue(parameters['avgSize'][0])
        if 'withTracklets' in parameters.keys():
            self._drawer.trackletsBox.setChecked(parameters['withTracklets'])
        if 'sizeDependent' in parameters.keys():
            self._drawer.sizeDepBox.setChecked(parameters['sizeDependent'])
        if 'detWeight' in parameters.keys():
            self._drawer.detWeightBox.setValue(parameters['detWeight'])
        if 'divWeight' in parameters.keys():
            self._drawer.divWeightBox.setValue(parameters['divWeight'])
        if 'transWeight' in parameters.keys():
            self._drawer.transWeightBox.setValue(parameters['transWeight'])
        if 'withDivisions' in parameters.keys():
            self._drawer.divisionsBox.setChecked(parameters['withDivisions'])
        if 'withOpticalCorrection' in parameters.keys():
            self._drawer.opticalBox.setChecked(
                parameters['withOpticalCorrection'])
        if 'withClassifierPrior' in parameters.keys():
            self._drawer.classifierPriorBox.setChecked(
                parameters['withClassifierPrior'])
        if 'withMergerResolution' in parameters.keys():
            self._drawer.mergerResolutionBox.setChecked(
                parameters['withMergerResolution'])
        if 'borderAwareWidth' in parameters.keys():
            self._drawer.bordWidthBox.setValue(parameters['borderAwareWidth'])
        if 'cplex_timeout' in parameters.keys():
            self._drawer.timeoutBox.setText(str(parameters['cplex_timeout']))
        if 'appearanceCost' in parameters.keys():
            self._drawer.appearanceBox.setValue(parameters['appearanceCost'])
        if 'disappearanceCost' in parameters.keys():
            self._drawer.disappearanceBox.setValue(
                parameters['disappearanceCost'])

        solverName = self.topLevelOperatorView._solver
        if solverName == "Flow-based":
            self._drawer.StructuredLearningButton.setEnabled(False)
            self._drawer.RandomButton.setEnabled(False)
            self._drawer.OnesButton.setEnabled(False)
            self._drawer.ZerosButton.setEnabled(False)

        return self._drawer

    def initAppletDrawerUi(self):
        self._previousCrop = -1
        self._currentCrop = -1
        self._currentCropName = ""
        self._maxNearestNeighbors = 1

        super(StructuredTrackingGui, self).initAppletDrawerUi()

        self.realOperator = self.topLevelOperatorView.Labels.getRealOperator()
        for i, op in enumerate(self.realOperator.innerOperators):
            self.operator = op

        self._allowedTimeoutInputRegEx = re.compile('^[0-9]*$')
        self._drawer.timeoutBox.textChanged.connect(self._onTimeoutBoxChanged)

        if not ilastik_config.getboolean("ilastik", "debug"):

            def checkboxAssertHandler(checkbox, assertEnabled=True):
                if checkbox.isChecked() == assertEnabled:
                    checkbox.hide()
                else:
                    checkbox.setEnabled(False)

            checkboxAssertHandler(self._drawer.trackletsBox, True)

            if self._drawer.classifierPriorBox.isChecked():
                self._drawer.hardPriorBox.hide()
                self._drawer.classifierPriorBox.hide()
                self._drawer.sizeDepBox.hide()
            else:
                self._drawer.hardPriorBox.setEnabled(False)
                self._drawer.classifierPriorBox.setEnabled(False)
                self._drawer.sizeDepBox.setEnabled(False)

            checkboxAssertHandler(self._drawer.opticalBox, False)
            checkboxAssertHandler(self._drawer.mergerResolutionBox, True)

            self._drawer.label_5.hide()
            self._drawer.divThreshBox.hide()
            self._drawer.label_25.hide()
            self._drawer.avgSizeBox.hide()

            self._drawer.InitialWeightsLabel.hide()
            self._drawer.ZerosButton.hide()
            self._drawer.OnesButton.hide()
            self._drawer.RandomButton.hide()

        self.mergerLabels = [
            self._drawer.merg1, self._drawer.merg2, self._drawer.merg3,
            self._drawer.merg4, self._drawer.merg5, self._drawer.merg6,
            self._drawer.merg7
        ]

        for i in range(len(self.mergerLabels)):
            self._labelSetStyleSheet(self.mergerLabels[i],
                                     self.mergerColors[i + 1])

        self._drawer.maxObjectsBox.valueChanged.connect(
            self._onMaxObjectsBoxChanged)
        self._drawer.mergerResolutionBox.stateChanged.connect(
            self._onMaxObjectsBoxChanged)

        self._drawer.StructuredLearningButton.clicked.connect(
            self._onRunStructuredLearningButtonPressed)

        self._drawer.divWeightBox.valueChanged.connect(
            self._onDivisionWeightBoxChanged)
        self._drawer.detWeightBox.valueChanged.connect(
            self._onDetectionWeightBoxChanged)
        self._drawer.transWeightBox.valueChanged.connect(
            self._onTransitionWeightBoxChanged)
        self._drawer.appearanceBox.valueChanged.connect(
            self._onAppearanceWeightBoxChanged)
        self._drawer.disappearanceBox.valueChanged.connect(
            self._onDisappearanceWeightBoxChanged)
        self._drawer.maxNearestNeighborsSpinBox.valueChanged.connect(
            self._onMaxNearestNeighborsSpinBoxChanged)

        self._drawer.OnesButton.clicked.connect(self._onOnesButtonPressed)
        self._drawer.ZerosButton.clicked.connect(self._onZerosButtonPressed)
        self._drawer.RandomButton.clicked.connect(self._onRandomButtonPressed)

        self._divisionWeight = self.topLevelOperatorView.DivisionWeight.value
        self._detectionWeight = self.topLevelOperatorView.DetectionWeight.value
        self._transitionWeight = self.topLevelOperatorView.TransitionWeight.value
        self._appearanceWeight = self.topLevelOperatorView.AppearanceWeight.value
        self._disappearanceWeight = self.topLevelOperatorView.DisappearanceWeight.value

        self._drawer.detWeightBox.setValue(self._detectionWeight)
        self._drawer.divWeightBox.setValue(self._divisionWeight)
        self._drawer.transWeightBox.setValue(self._transitionWeight)
        self._drawer.appearanceBox.setValue(self._appearanceWeight)
        self._drawer.disappearanceBox.setValue(self._disappearanceWeight)

        self._maxNumObj = self.topLevelOperatorView.MaxNumObj.value
        self._drawer.maxObjectsBox.setValue(
            self.topLevelOperatorView.MaxNumObj.value)
        self._onMaxObjectsBoxChanged()
        self._drawer.maxObjectsBox.setReadOnly(True)

        self.topLevelOperatorView.Labels.notifyReady(
            bind(self._updateLabelsFromOperator))
        self.topLevelOperatorView.Divisions.notifyReady(
            bind(self._updateDivisionsFromOperator))

        self.operator.labels = self.operator.Labels.value
        self.topLevelOperatorView._updateCropsFromOperator()

        self._drawer.exportButton.setVisible(True)
        self._drawer.exportTifButton.setVisible(False)

        self.topLevelOperatorView._detectionWeight = self._detectionWeight
        self.topLevelOperatorView._divisionWeight = self._divisionWeight
        self.topLevelOperatorView._transitionWeight = self._transitionWeight
        self.topLevelOperatorView._appearanceWeight = self._appearanceWeight
        self.topLevelOperatorView._disappearanceWeight = self._disappearanceWeight

        self._drawer.solverComboBox.clear()
        availableSolvers = self.getAvailableTrackingSolverTypes()
        self._drawer.solverComboBox.addItems(availableSolvers)
        parameters = self.topLevelOperatorView.Parameters.value
        if 'solver' in parameters.keys(
        ) and parameters['solver'] in availableSolvers:
            self._drawer.solverComboBox.setCurrentIndex(
                availableSolvers.index(parameters['solver']))

        return self._drawer

    @staticmethod
    def getAvailableTrackingSolverTypes():
        solvers = []
        if WITH_HYTRA:
            try:
                if dpct:
                    solvers.append('Flow-based')
            except Exception as e:
                logger.info(str(e))

            try:
                if mht:
                    solvers.append('ILP')
            except Exception as e:
                logger.info(str(e))

        else:
            if hasattr(pgmlink.ConsTrackingSolverType, "CplexSolver"):
                solvers.append("ILP")

            if hasattr(pgmlink.ConsTrackingSolverType, "DynProgSolver"):
                solvers.append("Magnusson")

            if hasattr(pgmlink.ConsTrackingSolverType, "FlowSolver"):
                solvers.append("Flow-based")
        return solvers

    def _onOnesButtonPressed(self):
        val = math.sqrt(1.0 / 5)
        self.topLevelOperatorView.DivisionWeight.setValue(val)
        self.topLevelOperatorView.DetectionWeight.setValue(val)
        self.topLevelOperatorView.TransitionWeight.setValue(val)
        self.topLevelOperatorView.AppearanceWeight.setValue(val)
        self.topLevelOperatorView.DisappearanceWeight.setValue(val)

        self._divisionWeight = self.topLevelOperatorView.DivisionWeight.value
        self._detectionWeight = self.topLevelOperatorView.DetectionWeight.value
        self._transitionWeight = self.topLevelOperatorView.TransitionWeight.value
        self._appearanceWeight = self.topLevelOperatorView.AppearanceWeight.value
        self._disappearanceWeight = self.topLevelOperatorView.DisappearanceWeight.value

        self._drawer.detWeightBox.setValue(self._detectionWeight)
        self._drawer.divWeightBox.setValue(self._divisionWeight)
        self._drawer.transWeightBox.setValue(self._transitionWeight)
        self._drawer.appearanceBox.setValue(self._appearanceWeight)
        self._drawer.disappearanceBox.setValue(self._disappearanceWeight)

    def _onRandomButtonPressed(self):
        weights = []
        for i in range(5):
            weights.append(random.random())
        sltWeightNorm = 0
        for i in range(5):
            sltWeightNorm += weights[i] * weights[i]
        sltWeightNorm = math.sqrt(sltWeightNorm)
        self.topLevelOperatorView.DivisionWeight.setValue(weights[0] /
                                                          sltWeightNorm)
        self.topLevelOperatorView.DetectionWeight.setValue(weights[1] /
                                                           sltWeightNorm)
        self.topLevelOperatorView.TransitionWeight.setValue(weights[2] /
                                                            sltWeightNorm)
        self.topLevelOperatorView.AppearanceWeight.setValue(weights[3] /
                                                            sltWeightNorm)
        self.topLevelOperatorView.DisappearanceWeight.setValue(weights[4] /
                                                               sltWeightNorm)

        self._divisionWeight = self.topLevelOperatorView.DivisionWeight.value
        self._detectionWeight = self.topLevelOperatorView.DetectionWeight.value
        self._transitionWeight = self.topLevelOperatorView.TransitionWeight.value
        self._appearanceWeight = self.topLevelOperatorView.AppearanceWeight.value
        self._disappearanceWeight = self.topLevelOperatorView.DisappearanceWeight.value

        self._drawer.detWeightBox.setValue(self._detectionWeight)
        self._drawer.divWeightBox.setValue(self._divisionWeight)
        self._drawer.transWeightBox.setValue(self._transitionWeight)
        self._drawer.appearanceBox.setValue(self._appearanceWeight)
        self._drawer.disappearanceBox.setValue(self._disappearanceWeight)

    def _onZerosButtonPressed(self):
        self.topLevelOperatorView.DivisionWeight.setValue(0)
        self.topLevelOperatorView.DetectionWeight.setValue(0)
        self.topLevelOperatorView.TransitionWeight.setValue(0)
        self.topLevelOperatorView.AppearanceWeight.setValue(0)
        self.topLevelOperatorView.DisappearanceWeight.setValue(0)

        self._divisionWeight = self.topLevelOperatorView.DivisionWeight.value
        self._detectionWeight = self.topLevelOperatorView.DetectionWeight.value
        self._transitionWeight = self.topLevelOperatorView.TransitionWeight.value
        self._appearanceWeight = self.topLevelOperatorView.AppearanceWeight.value
        self._disappearanceWeight = self.topLevelOperatorView.DisappearanceWeight.value

        self._drawer.detWeightBox.setValue(self._detectionWeight)
        self._drawer.divWeightBox.setValue(self._divisionWeight)
        self._drawer.transWeightBox.setValue(self._transitionWeight)
        self._drawer.appearanceBox.setValue(self._appearanceWeight)
        self._drawer.disappearanceBox.setValue(self._disappearanceWeight)

    @threadRouted
    def _onTimeoutBoxChanged(self, *args):
        inString = str(self._drawer.timeoutBox.text())
        if self._allowedTimeoutInputRegEx.match(inString) is None:
            self._drawer.timeoutBox.setText(
                inString.decode("utf8").encode("ascii", "replace")[:-1])

    def _onMaxNumObjChanged(self):
        self._maxNumObj = self.topLevelOperatorView.MaxNumObj.value
        self._setMergerLegend(self.mergerLabels, self._maxNumObj)
        self._drawer.maxObjectsBox.setValue(self._maxNumObj)

    @threadRouted
    def _onDivisionWeightBoxChanged(self, *args):
        self._divisionWeight = self._drawer.divWeightBox.value()
        self.topLevelOperatorView.DivisionWeight.setValue(self._divisionWeight)

    @threadRouted
    def _onDetectionWeightBoxChanged(self, *args):
        self._detectionWeight = self._drawer.detWeightBox.value()
        self.topLevelOperatorView.DetectionWeight.setValue(
            self._detectionWeight)

    @threadRouted
    def _onTransitionWeightBoxChanged(self, *args):
        self._transitionWeight = self._drawer.transWeightBox.value()
        self.topLevelOperatorView.TransitionWeight.setValue(
            self._transitionWeight)

    @threadRouted
    def _onAppearanceWeightBoxChanged(self, *args):
        self._appearanceWeight = self._drawer.appearanceBox.value()
        self.topLevelOperatorView.AppearanceWeight.setValue(
            self._appearanceWeight)

    @threadRouted
    def _onDisappearanceWeightBoxChanged(self, *args):
        self._disappearanceWeight = self._drawer.disappearanceBox.value()
        self.topLevelOperatorView.DisappearanceWeight.setValue(
            self._disappearanceWeight)

    @threadRouted
    def _onMaxNearestNeighborsSpinBoxChanged(self, *args):
        self._maxNearestNeighbors = self._drawer.maxNearestNeighborsSpinBox.value(
        )

    def _setRanges(self, *args):
        super(StructuredTrackingGui, self)._setRanges()
        maxx = self.topLevelOperatorView.LabelImage.meta.shape[1] - 1
        maxy = self.topLevelOperatorView.LabelImage.meta.shape[2] - 1
        maxz = self.topLevelOperatorView.LabelImage.meta.shape[3] - 1

        maxBorder = min(maxx, maxy)
        if maxz != 0:
            maxBorder = min(maxBorder, maxz)
        self._drawer.bordWidthBox.setRange(0, maxBorder / 2)

    def _onMaxObjectsBoxChanged(self):
        self._setMergerLegend(self.mergerLabels,
                              self._drawer.maxObjectsBox.value())
        self._maxNumObj = self._drawer.maxObjectsBox.value()
        self.topLevelOperatorView.MaxNumObjOut.setValue(self._maxNumObj)

    @threadRouted
    def _updateLabelsFromOperator(self):
        self.operator.labels = self.topLevelOperatorView.Labels.wait()

    @threadRouted
    def _updateDivisionsFromOperator(self):
        self.operator.divisions = self.topLevelOperatorView.Divisions.wait()

    def getLabel(self, time, track):
        for label in self.operator.labels[time].keys():
            if self.operator.labels[time][label] == set([track]):
                return label
        return False

    def _onRunStructuredLearningButtonPressed(self, withBatchProcessing=False):

        numStages = 4
        # creating traxel store
        # generating probabilities
        # insert energies
        # structured learning

        if WITH_HYTRA:
            self.progressWindow = TrackProgressDialog(parent=self,
                                                      numStages=numStages)
            self.progressWindow.run()
            self.progressWindow.show()
            self.progressVisitor = GuiProgressVisitor(
                progressWindow=self.progressWindow)
        else:
            self.progressWindow = None
            self.progressVisitor = DefaultProgressVisitor()

        def _learn():
            self.applet.busy = True
            self.applet.appletStateUpdateRequested.emit()
            try:
                self.topLevelOperatorView._runStructuredLearning(
                    (self._drawer.from_z.value(), self._drawer.to_z.value()),
                    self._maxNumObj,
                    self._maxNearestNeighbors,
                    self._drawer.maxDistBox.value(),
                    self._drawer.divThreshBox.value(),
                    (self._drawer.x_scale.value(),
                     self._drawer.y_scale.value(),
                     self._drawer.z_scale.value()),
                    (self._drawer.from_size.value(),
                     self._drawer.to_size.value()),
                    self._drawer.divisionsBox.isChecked(),
                    self._drawer.bordWidthBox.value(),
                    self._drawer.classifierPriorBox.isChecked(),
                    withBatchProcessing,
                    progressWindow=self.progressWindow,
                    progressVisitor=self.progressVisitor)
            except Exception:
                ex_type, ex, tb = sys.exc_info()
                traceback.print_tb(tb)
                self._criticalMessage("Exception(" + str(ex_type) + "): " +
                                      str(ex))
                return

        def _handle_finished(*args):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested.emit()

        def _handle_failure(exc, exc_info):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested.emit()
            traceback.print_exception(*exc_info)
            sys.stderr.write(
                "Exception raised during learning.  See traceback above.\n")

            if self.progressWindow is not None:
                self.progressWindow.onTrackDone()

        req = Request(_learn)
        req.notify_failed(_handle_failure)
        req.notify_finished(_handle_finished)
        req.submit()

    def _onTrackButtonPressed(self):
        if not self.mainOperator.ObjectFeatures.ready():
            self._criticalMessage("You have to compute object features first.")
            return

        withMergerResolution = self._drawer.mergerResolutionBox.isChecked()
        withTracklets = True

        numStages = 6
        # creating traxel store
        # generating probabilities
        # insert energies
        # convexify costs
        # solver
        # compute lineages
        if withMergerResolution:
            numStages += 1  # merger resolution
        if withTracklets:
            numStages += 3  # initializing tracklet graph, finding tracklets, contracting edges in tracklet graph

        if WITH_HYTRA:
            self.progressWindow = TrackProgressDialog(parent=self,
                                                      numStages=numStages)
            self.progressWindow.run()
            self.progressWindow.show()
            self.progressVisitor = GuiProgressVisitor(
                progressWindow=self.progressWindow)
        else:
            self.progressWindow = None
            self.progressVisitor = DefaultProgressVisitor()

        def _track():
            self.applet.busy = True
            self.applet.appletStateUpdateRequested.emit()
            maxDist = self._drawer.maxDistBox.value()
            maxObj = self._drawer.maxObjectsBox.value()
            divThreshold = self._drawer.divThreshBox.value()

            from_t = self._drawer.from_time.value()
            to_t = self._drawer.to_time.value()
            from_x = self._drawer.from_x.value()
            to_x = self._drawer.to_x.value()
            from_y = self._drawer.from_y.value()
            to_y = self._drawer.to_y.value()
            from_z = self._drawer.from_z.value()
            to_z = self._drawer.to_z.value()
            from_size = self._drawer.from_size.value()
            to_size = self._drawer.to_size.value()

            self.time_range = range(from_t, to_t + 1)
            avgSize = [self._drawer.avgSizeBox.value()]

            cplex_timeout = None
            if len(str(self._drawer.timeoutBox.text())):
                cplex_timeout = int(self._drawer.timeoutBox.text())

            withTracklets = True
            sizeDependent = self._drawer.sizeDepBox.isChecked()
            hardPrior = self._drawer.hardPriorBox.isChecked()
            classifierPrior = self._drawer.classifierPriorBox.isChecked()
            detWeight = self._drawer.detWeightBox.value()
            divWeight = self._drawer.divWeightBox.value()
            transWeight = self._drawer.transWeightBox.value()
            withDivisions = self._drawer.divisionsBox.isChecked()
            withOpticalCorrection = self._drawer.opticalBox.isChecked()
            withMergerResolution = self._drawer.mergerResolutionBox.isChecked()
            borderAwareWidth = self._drawer.bordWidthBox.value()
            withArmaCoordinates = True
            appearanceCost = self._drawer.appearanceBox.value()
            disappearanceCost = self._drawer.disappearanceBox.value()

            solverName = self._drawer.solverComboBox.currentText()

            ndim = 3
            if (to_z - from_z == 0):
                ndim = 2

            try:
                self.mainOperator.track(
                    time_range=self.time_range,
                    x_range=(from_x, to_x + 1),
                    y_range=(from_y, to_y + 1),
                    z_range=(from_z, to_z + 1),
                    size_range=(from_size, to_size + 1),
                    x_scale=self._drawer.x_scale.value(),
                    y_scale=self._drawer.y_scale.value(),
                    z_scale=self._drawer.z_scale.value(),
                    maxDist=maxDist,
                    maxObj=maxObj,
                    divThreshold=divThreshold,
                    avgSize=avgSize,
                    withTracklets=withTracklets,
                    sizeDependent=sizeDependent,
                    detWeight=detWeight,
                    divWeight=divWeight,
                    transWeight=transWeight,
                    withDivisions=withDivisions,
                    withOpticalCorrection=withOpticalCorrection,
                    withClassifierPrior=classifierPrior,
                    ndim=ndim,
                    withMergerResolution=withMergerResolution,
                    borderAwareWidth=borderAwareWidth,
                    withArmaCoordinates=withArmaCoordinates,
                    cplex_timeout=cplex_timeout,
                    appearance_cost=appearanceCost,
                    disappearance_cost=disappearanceCost,
                    #graph_building_parameter_changed = True,
                    #trainingToHardConstraints = self._drawer.trainingToHardConstraints.isChecked(),
                    max_nearest_neighbors=self._maxNearestNeighbors,
                    solverName=solverName,
                    progressWindow=self.progressWindow,
                    progressVisitor=self.progressVisitor)
            except Exception:
                ex_type, ex, tb = sys.exc_info()
                traceback.print_tb(tb)
                self._criticalMessage("Exception(" + str(ex_type) + "): " +
                                      str(ex))
                return

        def _handle_finished(*args):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested.emit()
            self._drawer.TrackButton.setEnabled(True)
            self._drawer.exportButton.setEnabled(True)
            self._drawer.exportTifButton.setEnabled(True)
            self._setLayerVisible("Objects", False)

        def _handle_failure(exc, exc_info):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested.emit()
            traceback.print_exception(*exc_info)
            sys.stderr.write(
                "Exception raised during tracking.  See traceback above.\n")
            self._drawer.TrackButton.setEnabled(True)

            if self.progressWindow is not None:
                self.progressWindow.onTrackDone()

        req = Request(_track)
        req.notify_failed(_handle_failure)
        req.notify_finished(_handle_finished)
        req.submit()

    def menus(self):
        m = QtGui.QMenu("&Export", self.volumeEditorWidget)
        m.addAction("Export Tracking Information").triggered.connect(
            self.show_export_dialog)

        return [m]

    def get_raw_shape(self):
        return self.topLevelOperatorView.RawImage.meta.shape

    def get_feature_names(self):
        params = self.topLevelOperatorView.Parameters
        if params.ready() and params.value["withDivisions"]:
            return self.topLevelOperatorView.ComputedFeatureNamesWithDivFeatures(
                []).wait()
        return self.topLevelOperatorView.ComputedFeatureNames([]).wait()

    def get_color(self, pos5d):
        slicing = tuple(slice(i, i + 1) for i in pos5d)
        color = self.mainOperator.CachedOutput(slicing).wait()
        return color.flat[0]

    def get_object(self, pos5d):
        slicing = tuple(slice(i, i + 1) for i in pos5d)
        label = self.mainOperator.RelabeledImage(slicing).wait()
        return label.flat[0], pos5d[0]

    @property
    def gui_applet(self):
        return self.applet

    def get_export_dialog_title(self):
        return "Export Tracking Information"

    # def handleEditorRightClick(self, position5d, win_coord):
    #     debug = ilastik_config.getboolean("ilastik", "debug")
    #
    #     obj, time = self.get_object(position5d)
    #     if obj == 0:
    #         menu = TitledMenu(["Background"])
    #         if debug:
    #             menu.addAction("Clear Hilite", IPCFacade().broadcast(Protocol.cmd("clear")))
    #         menu.exec_(win_coord)
    #         return
    #
    #     try:
    #         extra = self.mainOperator.extra_track_ids
    #     except (IndexError, KeyError):
    #         extra = {}
    #
    #     # if this is a resolved merger, find which of the merged IDs we actually clicked on
    #     if time in extra and obj in extra[time]:
    #         colors = [self.mainOperator.label2color[time][t] for t in extra[time][obj]]
    #         tracks = [self.mainOperator.track_id[time][t] for t in extra[time][obj]]
    #         selected_track = self.get_color(position5d)
    #         idx = colors.index(selected_track)
    #         color = colors[idx]
    #         track = tracks[idx]
    #     else:
    #         try:
    #             color = self.mainOperator.label2color[time][obj]
    #             track = [self.mainOperator.track_id[time][obj]][0]
    #         except (IndexError, KeyError):
    #             color = None
    #             track = []
    #
    #     if track:
    #         children, parents = self.mainOperator.track_family(track)
    #     else:
    #         children, parents = None, None
    #
    #     menu = TitledMenu([
    #         "Object {} of lineage id {}".format(obj, color),
    #         "Track id: " + (str(track) or "None"),
    #     ])
    #
    #     if not debug:
    #         menu.exec_(win_coord)
    #         return
    #
    #     if any(IPCFacade().sending):
    #
    #         obj_sub_menu = menu.addMenu("Hilite Object")
    #         for mode in Protocol.ValidHiliteModes:
    #             where = Protocol.simple("and", ilastik_id=obj, time=time)
    #             cmd = Protocol.cmd(mode, where)
    #             obj_sub_menu.addAction(mode.capitalize(), IPCFacade().broadcast(cmd))
    #
    #         sub_menus = [
    #             ("Tracks", Protocol.simple_in, tracks),
    #             ("Parents", Protocol.simple_in, parents),
    #             ("Children", Protocol.simple_in, children)
    #         ]
    #         for name, protocol, args in sub_menus:
    #             if args:
    #                 sub = menu.addMenu("Hilite {}".format(name))
    #                 for mode in Protocol.ValidHiliteModes[:-1]:
    #                     mode = mode.capitalize()
    #                     where = protocol("track_id*", args)
    #                     cmd = Protocol.cmd(mode, where)
    #                     sub.addAction(mode, IPCFacade().broadcast(cmd))
    #             else:
    #                 sub = menu.addAction("Hilite {}".format(name))
    #                 sub.setEnabled(False)
    #
    #         menu.addAction("Clear Hilite", IPCFacade().broadcast(Protocol.cmd("clear")))
    #     else:
    #         menu.addAction("Open IPC Server Window", IPCFacade().show_info)
    #         menu.addAction("Start IPC Server", IPCFacade().start)
    #
    #     menu.exec_(win_coord)

    def handleEditorRightClick(self, position5d, win_coord):
        debug = ilastik_config.getboolean("ilastik", "debug")

        obj, time = self.get_object(position5d)
        if obj == 0:
            menu = TitledMenu(["Background"])
            if debug:
                menu.addAction("Clear Hilite",
                               IPCFacade().broadcast(Protocol.cmd("clear")))
            menu.exec_(win_coord)
            return

        hypothesesGraph = self.mainOperator.HypothesesGraph.value

        if hypothesesGraph == None:
            color = None
            track = None
        else:
            color = hypothesesGraph.getLineageId(time, obj)
            track = hypothesesGraph.getTrackId(time, obj)

        children = None
        parents = None

        menu = TitledMenu([
            "Object {} of lineage id {}".format(obj, color),
            "Track id: " + (str(track) or "None"),
        ])

        if not debug:
            menu.exec_(win_coord)
            return

        if any(IPCFacade().sending):

            obj_sub_menu = menu.addMenu("Hilite Object")
            for mode in Protocol.ValidHiliteModes:
                where = Protocol.simple("and", ilastik_id=obj, time=time)
                cmd = Protocol.cmd(mode, where)
                obj_sub_menu.addAction(mode.capitalize(),
                                       IPCFacade().broadcast(cmd))

            sub_menus = [("Tracks", Protocol.simple_in, tracks),
                         ("Parents", Protocol.simple_in, parents),
                         ("Children", Protocol.simple_in, children)]
            for name, protocol, args in sub_menus:
                if args:
                    sub = menu.addMenu("Hilite {}".format(name))
                    for mode in Protocol.ValidHiliteModes[:-1]:
                        mode = mode.capitalize()
                        where = protocol("track_id*", args)
                        cmd = Protocol.cmd(mode, where)
                        sub.addAction(mode, IPCFacade().broadcast(cmd))
                else:
                    sub = menu.addAction("Hilite {}".format(name))
                    sub.setEnabled(False)

            menu.addAction("Clear Hilite",
                           IPCFacade().broadcast(Protocol.cmd("clear")))
        else:
            menu.addAction("Open IPC Server Window", IPCFacade().show_info)
            menu.addAction("Start IPC Server", IPCFacade().start)

        menu.exec_(win_coord)

    @threadRouted
    def _informationMessage(self, prompt):
        self.emit(QtCore.SIGNAL('postInformationMessage(QString)'), prompt)

    @threadRouted
    def postInformationMessage(self, prompt):
        QtGui.QMessageBox.information(self, "Info:", prompt,
                                      QtGui.QMessageBox.Ok)
class ConservationTrackingGui(TrackingBaseGui, ExportingGui):
    
    withMergers = True
    @threadRouted
    def _setMergerLegend(self, labels, selection):
        param = self.topLevelOperatorView.Parameters.value
        if 'withMergerResolution' in list(param.keys()):
            if param['withMergerResolution']:
                selection = 1
        elif self._drawer.mergerResolutionBox.isChecked():
            selection = 1

        for i in range(2,len(labels)+1):
            if i <= selection:
                labels[i-1].setVisible(True)
            else:
                labels[i-1].setVisible(False)

        # hide merger legend if selection < 2
        self._drawer.label_4.setVisible(selection > 1)
        labels[0].setVisible(selection > 1)

    def _loadUiFile(self):
        # Load the ui file (find it in our own directory)
        localDir = os.path.split(__file__)[0]
        self._drawer = uic.loadUi(localDir+"/drawer.ui")
        
        parameters = self.topLevelOperatorView.Parameters.value        
        if 'maxDist' in list(parameters.keys()):
            self._drawer.maxDistBox.setValue(parameters['maxDist'])
        if 'maxObj' in list(parameters.keys()):
            self._drawer.maxObjectsBox.setValue(parameters['maxObj'])
        if 'divThreshold' in list(parameters.keys()):
            self._drawer.divThreshBox.setValue(parameters['divThreshold'])
        if 'avgSize' in list(parameters.keys()):
            self._drawer.avgSizeBox.setValue(parameters['avgSize'][0])
        if 'withTracklets' in list(parameters.keys()):
            self._drawer.trackletsBox.setChecked(parameters['withTracklets'])
        if 'sizeDependent' in list(parameters.keys()):
            self._drawer.sizeDepBox.setChecked(parameters['sizeDependent'])
        if 'divWeight' in list(parameters.keys()):
            self._drawer.divWeightBox.setValue(parameters['divWeight'])
        if 'transWeight' in list(parameters.keys()):
            self._drawer.transWeightBox.setValue(parameters['transWeight'])
        if 'withDivisions' in list(parameters.keys()):
            self._drawer.divisionsBox.setChecked(parameters['withDivisions'])
        if 'withOpticalCorrection' in list(parameters.keys()):
            self._drawer.opticalBox.setChecked(parameters['withOpticalCorrection'])
        if 'withClassifierPrior' in list(parameters.keys()):
            self._drawer.classifierPriorBox.setChecked(parameters['withClassifierPrior'])
        if 'withMergerResolution' in list(parameters.keys()):
            self._drawer.mergerResolutionBox.setChecked(parameters['withMergerResolution'])
        if 'borderAwareWidth' in list(parameters.keys()):
            self._drawer.bordWidthBox.setValue(parameters['borderAwareWidth'])
        if 'cplex_timeout' in list(parameters.keys()):
            self._drawer.timeoutBox.setText(str(parameters['cplex_timeout']))
        if 'appearanceCost' in list(parameters.keys()):
            self._drawer.appearanceBox.setValue(parameters['appearanceCost'])
        if 'disappearanceCost' in list(parameters.keys()):
            self._drawer.disappearanceBox.setValue(parameters['disappearanceCost'])
        if 'max_nearest_neighbors' in list(parameters.keys()):
            self._drawer.maxNearestNeighborsSpinBox.setValue(parameters['max_nearest_neighbors'])
        if 'numFramesPerSplit' in list(parameters.keys()):
            self._drawer.numFramesPerSplitSpinBox.setValue(parameters['numFramesPerSplit'])

        # solver: use stored value only if that solver is available
        self._drawer.solverComboBox.clear()
        availableSolvers = self.getAvailableTrackingSolverTypes()
        self._drawer.solverComboBox.addItems(availableSolvers)
        if 'solver' in list(parameters.keys()) and parameters['solver'] in availableSolvers:
            self._drawer.solverComboBox.setCurrentIndex(availableSolvers.index(parameters['solver']))

        # listen on the main operator's NumLabels slot for changes, and adjust the max value of the "maxNumObjects" box
        self.topLevelOperatorView.NumLabels.notifyDirty(self._updateMaxObjectsBoxMaxValue)
        self._updateMaxObjectsBoxMaxValue()

        # Hide division GUI widgets
        if 'withAnimalTracking' in list(parameters.keys()) and parameters['withAnimalTracking'] == True:
            self._drawer.label_5.hide()
            self._drawer.divThreshBox.hide()
            self._drawer.divisionsBox.hide()
            self._drawer.divWeightBox.hide()
            self._drawer.label_6.hide()       
        
        return self._drawer

    @threadRouted
    def _updateMaxObjectsBoxMaxValue(self, *args, **kwargs):
        if self.topLevelOperatorView.NumLabels.ready():
            if self.topLevelOperatorView.NumLabels.value > 1:
                self._drawer.maxObjectsBox.setMaximum(self.topLevelOperatorView.NumLabels.value - 1)
                self._drawer.maxObjectsBox.setValue(self.topLevelOperatorView.NumLabels.value - 1)
                self._drawer.TrackButton.setEnabled(True)
            else:
                self._drawer.maxObjectsBox.setMaximum(0)
                self._drawer.maxObjectsBox.setValue(0)
                self._drawer.TrackButton.setEnabled(False)

    @staticmethod
    def getAvailableTrackingSolverTypes():
        solvers = []
        try:
            if dpct:
                solvers.append('Flow-based')
        except Exception as e:
            logger.info(str(e))
            
        try:
            if mht:
                solvers.append('ILP')
        except Exception as e:
            logger.info(str(e))

        return solvers

    def initAppletDrawerUi(self):
        super(ConservationTrackingGui, self).initAppletDrawerUi()

        self._allowedTimeoutInputRegEx = re.compile('^[0-9]*$')
        self._drawer.timeoutBox.textChanged.connect(self._onTimeoutBoxChanged)

        if not ilastik_config.getboolean("ilastik", "debug"):
            def checkboxAssertHandler(checkbox, assertEnabled=True):
                if checkbox.isChecked() == assertEnabled:
                    checkbox.hide()
                else:
                    checkbox.setEnabled(False)

            checkboxAssertHandler(self._drawer.trackletsBox, True)

            if self._drawer.classifierPriorBox.isChecked():
                self._drawer.hardPriorBox.hide()
                self._drawer.classifierPriorBox.hide()
                self._drawer.sizeDepBox.hide()
            else:
                self._drawer.hardPriorBox.setEnabled(False)
                self._drawer.classifierPriorBox.setEnabled(False)
                self._drawer.sizeDepBox.setEnabled(False)

            checkboxAssertHandler(self._drawer.opticalBox, False)
            checkboxAssertHandler(self._drawer.mergerResolutionBox, True)

            self._drawer.maxDistBox.hide() # hide the maximal distance box
            self._drawer.label_2.hide() # hie the maximal distance label
            self._drawer.label_5.hide() # hide division threshold label
            self._drawer.divThreshBox.hide()
            self._drawer.label_25.hide() # hide avg. obj size label
            self._drawer.avgSizeBox.hide()
            self._drawer.label_24.hide() # hide motion model weight label
            self._drawer.motionModelWeightBox.hide()
          
        self.mergerLabels = [self._drawer.merg1,
                             self._drawer.merg2,
                             self._drawer.merg3,
                             self._drawer.merg4,
                             self._drawer.merg5,
                             self._drawer.merg6,
                             self._drawer.merg7]
        for i in range(len(self.mergerLabels)):
            self._labelSetStyleSheet(self.mergerLabels[i], self.mergerColors[i+1])
        
        self._onMaxObjectsBoxChanged()
        self._drawer.maxObjectsBox.valueChanged.connect(self._onMaxObjectsBoxChanged)
        self._drawer.mergerResolutionBox.stateChanged.connect(self._onMaxObjectsBoxChanged)

        self._drawer.exportButton.hide()



    @threadRouted
    def _onTimeoutBoxChanged(self, *args):
        inString = str(self._drawer.timeoutBox.text())
        if self._allowedTimeoutInputRegEx.match(inString) is None:
            self._drawer.timeoutBox.setText(inString[:-1])

    def _setRanges(self, *args):
        super(ConservationTrackingGui, self)._setRanges()        
        maxx = self.topLevelOperatorView.LabelImage.meta.shape[1] - 1
        maxy = self.topLevelOperatorView.LabelImage.meta.shape[2] - 1
        maxz = self.topLevelOperatorView.LabelImage.meta.shape[3] - 1
        
        maxBorder = min(maxx, maxy)
        if maxz != 0:
            maxBorder = min(maxBorder, maxz)
        self._drawer.bordWidthBox.setRange(0, old_div(maxBorder,2))
        
        
    def _onMaxObjectsBoxChanged(self):
        self._setMergerLegend(self.mergerLabels, self._drawer.maxObjectsBox.value())
        
    def _onTrackButtonPressed( self ):    
        if not self.mainOperator.ObjectFeatures.ready():
            self._criticalMessage("You have to compute object features first.")            
            return

        withMergerResolution = self._drawer.mergerResolutionBox.isChecked()
        numStages = 8
        # object features
        # detection probabilities
        # creating traxel store
        # generating probabilities
        # insert energies
        # convexify costs
        # solver
        # compute lineages
        if self._drawer.divisionsBox.isChecked():
            # division probabilities
            numStages +=1

        if withMergerResolution:
            numStages += 1 # merger resolution
        withTracklets = self._drawer.trackletsBox.isChecked()
        if withTracklets:
            numStages += 3 # initializing tracklet graph, finding tracklets, contracting edges in tracklet graph

        self.progressWindow = TrackProgressDialog(parent=self,numStages=numStages)
        self.progressWindow.run()
        self.progressWindow.show()
        self.progressVisitor = GuiProgressVisitor(progressWindow=self.progressWindow)

        def _track():
            self.applet.busy = True
            self.applet.appletStateUpdateRequested()
            maxDist = self._drawer.maxDistBox.value()
            maxObj = self._drawer.maxObjectsBox.value()        
            divThreshold = self._drawer.divThreshBox.value()
            
            from_t = self._drawer.from_time.value()
            to_t = self._drawer.to_time.value()
            from_x = self._drawer.from_x.value()
            to_x = self._drawer.to_x.value()
            from_y = self._drawer.from_y.value()
            to_y = self._drawer.to_y.value()        
            from_z = self._drawer.from_z.value()
            to_z = self._drawer.to_z.value()        
            from_size = self._drawer.from_size.value()
            to_size = self._drawer.to_size.value()        
            
            self.time_range =  list(range(from_t, to_t + 1))
            avgSize = [self._drawer.avgSizeBox.value()]

            cplex_timeout = None
            if len(str(self._drawer.timeoutBox.text())):
                cplex_timeout = int(self._drawer.timeoutBox.text())

            withTracklets = self._drawer.trackletsBox.isChecked()
            sizeDependent = self._drawer.sizeDepBox.isChecked()
            hardPrior = self._drawer.hardPriorBox.isChecked()
            classifierPrior = self._drawer.classifierPriorBox.isChecked()
            divWeight = self._drawer.divWeightBox.value()
            transWeight = self._drawer.transWeightBox.value()
            withDivisions = self._drawer.divisionsBox.isChecked()        
            withOpticalCorrection = self._drawer.opticalBox.isChecked()
            withMergerResolution = self._drawer.mergerResolutionBox.isChecked()
            borderAwareWidth = self._drawer.bordWidthBox.value()
            withArmaCoordinates = True
            appearanceCost = self._drawer.appearanceBox.value()
            disappearanceCost = self._drawer.disappearanceBox.value()

            motionModelWeight = self._drawer.motionModelWeightBox.value()
            solver = self._drawer.solverComboBox.currentText()

            ndim=3
            if (to_z - from_z == 0):
                ndim=2
            
            try:
                self.mainOperator.track(
                    time_range = self.time_range,
                    x_range = (from_x, to_x + 1),
                    y_range = (from_y, to_y + 1),
                    z_range = (from_z, to_z + 1),
                    size_range = (from_size, to_size + 1),
                    x_scale = self._drawer.x_scale.value(),
                    y_scale = self._drawer.y_scale.value(),
                    z_scale = self._drawer.z_scale.value(),
                    maxDist=maxDist,         
                    maxObj = maxObj,               
                    divThreshold=divThreshold,
                    avgSize=avgSize,                
                    withTracklets=withTracklets,
                    sizeDependent=sizeDependent,
                    detWeight=10.0,
                    divWeight=divWeight,
                    transWeight=transWeight,
                    withDivisions=withDivisions,
                    withOpticalCorrection=withOpticalCorrection,
                    withClassifierPrior=classifierPrior,
                    ndim=ndim,
                    withMergerResolution=withMergerResolution,
                    borderAwareWidth =borderAwareWidth,
                    withArmaCoordinates =withArmaCoordinates,
                    cplex_timeout =cplex_timeout,
                    appearance_cost =appearanceCost,
                    disappearance_cost =disappearanceCost,
                    motionModelWeight=motionModelWeight,
                    force_build_hypotheses_graph =False,
                    max_nearest_neighbors=self._drawer.maxNearestNeighborsSpinBox.value(),
                    numFramesPerSplit=self._drawer.numFramesPerSplitSpinBox.value(),
                    solverName=solver,
                    progressWindow=self.progressWindow,
                    progressVisitor=self.progressVisitor
                    )

            except Exception as ex:
                self.progressWindow.onTrackDone()
                log_exception(logger, "Error during tracking.  See above error traceback.")
                self._criticalMessage("Error during tracking.  See error log.\n\n"
                                      "Exception was:\n\n{})".format( ex ))
                return
        
        def _handle_finished(*args):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested()
            self._drawer.TrackButton.setEnabled(True)
            self._drawer.exportButton.setEnabled(True)
            self._drawer.exportTifButton.setEnabled(True)
            self._setLayerVisible("Objects", False)
            
            # update showing the merger legend,
            # as it might be (no longer) needed if merger resolving
            # is disabled(enabled)
            self._setMergerLegend(self.mergerLabels, self._drawer.maxObjectsBox.value())
            
        def _handle_failure( exc, exc_info ):
            self.applet.busy = False
            self.applet.appletStateUpdateRequested()
            traceback.print_exception(*exc_info)
            sys.stderr.write("Exception raised during tracking.  See traceback above.\n")
            self._drawer.TrackButton.setEnabled(True)
        
        req = Request( _track )
        req.notify_failed( _handle_failure )
        req.notify_finished( _handle_finished )
        req.submit()

    def get_raw_shape(self):
        return self.topLevelOperatorView.RawImage.meta.shape

    def get_feature_names(self):
        params = self.topLevelOperatorView.Parameters
        if params.ready() and params.value["withDivisions"]:
            return self.topLevelOperatorView.ComputedFeatureNamesWithDivFeatures([]).wait()
        return self.topLevelOperatorView.ComputedFeatureNames([]).wait()

    def get_color(self, pos5d):
        slicing = tuple(slice(i, i+1) for i in pos5d)
        color = self.mainOperator.CachedOutput(slicing).wait()
        return color.flat[0]

    def get_object(self, pos5d):
        slicing = tuple(slice(i, i+1) for i in pos5d)
        label = self.mainOperator.RelabeledImage(slicing).wait()
        return label.flat[0], pos5d[0]

    @property
    def gui_applet(self):
        return self.applet

    def get_export_dialog_title(self):
        return "Export Tracking Information"

    def handleEditorRightClick(self, position5d, win_coord):
        debug = ilastik_config.getboolean("ilastik", "debug")

        obj, time = self.get_object(position5d)
        if obj == 0:
            menu = TitledMenu(["Background"])
            if debug:
                menu.addAction("Clear Hilite", IPCFacade().broadcast(Protocol.cmd("clear")))
            menu.exec_(win_coord)
            return
        
        # Get color and track from hypotheses graph (which is a slot in the new operator)
        hypothesesGraph = self.mainOperator.HypothesesGraph.value

        if hypothesesGraph == None:
            color = None
            track = None
        else:
            color = hypothesesGraph.getLineageId(time, obj)
            track = hypothesesGraph.getTrackId(time, obj)

        tracks = None
        children = None 
        parents = None

        menu = TitledMenu([
            "Object {} of lineage id {}".format(obj, color),
            "Track id: " + (str(track) or "None"),
        ])

        if not debug:
            menu.exec_(win_coord)
            return

        if any(IPCFacade().sending):

            obj_sub_menu = menu.addMenu("Hilite Object")
            for mode in Protocol.ValidHiliteModes:
                where = Protocol.simple("and", ilastik_id=obj, time=time)
                cmd = Protocol.cmd(mode, where)
                obj_sub_menu.addAction(mode.capitalize(), IPCFacade().broadcast(cmd))

            sub_menus = [
                ("Tracks", Protocol.simple_in, tracks),
                ("Parents", Protocol.simple_in, parents),
                ("Children", Protocol.simple_in, children)
            ]
            for name, protocol, args in sub_menus:
                if args:
                    sub = menu.addMenu("Hilite {}".format(name))
                    for mode in Protocol.ValidHiliteModes[:-1]:
                        mode = mode.capitalize()
                        where = protocol("track_id*", args)
                        cmd = Protocol.cmd(mode, where)
                        sub.addAction(mode, IPCFacade().broadcast(cmd))
                else:
                    sub = menu.addAction("Hilite {}".format(name))
                    sub.setEnabled(False)

            menu.addAction("Clear Hilite", IPCFacade().broadcast(Protocol.cmd("clear")))
        else:
            menu.addAction("Open IPC Server Window", IPCFacade().show_info)
            menu.addAction("Start IPC Server", IPCFacade().start)

        menu.exec_(win_coord)